4

How to preserve table row selecetion after table mode update (fireTableDataChanes)? I know that I should save selection before fire and restore it after (from there). But when I try to restore selection in TableModelListener it doesn't work. So where should I restore selection?

Update: Now I try to restore selection in this way: table.setModel(model);

    model.addTableModelListener(new TableModelListener() {

      @Override
      public void tableChanged(TableModelEvent e) {
        table.addRowSelectionInterval(1, 1);
      }
    });

but it doesn't work.

Community
  • 1
  • 1
Lampapos
  • 1,063
  • 1
  • 12
  • 26
  • Show us some code. How are you currently trying to save/restore selection state? – Nate W. Aug 25 '11 at 21:39
  • My fault. Code added into question. – Lampapos Aug 25 '11 at 21:48
  • 1
    dont fire dataChanged if you don't have to - so first check your model, if you really have a change which is a vast mixture of content updates and removes/adds. If not, fire the one or more of the appropriate more-limited event types - the table will keep selection synced. Or the other way round: if the table cant, any custom code cant as well ;-) – kleopatra Aug 26 '11 at 09:06
  • thanks. but in my case table can change dramatically (: – Lampapos Aug 26 '11 at 09:38

3 Answers3

2

This is an updated version of the first answer. You can use a field to store the row as it can be accessed by inner classes. I had some trouble with this solution tough because I used a periodic thread to update the table.

private int selectedRow = -1;

public void mymethod() {
//put code to create the table here...
    JTable tableList = new JTable();


// Save selected row table
    tableList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e) {
            selectedRow = e.getFirstIndex();
        }
    });

// Restore selected raw table
model.addTableModelListener(new TableModelListener() {      
    @Override
    public void tableChanged(TableModelEvent e) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (selectedRow >= 0) {
                            tableList.addRowSelectionInterval(index, index);
                }
             }
        });
    }
    });
}
L2M
  • 51
  • 4
0

The example from the first answer shows the basic solution but won't work out of the box. It's not possible to change the final "selectedRow". So a mutable integer (e.g. AtomicInteger) should be used. The tamleModelListener dispatches to task to swing, so it gets invoked later - in most cases after the table change has already removed the selection. So selectedRow will in most cases be -1.

I have changed the above example a bit (and added single cell selection but it also works for full rows):

    final AtomicInteger selectedRow=new AtomicInteger(-1);
    final AtomicInteger selectedCol=new AtomicInteger(-1);
    tblZeiten.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e)
        {
            selectedRow.set(tblZeiten.getSelectedRow());
            selectedCol.set(tblZeiten.getSelectedColumn());
        }
    });
    tblZeiten.getModel().addTableModelListener(new TableModelListener() {      
        @Override
        public void tableChanged(TableModelEvent e)
        {
            TableCellEditor editor=tblZeiten.getCellEditor();
            if (editor!=null) editor.cancelCellEditing();

            final int row=selectedRow.get();
            final int col=selectedCol.get();
            if (row<0||col<0) return;

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    // http://book.javanb.com/the-java-developers-almanac-1-4/egs/javax.swing.table/Sel.html
                    tblZeiten.changeSelection(row,col, false, false);
                 }
            });
        }
    });
Michael Wyraz
  • 3,638
  • 1
  • 27
  • 25
0

Decision is simple: we should use Swing EventQueue:

final int selectedRow = 0;
// Save selected row table
tableList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
    @Override
    public void valueChanged(ListSelectionEvent e) {
        selectedRow = e.getFirstIndex();
    }
});

// Restore selected raw table
model.addTableModelListener(new TableModelListener() {      
    @Override
    public void tableChanged(TableModelEvent e) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (selectedRow >= 0) {
                            tableList.addRowSelectionInterval(index, index);
                }
             }
        });
    }
});
Lampapos
  • 1,063
  • 1
  • 12
  • 26