如何冻结JTable
中的行?
这应该类似于Microsoft Excel,其中用户可以选择单元格并右键单击并冻结/解冻行。我找到了很多关于冻结列而不是行的答案。
谢谢!
答案 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
}
通过这种变通方法,有一个我还没有找到修复方法的小缺点:当用鼠标滚轮向上滚动时,冻结的行将在表格更新之前短暂闪烁。使用滚动条滚动时不会发生这种情况,或者使用滚动条或鼠标滚轮向下滚动时根本不会发生这种情况。