Sunday, November 8, 2009

DefaultTableModel, JTable, and SwingWorker

It seems this problem occurs intermittently but is definitely related to threading. When a user decides to delete files that are deemed duplicates, the files are deleted and the entry is removed from the JTable. The process of deleting files and removing them from the JTable is done in a SwingWorker task with the JTable object passed to the SwingWorker. To remove a row I have a simple method in my SongTable, which extends JTable, that searches for the correct row and then removes it. Sometimes though this error occurs with different array indexes:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 8 >= 8
at java.util.Vector.elementAt(Vector.java:427)

and you can tell it happens because of threading due to the fact that other output to the command line comes in between the entire exception trace on the command line. In other words, there is more to the exception that is printed but some of my output is printed between exception lines. I have yet to figure this one out. I've tried synchronizing the methods (which was already there) as well as calling the wait() method on other threads using a simple boolean called available that would go to false when something was operating on the SongTable. Still nothing.

My newest theory is it has something to do with the JTable working in the Event Dispatch Thread and the SwingWorker, essentially a thread, interfering but I'm stuck there. I'll keep searching for clues however. Until then, toodles.

Brian

UPDATE: 11/8/2009 3:27
I think I have fixed the issue. Here's what was going on. Basically I was trying to modify a component on the Event Dispatch Thread (EDT) which is where the GUI should run. The component was being modified by a different thread and I would essentially have the producer consumer problem. Here are a couple of resources to check out...

http://forums.sun.com/thread.jspa?threadID=790880

http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/SwingUtilities.html#invokeLater%28java.lang.Runnable%29 - look into the invokeLater method

So in the end, and this may not be the way to do it, but I can now modify components in the GUI/EDT from other threads using the invokeLater method inside of my remove row method. Here's the code...



public void removeRow(final File fileToRemove){
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
int fileNameColumn = FILE_COLUMN_NUM;
int rowCount = model.getRowCount();
for(int i=0; i< rowCount ; i++){
String selectedRowFilename = (String) model.getValueAt(i, fileNameColumn);
if(fileToRemove.getPath().equals(selectedRowFilename)){
System.out.println("Removing row " + i + " " + fileToRemove.getName());
assert i < model.getRowCount();
rowCount--;
model.removeRow(i);
break;
}
}
}
});
}

No comments:

Post a Comment