javydreamercsw
javydreamercsw

Reputation: 5099

Running code in AWT Thread

I have a JTextPane I'm using to put the chat history of a chat application. There are two sources for it's content right now:

  1. Client thread listening for server messages.
  2. GUI: a JField and button to add to the the messages (temporary as everything is meant to come from the server)

Here's the code used by both methods:

private void appendText(String text, AttributeSet attr) {
        try {
            int len = history.getDocument().getLength();
            history.getDocument().insertString(len, text + "\n", attr);
                    // Convert the new end location
            // to view co-ordinates
            Rectangle r = history.modelToView(len);

            // Finally, scroll so that the new text is visible
            if (r != null) {
                scrollRectToVisible(r);
            }
        } catch (BadLocationException e) {
            System.out.println("Failed to append text: " + e);
        }
    }

Debugging I noticed that the code is executed in both scenarios but only actually shows in the component when is ran in the AWT thread via the GUI.

So unless someone else has a better idea I have the following options:

  1. Somehow run the client thread on the AWT.
  2. Somehow run the append method on the AWT.
  3. Use a smart answer from one of you guys.

Any ideas/suggestions?

Upvotes: 1

Views: 1337

Answers (2)

junkman
junkman

Reputation: 44

Try this:

private void appendText(String text, AttributeSet attr) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            // your method code here
        }
    });
}

It looks like you are trying to update swing components outside the AWT thread since you are calling appendText directly from your client's thread. You can't do that. Now if you use EventQueue.invokeLater, it will make sure the code that updates the swing components gets executed in the AWT thread no matter from which thread you called the method.

Upvotes: 3

Lajos Arpad
Lajos Arpad

Reputation: 76508

I believe you should create a class which holds information about the message (like message text, sender, receiver, timestamp). Like this:

public class ChatHistoryElement {
    private String text;
    private Date moment;
    private User sender;
    private User receiver;
    public volatile volatile AbstractList<ChatHistoryElement> chatHistory = null;

    public String getMessage() {
        return text;
    }

    public Date getMoment() {
        return moment;
    }

    public User getSender() {
        return sender;
    }

    public User getReceiver() {
        return receiver;
    }

    public ChatHistoryElement(String text, Date moment, User sender, User receiver) {
        this.text = text;
        this.moment = moment;
        this.sender = sender;
        this.receiver = receiver;
        if (chatHistory == null) {
            chatHistory = new ArrayList<ChatHistoryElement>();
        }
        chatHistory.add(this);
    }
}

By making your history volatile, you will always be able to reach it using ChatHistoryElement.chatHistory.

Upvotes: 0

Related Questions