TableModel fireEvents dont seem to get put on the EventDispatchQueue ?

Hi I thought I had all this Swing events stuff sorted out but the fire methods on AbstractTableModel have confused me. I thought they were generally called when updating a table model from the back end, and that they would generate a TableModelEvent which would be on the event queue, and then the EventDispatchQueue would dispatch the event to all the listeners (including JTable whcih Implements TableModelListener) allowing them to to do gui repaints in their tableChanged() method.

But looking the code for AbstractTableModel it seems to bypass the event queue and call the listeners directly so if it isnt called in the EventDispatchThread (which it never is in my code) the end result will be making changes to the JTable outside of the EventDispatchThread, but why would I ever want to do back end updates from the EventDispatchThread ?

I dont understand this, please explain.

[902 byte] By [paultaylora] at [2007-10-3 3:13:35]
# 1
Always follow the single thread rule when programming in swing: http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#single_thread_ruleIf you follow the rule, you will not have any similar problems.
jvaudrya at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 2
Yes I know that, but that applys to the JTable rather than the TableModel, why dont the fire methods put events onto the Event Queue
paultaylora at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 3

Ok, Ive read up on this some more and it seems the fire events just call the listeners on the current thread. This seems like a design mistake to me and appears to have been rectified in java 1.6 somewhat with the SwingPropertyChangeSupport class with isNotifyOnEdt method which ensures that the event is fired on the event dispatch but this behaviour wont fix existing fire() methods.

In my particular circumstances afer updating the model from along running thread (non edt) I want to notify on the EDT. There is no problem with the user accessing the model whilst incomplete because the user is not allowed to access the table whilst the update is occurring, so I have just overridden fireTableChanged() fromAbstractTableModel (which is what all the other fire methods call) to ensure it is added to the Event Queue, seems like a good general idea to me.

public class DatasheetTableModel extends AbstractTableModel

{

..............

/** Overridden to ensure listeners run from Event Dispatch Thread */

public void fireTableChanged( final TableModelEvent e )

{

if( !SwingUtilities.isEventDispatchThread() )

{

SwingUtilities.invokeLater(

new Runnable()

{

public void run()

{

DatasheetTableModel.super.fireTableChanged( e );

}

} );

}

else

{

super.fireTableChanged( e );

}

}

paultaylora at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 4

> In my particular circumstances afer updating the

> model from along running thread (non edt) I want to

> notify on the EDT.

And that's the problem. You need to update the model from the EDT; it's not

just simple stuff like changing a color that has to happen on the EDT, it's

the complex stuff as well. When the long running thread needs to make an

update, it should queue that up on the EDT, via invokeLater or using a

SwingWorker or what have you.

JayDSa at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 5

> This seems like a design mistake to me

No. All Swing updates should be done on the EDT. So if the model was correctly updated on the EDT then the listeners would be invoked on the EDT. This is the number one rule in Swing. All updates should be done on the EDT. There are a few methods in the API that state they are thread safe, but otherwise it is you responsibility to ensure this.

camickra at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 6

Ok, but as far as i can see there is no reason why listeners listener method should EVER be invoked from anywhere then the EDT so wouldnt it make sense for the fire methods to check if they are not being called from EDT and if so use invokeLater(0 to add their code to the queue, furhermore this would be simpler if the EventDispatcher had an addEventToQueue() method, that is why I think there is a design problem with the fire methods provided by SUN.

>> So if the model correctly updated on EDT

The actual model update maybe quite slow if for example table rows are getting added slowly by the long running thread from loading the data from a series of files. Because the user cannot access the table whilst this thread is running it doesnt matter if the model does not match what it displayed in the table at that moment in time, but I when I have finished updating the model I want to fire a single event on the EDT to inform the JTable it needs to redraw, so in this case I dont see that the model should be modified on the EDT.

paultaylora at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 7

> so in this case I dont see that the model should be modified on the EDT.

Well, you might not see it that way, and it might not be what you want to do,

but all Swing updates should happen on the EDT, so modifying the model

should happen on the EDT. If you choose not to do this, then don't complain

that it doesn't work properly.

That said, it sounds to me that rather than modifying the model, you should

create a new instance of the model with the current data, modify that instance

in your long running thread, then when complete simply set that instance as

the new model on the table (of course, doing this from the EDT). That should

accomplish everything you want.

JayDSa at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 8

yeah, replace the model in one call once it is ready that seems resonable. The only thing I dont like is that my long running thread has to wrap it in a SwingUtilities,invokeLater so it has to know about the GUI I would prefer it if it doidnt have to worry about the gui and let the table model deal with that aspect.

paultaylora at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...
# 9
Well, you could either extend JTable so that its setModel() (as well as any otherrelated) method checks if it is the EDT and if not, does the invokeLater, or youcould do the same thing with your TableModel.
JayDSa at 2007-7-14 21:04:37 > top of Java-index,Desktop,Core GUI APIs...