如何冻结JTable中的行

时间:2016-11-12 16:42:16

标签: java swing jtable

如何冻结JTable中的行?

这应该类似于Microsoft Excel,其中用户可以选择单元格并右键单击并冻结/解冻行。我找到了很多关于冻结列而不是行的答案。

谢谢!

2 个答案:

答案 0 :(得分:0)

简短的答案是,您需要有两个JScrollPanes:最上面的一个用于处理冻结的行(带有行标题以处理其冻结的列),最下面的一个用于滚动行(也带有rowheader)-因此您最后要管理4个表。 不要在顶部滚动窗格中使用滚动条:而是在下部滚动窗格的视口中添加一个ChangeListener() 内容如下:

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

需要隐藏底部窗格的TableHeader(至少在显示顶部窗格时):

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

其他情况并非一帆风顺,但是如果您没有生成的行号列来模拟Excel,则可以使您的生活更加轻松,不要冻结已经冻结的表(您不能在Excel中执行),并且不允许排序(至少冻结部分中的列)。 我使用的JVM具有一个“功能”,该功能使将顶部窗格中的标题与底部窗格中的列对齐变得复杂,直到顶部表中至少有一行为止-仅在实际执行“冻结”后才考虑使用顶部窗格。

答案 1 :(得分:0)

一种简单的方法是覆盖表模型的 getValueAt() 方法。

你可以这样做:

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

firstVisibleRowIndexSupplier 传递给表模型。

在表模型中:

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

缺点是表格在垂直向上滚动时会缓存数据。 解决方法是向垂直滚动条添加 AdjustmentListener

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

// 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
}

通过这种变通方法,有一个我还没有找到修复方法的小缺点:当用鼠标滚轮向上滚动时,冻结的行将在表格更新之前短暂闪烁。使用滚动条滚动时不会发生这种情况,或者使用滚动条或鼠标滚轮向下滚动时根本不会发生这种情况。