我有在表中显示日志事件的窗口。例如,用户正在阅读表格某行中的文本。当新日志出现时,它们被添加到表的开头,并且用户正在阅读的行向下移动。当在表的开头添加新行时,我需要防止 JScrollPane 滚动。我尝试了不同的东西,但没有任何帮助。有人可以建议我如何实施吗?提前致谢!
问问题
400 次
1 回答
1
棘手的任务 :-) 搬出是因为默认情况下不会以任何方式调整滚动位置:在上面添加行只是保持垂直滚动位置,然后像以前一样指向不同的行。
需要什么:
- 跟踪插入前的 visibleRect/最后一行
- 监听插入类型的模型变化
- 计算新的可见矩形,使旧的最后一行滚动回视图
- 触发滚动
这很棘手,因为我们需要倾听模型的变化。该侦听器是由表在内部注册的 modelListener 的邻居,该表在更改时自行更新。所以我们需要确保在内部更改完成后采取行动,同时在内部更新之前使用信息。
一个肮脏的解决方案 - 取决于最后添加的第一个通知的摇摆监听器通知的通常顺序(注意:在生产代码中不要!它很容易破坏,当更改 LAF 时) - 是收集之前的状态时通知并调整包含在 invokeLater 中的滚动位置:
final DefaultTableModel model = new DefaultTableModel(20, 2);
for (int i = 0; i < model.getRowCount(); i++) {
model.setValueAt(i, i, 0);
}
final JTable table = new JTable(model);
Action action = new AbstractAction("add row at 0") {
@Override
public void actionPerformed(ActionEvent e) {
model.insertRow(0, new Object[] {});
}
};
JXFrame frame = wrapWithScrollingInFrame(table, "modify scroll");
TableModelListener l = new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (!TableUtilities.isInsert(e)) return;
final Rectangle r = table.getVisibleRect();
final int lastRow = table.rowAtPoint(
new Point(0, r.y + r.height - 5));
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// assuming
// a) the insert was exactly 1 row
// b) was _before_ the old last row in view-coordinates
Rectangle cell = table.getCellRect(lastRow + 1, 0, true);
cell.translate(0, -r.height + cell.height);
cell.height = r.height;
table.scrollRectToVisible(cell);
}
});
}
};
model.addTableModelListener(l);
干净地获取之前状态的适当方法取决于您的确切上下文。您可以在表的生命周期内跟踪第一行/最后一行,更新它们(一个或全部)
- 行 selectionModel 的 ListSelectionListener(如果用户正在阅读的行总是被选中)
- 垂直滚动条的 ChangeListener
- 一个 ComponentListener 来改变 scrollPane 的大小
于 2013-08-24T16:56:19.690 回答