简体   繁体   中英

How to freeze rows in JTable

How do I freeze rows in JTable ?

This should work similar to that of Microsoft Excel in which a user can select a cell and right click and freezes/unfreezes the rows. I found A lot of answers about freezing columns but not rows.

Thanks!

The short answer is that you need to have two JScrollPanes: the top one to handle the frozen rows (with a row header to handle its frozen columns) and the bottom one for the scrollable rows (also with rowheader) - so you end up with 4 tables to manage. Don't use scrollbars for the top scrollpane: instead add a ChangeListener to the viewport of the lower scroll pane () with something like the following:

   public void stateChanged(ChangeEvent e) {
      Point p = spMain.getViewport().getViewPosition();
      p.y = 0;
      spHead.getViewport().setViewPosition(p);
   }

The TableHeader for the bottom pane needs to be hidden (at least when displaying the top pane):

   spMain.setColumnHeaderView(bodyTable.getTableHeader());
   spMain.getColumnHeader().setVisible(false);

The rest isn't exactly plain sailing but you can make your life easier if you don't have a generated column of row numbers to emulate Excel, don't allow freezing of an already frozen table (which you can't do in Excel) and don't allow sorting (at least of columns in the frozen section. The JVM that I use has a "feature" that complicates aligning the headers in the top pane with the columns in the lower until the top tables have at least one row - consider only using the top pane once a 'freeze' is actually performed.

An easy way to do this is by overriding the table model's getValueAt() method.

You could do something like this:

Supplier<Integer> firstVisibleRowIndexSupplier = () -> {
  Point p = scrollPane.getViewport()
                      .getViewPosition();
  return table.rowAtPoint(p);
};

Pass the firstVisibleRowIndexSupplier to the table model.

In the table model:

@Override
public Object getValueAt(int row, int column) {
  int firstVisibleRow = this.firstVisibleRowSupplier.get();
  // Logic for returning data for the frozen rows, based on firstVisibleRow
}

The downside is that the table caches data when scrolling up vertically. A workaround for this is to add an AdjustmentListener to the vertical scroll bar:

scrollPane.getVerticalScrollBar()
          .addAdjustmentListener(e -> tableModel.refresh());

with

// TableModel
public void refresh() {
  // Preserves selection
  fireTableChanged(new TableModelEvent(this, //tableModel
    this.firstVisibleRowSupplier.get(), //firstRow
    getRowCount() - 1, //lastRow
    TableModelEvent.ALL_COLUMNS, //column
    TableModelEvent.UPDATE)); //changeType
}

With this workaround, there is one minor downside that I haven't found a fix for yet: When scrolling upwards with the mouse wheel, the frozen row(s) will flash briefly before the table updates. This doesn't happen as much when scrolling with the scroll bar or at all when scrolling down with either the scroll bar or mouse wheel.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM