views:

100

answers:

3

I'm trying to use an empty column as a divider between pairs of columns in a JTable. Here's a picture and code for what I have so far. I know I can change the look using a custom TableCellRenderer. Before I go down that road, is there a better way to do this? Any ideas appreciated.

TablePanel.png

import javax.swing.*;
import javax.swing.table.*;

public class TablePanel extends JPanel {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame("TablePanel");
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.add(new TablePanel());
                f.pack();
                f.setVisible(true);
            }
        });
    }

    public TablePanel() {
        TableModel dataModel = new MyModel();
        JTable table = new JTable(dataModel);
        table.getColumnModel().getColumn(MyModel.DIVIDER).setMaxWidth(0);
        JScrollPane jsp = new JScrollPane(table);
        jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        this.add(jsp);
    }

    private static class MyModel extends AbstractTableModel {

        private static final int DIVIDER = 2;
        private final String[] names = { "A1", "A2", "", "B1", "B2" };

        @Override
        public int getRowCount() {
            return 32;
        }

        @Override
        public int getColumnCount() {
            return names.length;
        }

        @Override
        public String getColumnName(int col) {
            if (col == DIVIDER) return "";
            return names[col];
        }

        @Override
        public Object getValueAt(int row, int col) {
            if (col == DIVIDER) return "";
            return (row + 1) / 10.0;
        }

        @Override
        public Class<?> getColumnClass(int col) {
            if (col == DIVIDER) return String.class;
            return Number.class;
        }
    }
}
+2  A: 

Without knowing what do you want to show in this table it's hard to tell whether you've selected good solution or not.

Regarding this solution. This column does not seem like a divider. Paint it with gray/another color, or paint divider header cell in white.

But anyway I'd prefer JScrollPane + two tables inside it instead of this solution.

Alexander Babaev
+2  A: 

On problem with this approach it that the user will need to "tab over" the divider column. You could use the Table Tabbing suggestion to make it more user friendly.

Or if tabbing between the two tables isn't important, then maybe you can use use two tables and put whatever divider you want betweeen the two. The selection model can shared if required.

Edit:

As I suggested above sharing models is easier than writing custom listeners. To keep the scrolling in sync the code would be:

jspa.getVerticalScrollBar().setModel( jspb.getVerticalScrollBar().getModel() );

You can also do the same with the selection model so that highlighting of rows is in sync.

camickr
+1 Thanks for reminding me about tabbing. It's not important for this, but the article is good. My empty column idea also made sorting a problem.
Catalina Island
Oh, that's what that means! I changed it below. Thanks.
Catalina Island
+1  A: 

I kind of combined both answers: I used two tables that share one's scrollbar. This works with sorting, and it actually makes the model simpler. Tabbing doesn't matter, but comparing "A" and "B" does. I think I was trying to solve a "view" problem in the "model". I made this a separate answer, because I'd appreciate any critical comments.

TablePanel

public TablePanel() {
    this.setLayout(new GridLayout(1, 0, 8, 0));

    JTable tableA = new JTable(new MyModel("A"));
    tableA.setPreferredScrollableViewportSize(new Dimension(200, 400));
    final JScrollPane jspA = new JScrollPane(tableA);
    jspA.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    this.add(jspA);

    JTable tableB = new JTable(new MyModel("B"));
    tableB.setPreferredScrollableViewportSize(new Dimension(200, 400));
    final JScrollPane jspB = new JScrollPane(tableB);
    jspB.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    this.add(jspB);

    tableA.setSelectionModel(tableB.getSelectionModel());
    jspA.getVerticalScrollBar().setModel(jspB.getVerticalScrollBar().getModel());
}
Catalina Island
See my edit above.
camickr