开发者

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

开发者 https://www.devze.com 2022-12-25 07:34 出处:网络
What\'s t开发者_开发知识库he 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

What's t开发者_开发知识库he 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.


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 );


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.


Check out this class, extracted from http://fahdshariff.blogspot.sg/2010/02/freezing-columns-in-jtable.html

import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.JViewport; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.JTableHeader; 
import javax.swing.table.TableModel;   
public class FrozenTablePane extends JScrollPane{     
    public FrozenTablePane(JTable table, int colsToFreeze){     
        super(table);       
        TableModel model = table.getModel();       
        //create a frozen model     
        TableModel frozenModel = new DefaultTableModel(                                 
                model.getRowCount(),                                 
                colsToFreeze);       
        //populate the frozen model     
        for (int i = 0; i < model.getRowCount(); i++) {       
            for (int j = 0; j < colsToFreeze; j++) {         
                String value = (String) model.getValueAt(i, j);         
                frozenModel.setValueAt(value, i, j);       
            }     
        }
    //create frozen table
    JTable frozenTable = new JTable(frozenModel);
    //remove the frozen columns from the original table
    for (int j = 0; j < colsToFreeze; j++) {
    table.removeColumn(table.getColumnModel().getColumn(0));
    }     table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    //format the frozen table     
    JTableHeader header = table.getTableHeader();     
    frozenTable.setBackground(header.getBackground());     
    frozenTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);    
    frozenTable.setEnabled(false);     
    //set frozen table as row header view   
    JViewport viewport = new JViewport();    
    viewport.setView(frozenTable); 
    viewport.setPreferredSize(frozenTable.getPreferredSize());   
    setRowHeaderView(viewport);   
    setCorner(JScrollPane.UPPER_LEFT_CORNER, 
            frozenTable.getTableHeader()); 
    }
}

Thereafter, just call the constructor method:

JTable table = new JTable( <yourData>, <yourColumns> );
FrozenTablePane frozenPane = new FrozenTablePane(table,1);//where 1 is the number of freezed column(s)


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 'header' 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消