Question

I wrote a custom table model for a JTable:

class MessageTableModel{

    private static Set<Message> messages = Collections.synchronizedSet(new TreeSet<Message>());

    .
    .
    .

    public void setMessages(List<Message> newMessages) {
        Collections.sort(newMessages);
        Iterator<Message> it = messages.iterator();
        while (it.hasNext()) {
            Message mess = it.next();
            if (!newMessages.contains(mess)) {
                it.remove();
                this.fireTableDataChanged();
            }
        }
        for (Message message : newMessages)
            if (message.isOrderStatusMessage())
                if (!messages.contains(message)) {
                    addMessage(message);
                }
        this.fireTableDataChanged();
    }

    public Message getMessageAtRow(int row){
        return (Message) messages.toArray()[row];
    }
}

The problem is that there's a thread that updates the table values, calling setMessages() method perodically. If I try to get a row during this update:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1

in this line:

return (Message) messages.toArray()[row];

There's a way to make the method getMessageAtRow() waits for the modifications to be done, or another solution for this problem?

Was it helpful?

Solution

Swing is single threaded. You can't modify the model on a thread outside of the event thread. The easiest way to fix this would be:

public void setMessages(List<Message> newMessages) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
            Collections.sort(newMessages);
        Iterator<Message> it = messages.iterator();
        while (it.hasNext()) {
            Message mess = it.next();
            if (!newMessages.contains(mess)) {
                it.remove();
                this.fireTableDataChanged();
            }
        }
        for (Message message : newMessages)
            if (message.isOrderStatusMessage())
                if (!messages.contains(message)) {
                    addMessage(message);
                }
        this.fireTableDataChanged();
    }
  )};
}

Also,fireTableDateChanged() should also only be called on the event thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top