Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am trying to use JTable in the way where new data record are added to the end. The strange thing is the scroll bar does not go to the end of the table; instead, it always shows the second from the last. Any way to tell the scroll bar to always go to the end of the table?

Here is part of my code:

table.scrollRectToVisible(table.getCellRect(table.getRowCount()-1, 0, true));
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
474 views
Welcome To Ask or Share your Answers For Others

1 Answer

I just ran into this problem - there is actually nothing wrong with that line of code; the problem lies in when you execute it.

If you're, like me, trying to execute it immediately after manipulating the TableModel (even via invokeLater) or by using a TableModelListener, you'll get the problem you're describing. The problem is that while the model has been updated with the new data (table.getRowCount() is simply a pass-through to the getRowCount() method on your TableModel), the JTable component visually has not.

When you execute that line of code in the previously described places, you're actually trying to tell the JScrollPane (JTable.scrollRectToVisible defers any action to a parent that can provide scrolling behaviour, e.g. JScrollPane) to scroll beyond the end of the enclosed JTable component. It refuses to do that, and instead scrolls to the current end of the JTable component instead.

At some point later, the JTable component updates itself visually, and adds the newly added row underneath the row scrolled to earlier. You can verify that that line of code works by adding a button that executes it independently of the code that adds new rows, e.g.

private JTable _table = new JTable();
...
JButton b = new JButton("Force scroll to bottom");
b.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) { 
        _table.scrollRectToVisible(_table.getCellRect(_table.getRowCount()-1, 0, true));
    }
});
this.add(b);

The solution to this problem is a little indirect, but does work reliably in my testing. Because the issue lies in the visual side of things, I decided to hook into the ComponentListener instead, which provides, among other things, a componentResized method. Whenever a row is added or removed, the JTable resizes, even if it cannot be seen visually due to the JScrollPane's viewport. Therefore just run that line of code in that listener method, and things will work as expected.

private JTable _table = new JTable();
...
_table.addComponentListener(new ComponentAdapter() {
    public void componentResized(ComponentEvent e) {
        _table.scrollRectToVisible(_table.getCellRect(_table.getRowCount()-1, 0, true));
    }
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...