如何在表的开头添加行后使JScrollPane不滚动

时间:2013-08-20 08:16:27

标签: java swing jtable focus jscrollpane

我有窗口显示表中的日志事件。 例如,用户正在读取某行表格中的文本。当新日志到来时,它们会添加到表的开头,而用户正在读取的行向下移动。我需要在表的开头添加新行时阻止JScrollPane滚动。我尝试了不同的东西,但没有任何帮助。有人可以建议我如何实现这个? 提前谢谢!

1 个答案:

答案 0 :(得分:1)

棘手的任务:-)移出是因为默认情况下滚动位置以任何方式调整:在上面添加行只是保持垂直滚动位置,然后指向不同的行,如前所述

需要什么:

  • 在插入
  • 之前跟踪visibleRect /最后一行
  • 听取类型insert
  • 的模型更改
  • 计算新的可见矩形,使旧的最后一行滚动回视图
  • 触发滚动

这很棘手,因为我们需要听取模型的变化。该侦听器是由表在内部注册的modelListener的邻居,该表在更改时自行更新。因此,我们需要确保在内部更改完成后行动,同时在内部更新之前使用信息。

一个肮脏的解决方案 - 取决于最后添加的第一次通知的摇摆侦听器通知的常规顺序(当心:生产代码中的 DONT !在更改LAF时它会轻易破坏,fi ) - 是在收到通知后收集前状态并调整包含在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);

适当地获取前状态的方式取决于您的确切背景。您可以在表的生命周期内跟踪第一行/最后一行,在(一个或所有)

中更新它们
  • 一个ListSelectionListener到行selectionModel(如果总是选择用户正在读取的行)
  • 将ChangeListener更改为垂直scrollBar
  • 要使用scrollPane的大小更改的ComponentListener