views:

456

answers:

3

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.

+1  A: 

I think you are on the right track. What you conceptually have is a table with a 'header column' for each row. I would use two tables - one has the 'leftmost' column in and the other has all the others. Then I would present these in a JSplitPane with the 'leftmost column' table on the left and the rest on the right. There would be a single vertical scrollbar that controlled the y offset of both tables, and a single horizontal scrollbar controlling the right hand pane (only).

You can also use the advanced features of JScrollPane to set a 'heqder' component on the left of the main scroll area. I've never done it, but you might be able to use that as the 'headers' of your rows.

DJClayworth
+3  A: 

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 );
camickr
Hrmm, I expected my question to be more obscure to get an answer to quickly. That should work extremely well. I'll try it with the resizeable columns code you provided. Thanks.
voodoogiant
+1  A: 

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.

Keilly