Auto resizing the JTable column widths
Asked Answered
C

7

37

I need my JTable to automatically re-size its column widths to fit the content. I found the TableColumnAdjuster class very useful. But there's a small problem. Say i have 5 columns, and their content is very short. In that case, if i use the auto adjuster, it sets the first four columns widths according to their content and gives all the rest of space to the last column. Please see the example.

enter image description here

Here the last column, Balance is given all the excess space. But what if i need to give that space to one of the middle columns. In the above case, i need to assign that space to the third column, name. I tried modifying the TableColumnAdjuster class's adjustColumns() method. But I couldn't get it working.

I tried both column.setPreferredWidth() and column.setWidth() for changing column sizes. But seems it doesn't change anything. How can I effectively change the column sizes of a JTable. If there's some other alternative or a direct answer to my main problem, that's better. Thanks!

Cobnut answered 13/7, 2013 at 5:57 Comment(0)
C
77

You can try the next:

public void resizeColumnWidth(JTable table) {
    final TableColumnModel columnModel = table.getColumnModel();
    for (int column = 0; column < table.getColumnCount(); column++) {
        int width = 15; // Min width
        for (int row = 0; row < table.getRowCount(); row++) {
            TableCellRenderer renderer = table.getCellRenderer(row, column);
            Component comp = table.prepareRenderer(renderer, row, column);
            width = Math.max(comp.getPreferredSize().width +1 , width);
        }
        if(width > 300)
            width=300;
        columnModel.getColumn(column).setPreferredWidth(width);
    }
}

JTable

This needs to be executed before the resize method.
If you have:

table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

JTable

Cryptonymous answered 13/7, 2013 at 6:9 Comment(9)
This is fantastic, ended up using it. I added a check before the setPreferredColumnModel call that looks like "if(width > 300)width=300;" which fixes some cases where I'm displaying really long data fields. I'd suggest adding that to the answer--and you might also extract out min/max width (Would make fantastic optional parameters--in fact I'm going to go do that in my codebase now.) (I wish I knew when it was cool to edit something like that into someone else's answer... Since it's not CW I hate to change content without permission.)Mireyamiriam
Hi, @BillK Feel free to edit/add the code... and if you have, a screenshot. ;)Cryptonymous
can I also somehow evaluate the header too so that its text won't get cut off?Marilou
@Xerus Add width = Math.max(width, table.getColumnModel().getColumn(column).getPreferredWidth()); after line 9 in the above code to evaluate the headers.Vega
Worked perfectly, as expected!Convolute
Great approach. fits perfect. Enhancement: 1. add ` && width < max` to the 2nd expression of the inner for loop for better performance. 2. Use setPreferredWidth(Math.min(max, width)) instead the if expression. 3. Optionally set min, max as parameters for the function.Itol
@Vega Your suggestion does not help, if the wanted column min width is < 75, because this is the initial default of table.getColumnModel().getColumn(column).getPreferredWidth().Itol
@PaulVargas Why do you set to .width +1 instead just .width?Itol
See also: #78348116Itol
I
4

There is no option to automatically resize one column larger than the other.

Maybe you can to something like:

tca = new TableColumnAdjuster( table, 0 );
tca.adjustColumns();
TableColumnModel tcm = table.getColumnModel();  
TableColumn tc = tcm.getColumn(1);
tc.setWidth(tc.getWidth() + 25);

This would allow you to add extra space to column 1. This extra space would only be added the first time the table is displayed.

Another option is to use:

table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);

This would allocate extra space proportionally to each column.

Insulate answered 13/7, 2013 at 15:41 Comment(1)
This is the opposite of what was asked. "table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);" resizes all columns evenly without considering the content length.Debase
E
4

setAutoResizeMode() will tell your table how to resize you should give it a try will all different options available to see the differences, in My case I wanted to specifically resize two columns and let it decide how to adjust all the other ones.

jTable1.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
TableColumnModel colModel=jTable1.getColumnModel();
colModel.getColumn(1).setPreferredWidth(25);    
colModel.getColumn(2).setPreferredWidth(400);
Esquivel answered 8/4, 2017 at 22:43 Comment(0)
C
2

With a slight modification to Paul Vargas's answer, you can also take into account the column header size:

public static void resizeColumnWidth(JTable table) {
    final TableColumnModel columnModel = table.getColumnModel();
    for (int column = 0; column < table.getColumnCount(); column++) {
        // Account for header size
        double width = table.getTableHeader().getHeaderRect(column).getWidth();
        for (int row = 0; row < table.getRowCount(); row++) {
            TableCellRenderer renderer = table.getCellRenderer(row, column);
            Component comp = table.prepareRenderer(renderer, row, column);
            width = Math.max(comp.getPreferredSize().width + 1, width);
        }
        if (width > 300)
            width = 300;
        columnModel.getColumn(column).setPreferredWidth((int) width);
    }
}
Centurial answered 16/9, 2022 at 17:24 Comment(1)
This only works, if you accept a minimal width of 75 which is the default of table.getTableHeader().getHeaderRect(column).getWidth().Itol
I
1

If you also want to take the column header's content into account, use:
(For better performance it too stops the inner for loop when max is reached.)

  private static void resizeColumnWidth(JTable table, int min, int max) {
    for (int col=0; col<table.getColumnCount(); col++) {
      TableColumn tbColumn = table.getColumnModel().getColumn(col);
      TableCellRenderer renderer = tbColumn.getHeaderRenderer();
      if (renderer == null)
        renderer = table.getTableHeader().getDefaultRenderer();
      int width = Math.max(min, renderer.getTableCellRendererComponent(table,
          tbColumn.getHeaderValue(), false, false, -1, col).getPreferredSize().width);
      for (int row=0; row<table.getRowCount() && width<max; row++) {
        Component comp = table.prepareRenderer(table.getCellRenderer(row, col), row, col);
        width = Math.max(width, comp.getPreferredSize().width);
      }
      tbColumn.setPreferredWidth(Math.min(width, max));
    }
  }
Itol answered 18/4 at 16:54 Comment(0)
Y
0

You can do this:

JPanel jp = new JPanel();
jp.add(table);

jp.setLayout(new GridLayout(1,1)); /* little trick ;) and believe me that this step is important to the automatic all columns resize! A import is also needed for using GridLayout*/
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); // this is obvius part
Yellowbird answered 18/9, 2014 at 9:45 Comment(0)
L
0

With a slight modification to Paul Vargas's answer, you can also take into account the column header's content:

public static void resizeColumnWidth(JTable table)
{
      TableCellRenderer renderer;
      TableColumn column;
      Component component;
      Object header;
      int rowIndex, minWidth, width;

      column = table.
         getColumnModel().
         getColumn(colIndex);

      renderer = table.
         getTableHeader().
         getDefaultRenderer();

      header    = column.getHeaderValue();
      component = renderer.getTableCellRendererComponent(table, header, false, false, -1, colIndex);
      width     = component.getPreferredSize().width;
      minWidth  = Math.max(width, 0);

      for (rowIndex = table.getRowCount(); --rowIndex >= 0; )
      {
         renderer  = table.getCellRenderer(rowIndex, colIndex);
         component = table.prepareRenderer(renderer, rowIndex, colIndex);
         width     = component.getPreferredSize().width;
         minWidth  = Math.max(minWidth, width);
      }

      column.setPreferredWidth(minWidth);
    }

Note: This is different from Cardinal System's answer in that this code takes into account the header's content and Cardinal System's answer just takes into account the header's size.

Logo answered 15/5, 2023 at 22:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.