Java Tips Weblog

  • Blog Stats

    • 1,178,246 hits
  • Categories

  • Archives

Table Column Adjuster

Posted by Rob Camick on November 10, 2008

JTable sets a default width for each TableColumn in the table. When designing the table you can alter this width by setting the preferred size of the table column. However this size is only going to be a best guess as to the real width of the column. The real width of the column will never be known until data has been loaded in the table. It would be nice to be able to alter the width of the columns so that all text in the cell is displayed.

The most accurate solution is to use the actual TableCellRenderer of each column in the JTable to calculate the preferred width of the cell based on the data contained in each cell. A basic implementation of this approach could be:

JTable table = new JTable( ... );
table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );

for (int column = 0; column < table.getColumnCount(); column++)
{
    TableColumn tableColumn = table.getColumnModel().getColumn(column);
    int preferredWidth = tableColumn.getMinWidth();
    int maxWidth = tableColumn.getMaxWidth();

    for (int row = 0; row < table.getRowCount(); row++)
    {
        TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
        Component c = table.prepareRenderer(cellRenderer, row, column);
        int width = c.getPreferredSize().width + table.getIntercellSpacing().width;
        preferredWidth = Math.max(preferredWidth, width);

        //  We've exceeded the maximum width, no need to check other rows

        if (preferredWidth >= maxWidth)
        {
            preferredWidth = maxWidth;
            break;
        }
    }

    tableColumn.setPreferredWidth( preferredWidth );
}

This simple implementation will only work for static data and does not include the column header when determining the width of the column. For more features you may want to consider using the TableColumnAdjuster described below. It provides more dynamic features for handling changes to the data in the TableModel.

In many cases a JTable will contain dynamic data. Maybe rows of data can be added or removed from the table, or maybe the user has the ability to modify the data in the cell of a table. Either of these changes may result in the preferred width of a column changing. In these cases you may want the ability to change the column widths after data is initially loaded and the ability to alter columns widths as the user changes the data in the table. The TableColumnAdjuster can handle these situations. That is not only can the TableColumnAdjuster be used to determine the initial columns widths, it can be configured to support dynamic calculation of column widths as the data changes.

To help the TableColumnAdjuster calculate the appropriate column width you can set the following properties:

  • Column Header Included – use the width of the column header
  • Column Data Included – loop through all the rows of the TableModel and find the cell renderer with the largest width
  • Only Adjust Larger – only reset the column width if the calculated value is greater than the current width of the column.

The maximum width calculated using the above properties will be used for the column width. To provide default column widths you might use code like the following which will generate the table shown in the image:


table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumnAdjuster tca = new TableColumnAdjuster(table);
tca.adjustColumns();

 

Above is an example of installing the column adjuster and using static adjustments. As mentioned earlier the TableColumnAdjuster also supports dynamic column adjusts using the following property:

  • Dynamic Adjustment - changes to the TableModel will cause the adjustments to occur automatically. Updating a table cell will cause the column to be adjusted. Adding/removing rows will cause all columns to be adjusted.

The user may find the dynamic adjustment a bit annoying if the width changes every time they type something, so we can also give the user to option to request column adjustments. This was done by adding Actions to the table which the user can invoke with the appropriate key stroke:

Action Key Stroke
Adjust Column Control +
Adjust Columns Control Shift +
Restore Column Control -
Restore Columns Control Shift -
Toggle Dynamic Control *
Toggle Larger Control /

 
There are four main methods that can be used to change the column widths:

  • Adjust Column – adjust the width of the specified column
  • Adjust Columns – adjust the width of all columns
  • Restore Column – restore the width of the specified column
  • Restore Columns – restore the width of all columns

Typically, you would only use the “Adjust Columns” method to initially set up the widths for all columns. The other methods are used to support the keyboard functionality.

Note, that this class was designed to be used with tables that use an auto resize mode of AUTO_RESIZE_OFF. With all other modes you are constrained, as the width of the columns must fit inside the table. So if you increase the width of one column, the widths of one or more of the other columns must decrease. Because of this, the resize mode of RESIZE_ALL_COLUMNS will work the best.
 
Hopefully the usage of the static methods along with the user controlled Actions will provide the flexibility needed to adjust the width of any column in any situation.

Try The Demo

Launch – Using Java™ Web Start (JRE 6 required)

Get The Code

Table Column Adjuster.java

Related Reading

Setting and Changing Table Column Widths
How to Use Key Bindings

