52

I have a JTable that is within a JScrollPane. Rows are added to the table at runtime based on events that happen in my application. I want to have the scoll pane scroll to the bottom of the table when a new row is added to the table.

For JLists There is the [ensureIndexIsVisible][1]() that forces a particular index in the list to be visible. I'm looking for the same thing but for a JTable. It looks like I might have to manually move the scrolling view on the scroll pane but I figured there had to be an easier way.

Lalji Tadhani
  • 14,041
  • 3
  • 23
  • 40
Chris Dail
  • 25,715
  • 9
  • 65
  • 74

5 Answers5

82

It's very easy, JTable has scrollRectToVisible method too. If you want, you can try something like this to make scrollpane go to to the bottom if a new record is added :

jTable1.getSelectionModel().setSelectionInterval(i, i);
jTable1.scrollRectToVisible(new Rectangle(jTable1.getCellRect(i, 0, true)));

Where i is last added record.

lost_in_the_source
  • 10,998
  • 9
  • 46
  • 75
martinusadyh
  • 1,120
  • 1
  • 8
  • 11
  • 1
    This works well, as expect, and functions like ensureindexisvisible() (or whatever that method is) from Jlist. The code marked as the answer did not function properly. it did not scroll all the way to the index after a 5-6 calls down a longer list and would not show the entire row every time when it did scroll. some rows were left cut off. This should be the answer. – Bastiat Apr 12 '13 at 14:47
  • 1
    Simple and works. Just one question, what's the purpose of the first line? It looks like the second line is sufficient. Btw, I also needed to scroll to a specific column and it works fine too by setting the second parameter of getCellRect. – Smig Jan 20 '15 at 19:17
  • 7
    ...and what should be the sense of new Rectangle() ? getCellRect() already returns a Rectangle! – Elmue Dec 23 '16 at 22:58
  • What about `jTable1.changeSelection()`? Is it better or worse than `jTable1.getSelectionModel().setSelectionInterval(i, i);`? – Gustavo Jul 03 '17 at 20:16
  • FYI I tried just jTable1.scrollRectToVisible(dataTable.getCellRect(row, 0, true));
    and it works. @elmue
    – cliff2310 May 29 '18 at 22:43
  • Ok it works, but if you see that it doesn't work, be careful not to have done any resize operations on the frame before running that code (eg. `jframe.pack()`) – Memmo Jul 20 '22 at 08:59
35

See this example : http://www.exampledepot.com/egs/javax.swing.table/Vis.html

update: the link is now obsolete, here is the code (from http://smi-protege.stanford.edu/repos/protege/protege-core/trunk/src/edu/stanford/smi/protege/util/ComponentUtilities.java )

public static void scrollToVisible(JTable table, int rowIndex, int vColIndex) {
        if (!(table.getParent() instanceof JViewport)) {
            return;
        }
        JViewport viewport = (JViewport)table.getParent();

        // This rectangle is relative to the table where the
        // northwest corner of cell (0,0) is always (0,0).
        Rectangle rect = table.getCellRect(rowIndex, vColIndex, true);

        // The location of the viewport relative to the table
        Point pt = viewport.getViewPosition();

        // Translate the cell location so that it is relative
        // to the view, assuming the northwest corner of the
        // view is (0,0)
        rect.setLocation(rect.x-pt.x, rect.y-pt.y);

        table.scrollRectToVisible(rect);

        // Scroll the area into view
        //viewport.scrollRectToVisible(rect);
    }
Pierre
  • 34,472
  • 31
  • 113
  • 192
  • 2
    Wrong and far too complicated! This can be done in one single line: – Elmue Dec 23 '16 at 22:53
  • 12
    table.scrollRectToVisible(table.getCellRect(row,column, true)); – Elmue Dec 23 '16 at 22:53
  • I also had to add table.revalidate(); before calling any of the solutions on this page, otherwise it only scrolled to the row before the last row, or didn't scroll at all. – foolo Jul 28 '21 at 17:02
6

JList internally use scrollRectToVisible and specify the coordinates to scroll to. I think you will have to recode a similar functionality for JTable.

Valentin Rocher
  • 11,667
  • 45
  • 59
1

The first answer works well, but the selected row gets positioned at the bottom of the table. So I created this modified version:

private void scrollToVisible(int rowIndex, int vColIndex ) {
        JTable table = getTablePanel().getTable();
        if (!(table.getParent() instanceof JViewport)) {
            return;
        }
        if (table.getRowCount()<1){
            return;
        }
        JViewport viewport = (JViewport)table.getParent();
        // view dimension
        Dimension dim = viewport.getExtentSize();
        // cell dimension
        Dimension dimOne = new Dimension(0,0);

        // This rectangle is relative to the table where the
        // northwest corner of cell (0,0) is always (0,0).
        Rectangle rect = table.getCellRect(rowIndex, vColIndex, true);
        Rectangle rectOne;
        if (rowIndex+1<table.getRowCount()) {
            if (vColIndex+1<table.getColumnCount())
                vColIndex++;
            rectOne = table.getCellRect(rowIndex+1, vColIndex, true);
            dimOne.width=rectOne.x-rect.x;
            dimOne.height=rectOne.y-rect.y;
        }

        // '+ veiw dimension - cell dimension' to set first selected row on the top

        rect.setLocation(rect.x+dim.width-dimOne.width, rect.y+dim.height-dimOne.height);

        table.scrollRectToVisible(rect);
    }

Now the selected row gets positioned at the top of the table.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
MGaidamak
  • 65
  • 6
  • no, you don't need the viewport to scroll to anywhere in the table (all components have a getVisibleRect method) – kleopatra Mar 12 '13 at 12:34
  • Does not always work if table is already scrolled further than rowIndex and vColIndex. To fix this, just insert table.scrollRectToVisibile(new Rectangle(0, 0, 0, 0)); before the row: table.scrollRectToVisible(rect) – WannaBe Oct 17 '22 at 06:50
1

It seems to me a lot easier to set the viewport position instead of scrolling the table. Following is my code.

public void scrollCellToView(int rowIndex, int vColIndex) {
    if (!(this.getParent() instanceof JViewport)) {
        return;
    }
    JViewport viewport = (JViewport) this.getParent();
    Rectangle rect = this.getCellRect(rowIndex, vColIndex, true);
    Rectangle viewRect = viewport.getViewRect();

    int x = viewRect.x;
    int y = viewRect.y;

    if (rect.x >= viewRect.x && rect.x <= (viewRect.x + viewRect.width - rect.width)){

    } else if (rect.x < viewRect.x){
        x = rect.x;
    } else if (rect.x > (viewRect.x + viewRect.width - rect.width)) {
        x = rect.x - viewRect.width + rect.width;
    }

    if (rect.y >= viewRect.y && rect.y <= (viewRect.y + viewRect.height - rect.height)){

    } else if (rect.y < viewRect.y){
        y = rect.y;
    } else if (rect.y > (viewRect.y + viewRect.height - rect.height)){
        y = rect.y - viewRect.height + rect.height;
    }

    viewport.setViewPosition(new Point(x,y));
}