Tuesday, January 03, 2006

Getting JTable columns widths to fit the data

I've been stumped on a JTable problem for quite a while now: how to get the columns to fit the width of the data in the cells. Out of the box, JTable uses the same width for all columns in a table. This is very annoying for non-editable tables which just display data. I want my Java tables to looks similar to HTML tables which resize column widths according to the cell contents.

A likely solution is simply that I did not search Google well enough, but information was frustratingly rare to find for me.

I did, however, eventually stumble across the prepareRenderer(TableCellRenderer renderer, int row, int column):Component method (and likewise prepareRenderer(TableCellEditor editor, int row, int column):Component). A flash of insight illuminated the solution at once:

{
    final TableCellRenderer renderer = getTableHeader()
            .getDefaultRenderer();

    for (int i = 0; i < getColumnCount(); ++i)
        getColumnModel().getColumn(i).setPreferredWidth(
                renderer.getTableCellRendererComponent(this,
                        getModel().getColumnName(i), false, false, 0, i)
                        .getPreferredSize().width);
}

public Component prepareRenderer(final TableCellRenderer renderer,
        final int row, final int column) {
    final Component prepareRenderer = super
            .prepareRenderer(renderer, row, column);
    final TableColumn tableColumn = getColumnModel().getColumn(column);

    tableColumn.setPreferredWidth(max(
            prepareRenderer.getPreferredSize().width,
            tableColumn.getPreferredWidth()));

    return prepareRenderer;
}

My solution has two parts. Addressing first prepareRenderer: as the table is drawn, adjust the preferred width of a column to be at least as wide as the widest cell seen so far. This was 90% of my problem right there. Immediately I stopped having truncated cells, and the table adjusted gracefully to new cell data which did not fit the old column widths.

The second part is more obscure: the instance initializer. Although my cell contents were now always visible, the proportions among the columns did not look quite right: narrow columns were not narrow enough with excess slop on either side of column titles. So I instructed the table to shrink column widths down to just that necessary to show the title (prepareRenderer will widen them again as needed for cell contents). Perfect!

What surprises me is that I was unable to find this or a similar solution anywhere in my Google searches. I can scarcely believe this is the first attempt at this approach. Hopefully Sun will include a solution in the JDK—this is not an uncommon JTable problem.

UPDATE: This topic continues to deliver: Alex Boosmeeuw posts with a different approach.

Post a Comment