About these ads

60 Responses to “Table Column Adjuster”

  1. I have been looking for something like this for a while now.
    It works like a charm!!
    Thanks millions!!

  2. lefameuxmarc said

    Hello,
    i was looking also for such class.
    it fits perfectly my needs:)

    Thank you very much

  3. Lionel said

    Hello Rob,

    The code worked absolutely perfectly upon implementation in my project. Thank you kindly for your effort and time spent to solve the same problem all us developers were struggling with!

    I have placed your details in the script code in my application, for future reference.

    Once again, thank you very much!

    Regards,
    Lionel

  4. Nirav said

    Hi Rob,
    You have done nice job here…Table column width setting is a main prob. in application..
    You gave here nice solution..but i have found another solution which might be little simple to understand than this…
    Kindly see it and tell me if its correct or some modification needed..
    it is here
    http://niravjavadeveloper.blogspot.com/2011/05/resize-jtable-columns.html

  5. Anonymous said

    hiii
    i don’t have jre6 but i really need this class
    can i have a version with jdk1.5?
    thanks a lot!

  6. Hi Rob,

    Thanks again!!! :)

    I have one question – if we set the Table Header as null, i am getting exception

  7. Michael said

    Rob, wow great class! I have modified it for my use. Among other things, I added a tableContainer member var and have a property that allows for expanding to the full container width (like JScrollPane) if it’s not already wider than the container (tricky since I want it to fill the container exactly so I have to size each column carefully). I also had to change your Map to be just a Map (column number and width key value pairs), and added some functionality to manage the Map since it didn’t allow for the change in number of columns and my table does that.

    • Rob Camick said

      Glad you where able to customize the code for your requirement.

    • Matt said

      Hey Michael that is exactly what I am trying to do as well however it doesn’t appear to be working for me. Another problem may be the fact that I have hidden columns in my table, but I would think that the table.convertColumnIndexToView(e.getColumn()); would handle that with a -1. Would you mind sharing your code?

      • Michael said

        I have not tried hidden columns, but my table changes number of columns and all data as part of its main purpose. It does that with pretty much everything you do in the program. The table is really used for just display purposes, derived from something else. I don’t use convertColumnIndexToView.

        I added a JScrollPane tableContainer member variable and put it in the constructor. I did the same with an int tableContainerExclusionZone to limit what space the table can encroach on because I have a row header in the left column that needed to be accounted for. Row headers are really a pain I’ve found since they’re not really supported in Swing like a column header is. That’s beyond me since plenty of tables have a header down the left (spreadsheets anyone?).

        So after that, I made a new method adjustColumnsFillContainerWidth() that’s actually called at the end of the adjustColumns() method. That checks the current table width (that was made from normal adjustColumns()). Now the table would have already kept its max width if columns were added by the nature of how it works, but if columns decreased, it may no longer fill the space. So it calculates any leftover width that can be filled (container width minus table and exclusion zone), and expands it if needed by going through each column and adding width evenly. I have it getting all the widths to add for everything first, then does the adjustColumn() for each one.

        I also needed to update the map holding the column widths to remove map elements if the number of columns was reduced. The adding of columns already worked via the map’s put method called in updateTableColumn().

        Your hidden columns may require more work to make sure it fills the space. I’m not sure how it works but it may budget the space for that and not appear to take up the whole width. You would have to do an extra step to take that into account, on both adding and subtracting columns.

      • Dave said

        So from my understanding here, if the table width is smaller than the visible viewport, the table won’t be stretched by the TableColumnAdjuster. I’ll try to achieve the same as Michael, but I’ll try a simpler approach (since all I want is to stretch small tables): if any leftover width (table is added to a jscrollpane), set the table to JTable.AUTO_RESIZE_ALL_COLUMNS.
        What I am struggling at is how to know if there’s any leftover. Can you share the piece of code you wrote to achieve that?

      • Dave said

        Alright, found what I wanted on Rob’s answer here: http://stackoverflow.com/a/15240806/468508

      • Michael said

        Dave, yeah you found it. Actually for a minute I thought I was doing all this work when I could have just been using AUTO_RESIZE_ALL_COLUMNS on my table but no, that causes it to be useless when there are too many columns in a limited space. That’s what I was dealing with when I coded my stuff.

        Thanks for replying back here with what you found!

        “What I am struggling at is how to know if there’s any leftover.”

        Well in case anyone is doing what I’m doing, here is the beginning of my method adjustColumnsFillContainerWidth() where it checks if there is leftover, and the helper it uses. The tableContainerExclusionZone is a var I added for the width of the part of the container that table should not encroach on since I have a row header in the first column as I mentioned above. You don’t need it if you don’t have a row header like me. The 2 is there since I just found that 2 pixels weren’t being accounted for, maybe a column margin or something but I ended up just using 2 after having trouble fiddling with that.

        public void adjustColumnsFillContainerWidth(){
        	//only proceed if we're not filling the container's width currently
        	int tableWidth = getTableWidth();
        	int tableContainerWidthMinusExcl = tableContainer.getWidth() - tableContainerExclusionZone - 2;
        	if (tableWidth &lt; tableContainerWidthMinusExcl){
        		//we have room to spare, need to expand into it
        		.... 
        	}
        }
                
        public int getTableWidth() {
        	int tableWidth = 0;
        	for (int i = 0; i &lt; columnSizes.size(); i++)
        		tableWidth += (int) columnSizes.get(i);
        	return tableWidth;
        }
        
  8. Wolv said

    Exactly what i was looking for, thanks for sharing!

  9. Amani said

    Thaaaaaank alot for your help … this is what I was looking for :)

  10. Taying said

    YOU ROCK!

  11. Anonymous said

    Amazing dude… Nice work… with this class, adjust column width jtable is like piece of cake…. thanks^^
    posting

  12. Anonymous said

    Very nice! This helped me a lot!

  13. Anonymous said

    Great Job thanks..!!

  14. Rui Tomas said

    Excelent class…
    Should be included by default :)
    Thanks

  15. Anonymous said

    thanks too!
    Robert, googling for a solution just like that :-)

  16. hi there, i found this googling, i tried on my project but arent working i guess. the columns stay the same as default after the adjustcolumns call. this works only when you type directly on the cell? im filling the table with data retreived from a database. you have any tips to make this work in my project? thanks!

  17. Anonymous said

    Thank you!
    Are you releasing this with an open source license (BSD)?

  18. Anonymous said

    wow, someone finally plugged that hole in the JDK libraries :-)
    thank you very very much for sharing it.
    would you consider putting this code up on github or something so that people may submit any further enhancements they make to it?

  19. Govind Koranga said

    working excellent…

    thank you very much…

  20. Anonymous said

    Dude! You are awesome! Saved me a boat load of time and effort. Thanks!

  21. Anonymous said

    I think the link is dead, can someone upload a new version?

  22. Anonymous said

    Thank you! Great class as many have said. Any chance this makes it to github so stuff like filling the full container makes it into the shared codebase? And you never answered the license question. Currently I am not sure if it is even possible to use the code legally for anything.

  23. Arild said

    Very useful…. thanx alot… Havent found greater example.

  24. Gian said

    How can I implement it on custom coded model jTable?
    private String[][] data;
    private String[] header = {“Client Name”, “Contact No.”, “Gender”, “Unit”, “No. of Released”, “Date”};
    DefaultTableModel model = new DefaultTableModel(data, header);

  25. Zekeriya Bars said

    Thanks a lot for this very useful class !

  26. Anonymous said

    Thanks a mil..

  27. Anonymous said

    Helped me a lot.
    You’re awesome!

  28. Anonymous said

    Works perfect, really great, thanks a lot:)

  29. Thanks a lot for the code!

  30. Anonymous said

    Worked like a charm

  31. Anonymous said

    Works perfect, really great, thanks man!!!

  32. AJ said

    this works if my table only has strings. How can I use (or adjust) the class to work if my table also has an image.

    I had to add,

    table.getColumnModel().getColumn(0).setCellRenderer(table.getDefaultRenderer(ImageIcon.class));

    to be able to display the image but now I can not resize the column widths. Any help would be appreciated.

    • Rob Camick said

      Using Icons works for me. I usually override the getColumnClass() method to return the class type of the column so the table can use the default Icon renderer. However, setting the renderer manually should also work, just make sure you set the renderer before using the TableColumnAdjuster.

  33. Dhalwani Rohit said

    Thank you so much for the effort made to write this code. It was very very useful.

  34. Radu said

    very very usefull class. I could easily adjust it to do the following:
    1) to make it work with null header
    2) to make it also auto adjust row height

  35. thanks for your post. I won a lot of time!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 91 other followers

%d bloggers like this: