Search code examples
javaswingjtablejtableheadertableheader

Re-Using JTableHeader


The code below displays 2 JTables.

As they both will have exactly the same headers I wanted, for the sake of efficiency, to reuse the header from the first table.

However running the code results in the header appearing in the second table but not in the table it came from originally.

I am less interested in work-arounds, but - for the sake of learning and understanding - more interested in finding out why the header does not appear in the first table.

Here is the code:

public class HeaderTest1 {

public void doTheTest() {
    JFrame testFrame = new JFrame("Header Test");
    JPanel pane = new JPanel();

    Container theContentPane = testFrame.getContentPane();

    BoxLayout box = new BoxLayout(pane, BoxLayout.Y_AXIS);
    pane.setLayout(box);
    theContentPane.add(pane);

    String theData[][]
            = {
                {"One", "two", "3"},
                {"four", "5", "six"},
                {"7", "8", "9.0"},
                {"£10.00", "11", "twelve"}
            };

    String columnNames[] = {"Column 1", "Column 2", "Column 3"};

    JTable firstTable = new JTable(theData, columnNames);

    JScrollPane thisScrollPane = new JScrollPane(firstTable);
    JTableHeader thisTableHeader = firstTable.getTableHeader();

    pane.add(thisScrollPane);

    buildTheSecondTable(thisTableHeader, firstTable, columnNames, pane);

    testFrame.pack();
    testFrame.setVisible(true);
}

private void buildTheSecondTable(JTableHeader headerFromTheFirstTable,
        JTable firstTable, String[] columnNames, JPanel pane) {

    JTable secondTable = new JTable();
    int columnCount = columnNames.length;

    JScrollPane thisScrollPane = new JScrollPane(secondTable);
    secondTable.setTableHeader(headerFromTheFirstTable);

    Object[][] emptyData = new Object[1][columnCount];
    for (int n = 0; n < columnCount; n++) {
        emptyData[0][n] = "";
    }
    DefaultTableModel thisTableModel = new DefaultTableModel();
    thisTableModel.setDataVector(emptyData, columnNames);
    secondTable.setModel(thisTableModel);
    secondTable.setLayout(firstTable.getLayout());
    secondTable.setCellEditor(firstTable.getCellEditor());
    pane.add(thisScrollPane);
}

public static void main(String[] args) throws SQLException, ParseException {
    HeaderTest thisTest = new HeaderTest();
    thisTest.doTheTest();
}

Any advice would be appreciated


Solution

  • A Swing component can only have a single parent so you can't share the table header component.

    You can however share the Array of column names:

    JTable firstTable = new JTable(theData, columnNames);
    

    In your buildTheSecondTable method you have access to the array of column names so just use:

    //DefaultTableModel thisTableModel = new DefaultTableModel();
    DefaultTableModel thisTableModel = new DefaultTableModel(columnNames);
    

    Then you can add data to the model and the model to the table.

    Then reorder the code to create the JScrollPane after you add the model to the table.

    Also, get rid of the table.setLayout() code. You would never use a layout manager on a table. You don't add components to the table. The table renders the data itself without using real components.