I currently have a JTable that is populated with a series of data that forms the basis of a import screen. When I have finished selecting which updates I want or do not want, I press on the Apply button and the updates are applied successfully but the JTable does not fully update.
This is the code for the method that deals with applying the changes:
private void doProcessChanges() {
ChangeProcessor cp = new ChangeProcessor();
final List<Integer> rowsToRemove = new ArrayList<Integer>();
BeanTableModel<UpdateModel> model = (BeanTableModel<UpdateModel>) table.getModel();
for (int i=0; i<model.getRowCount(); i++) {
UpdateRow ur = mode.getObject(i);
if (ur.isAccepted() <> ChangeAcceptance.NO_ACTION) {
cp.processChange(ur);
rowsToRemove.add(i);
}
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (int row : rowsToRemove) {
model.removeObject(row);
model.fireTableDataChanged();
}
}
);
}
The method is called from within a SwingWorker thread as below:
SwingWorker<Object, Object> worker = new SwingWorker<Object, Object>() {
@Override
protected Object doInBackground() throws Exception {
doProcessChanges();
return null;
}
@Override
protected void done() {
try {
get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
I do not get any exceptions from executing this so I am I doing anything wrong? Thanks in advance.
Your fragment shows incorrect synchronization. In particular, you access
BeanTableModel
, a subclass ofAbstractTableModel
, from the background thread. Instead, pass theList<Integer> rowsToRemove
to your worker in its constructor.Addendum: Instead of
invokeLater()
, you can update theTableModel
in your implementation ofprocess()
, which executes on the EDT. Also, you shouldn't have tofireTableDataChanged()
, which "Notifies all listeners that all cell values in the table's rows may have changed." TheremoveObject()
implementation should fire the least pervasive event required to effect the change.