简体   繁体   English

如何冻结 JTable 中的行

[英]How to freeze rows in JTable

How do I freeze rows in JTable ?如何冻结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.这应该与 Microsoft Excel 类似,在 Microsoft Excel 中,用户可以选择一个单元格并右键单击并冻结/解冻行。 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.简短的回答是,您需要有两个 JScrollPanes:顶部的一个处理冻结的行(带有行标题来处理其冻结的列),底部的一个用于可滚动行(也带有行标题) - 所以你最终得到4张桌子来管理。 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:不要在顶部滚动窗格中使用滚动条:而是将 ChangeListener 添加到下部滚动窗格 () 的视口中,如下所示:

   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):底部窗格的 TableHeader 需要隐藏(至少在显示顶部窗格时):

   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.其余的并不是一帆风顺,但如果您没有生成的行号列来模拟 Excel,则可以让您的生活更轻松,不允许冻结已经冻结的表格(您无法在 Excel 中执行此操作) ) 并且不允许排序(至少是冻结部分中的列。我使用的 JVM 有一个“功能”,它使顶部窗格中的标题与下方的列对齐变得复杂,直到顶部表至少有一个行 - 在实际执行“冻结”后仅考虑使用顶部窗格。

An easy way to do this is by overriding the table model's getValueAt() method.一个简单的方法是覆盖表模型的getValueAt()方法。

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.firstVisibleRowIndexSupplier传递给表模型。

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:一种解决方法是将AdjustmentListener添加到垂直滚动条:

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.使用滚动条滚动或使用滚动条或鼠标滚轮向下滚动时,这种情况不会发生太多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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