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?
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.