0
votes

I use a HashMap to fill a JTable, which is more or less continuously updated:

public Map< Long, MyObject > tableData = new HashMap< Long, MyObject >();

Every time a new element is added to the map the table model is notified:

tableData.put(id, anObject);

AbstractTableModel atm = (AbstractTableModel)model;
atm.fireTableDataChanged();

In Addition I have a TableRowSorter which sorts the rows according to a specific criteria:

TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
.
.
.
table.setRowSorter(sorter);

My goal is that the (vertical) scrollbar always jumps to the last added row, which can be somwhere in the mid of the table because of the sorter probably using this:

table.scrollRectToVisible(table.getCellRect(row,0, true)); 

The problem is I do not know the index of the row :) Where can I hook in to get this index?

1
unrelated: a) never-ever fire a event on behalf of the model, instead implement a custom model with with modifying api that fulfills its notification contract itself b) always fire the most narrow event that's possible, f.i. an update/insert (vs. the shotgun dataChanged) c) if your rowSorter is just the plain core version, consider using table.setAutoCreateRowSorter(true) instead of creating and setting it manuallykleopatra

1 Answers

8
votes

Scrolling to a newly inserted row in a potentially sorted table involves

  • listening to changes in the table model
  • converting the rowIndex of the event (it is in model coordiates) to view coordinates
  • scrolling to the view position

In code:

final JTable table = new JTable();
TableModelListener l = new TableModelListener() {

    @Override
    public void tableChanged(TableModelEvent e) {
        if (TableUtilities.isInsert(e)) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    int viewRow = table.convertRowIndexToView(e.getFirstRow());
                    table.scrollRectToVisible(table.getCellRect(viewRow, 0, true));    
                }
            });
        }
    }
};
table.getModel().addTableModelListener(l);

Two important aspects:

  • your model implemenation must fire the correct event, that is a insert, not a dataChanged
  • invoking both index conversion and scrolling guarantees that the table (which is listening to the model as well) has updated all internal state according to the model change.