javaswingjtableswingworkerjide

JTable not updating from a SwingWorker thread


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.


Solution

  • Your fragment shows incorrect synchronization. In particular, you access BeanTableModel, a subclass of AbstractTableModel, from the background thread. Instead, pass the List<Integer> rowsToRemove to your worker in its constructor.

    Addendum: Instead of invokeLater(), you can update the TableModel in your implementation of process(), which executes on the EDT. Also, you shouldn't have to fireTableDataChanged(), which "Notifies all listeners that all cell values in the table's rows may have changed." The removeObject() implementation should fire the least pervasive event required to effect the change.