Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a JTable where the first column is always in the JScrollPane viewport?

What's the best way to set up a table in a JScrollPane such that the first column is always on the screen in the same position regardless of horizontal scrolling and overlaps columns that pass underneath?

When the scrollbar is at the farthest left, the columns look normal, but as the user scrolls to the right, the secondary columns (2 and on) move underneath the first until the last column appears on the far right of the viewport?

I found a sample taken from Eckstein's "Java Swing" book that sort of does this, but it doesn't allow resizing of the first column. I was thinking of some scheme where one JPanel held a horizontal struct and a table holding the secondary columns and another JPanel which floated over them (fixed regardless of scrolling). The struct would be to keep the viewport range constant as the first column floated around. Ideally I could do it with two tables using the same model, but I'm not sure if the whole idea is a naive solution.

I'd ideally like a setup where multiple tables are on the same scrollpane vertically, where all their first columns are aligned and move together and there are just little horizontal gaps between the individual tables.

like image 708
voodoogiant Avatar asked Mar 30 '10 19:03

voodoogiant


2 Answers

Fixed Column Table does most of what you need.

It does not support resizing the fixed column so you would need to add code like:

MouseAdapter ma = new MouseAdapter()
{
    TableColumn column;
    int columnWidth;
    int pressedX;

    public void mousePressed(MouseEvent e)
    {
        JTableHeader header = (JTableHeader)e.getComponent();
        TableColumnModel tcm = header.getColumnModel();
        int columnIndex = tcm.getColumnIndexAtX( e.getX() );
        Cursor cursor = header.getCursor();

        if (columnIndex == tcm.getColumnCount() - 1
        &&  cursor == Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR))
        {
            column = tcm.getColumn( columnIndex );
            columnWidth = column.getWidth();
            pressedX = e.getX();
            header.addMouseMotionListener( this );
        }
    }

    public void mouseReleased(MouseEvent e)
    {
        JTableHeader header = (JTableHeader)e.getComponent();
        header.removeMouseMotionListener( this );
    }

    public void mouseDragged(MouseEvent e)
    {
        int width = columnWidth - pressedX + e.getX();
        column.setPreferredWidth( width );
        JTableHeader header = (JTableHeader)e.getComponent();
        JTable table = header.getTable();
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = (JScrollPane)table.getParent().getParent();
        scrollPane.revalidate();
    }
};

JTable fixed = fixedColumnTable.getFixedTable();
fixed.getTableHeader().addMouseListener( ma );
like image 188
camickr Avatar answered Oct 26 '22 12:10

camickr


JScrollPane has an area specifically for this, the row header (see the diagram in the API:)

All you need to do is: - create an extra JTable for this fixed area - hook it up to the first column of your data model - set it as the row header - and in the main table omit or remove the first column of data.

When the scrollpane scrolls up and down both tables will scroll in sync with no added code. When the scrollpane scrolls horizontally the row header is always kept visible and only the main table scrolls.

For most cases the only added code you'll need is for the column resizing, like camickr's example.

like image 39
Keilly Avatar answered Oct 26 '22 12:10

Keilly