Friday, May 7, 2010

Auto-Alignment of JTable TableHeaders

Most Java programmers are familiar with setting up various TableCellRenderers for the contents of JTables.  Often the JTable.getDefaultRenderer() defaults are fine, if you set the proper class for each column.  Else you create your own class, typically subclassing JLabel or DefaultTableCellRenderer.  Numeric data is typically right aligned/justified, perhaps with a fixed number of decimal points, so that the digits line up nicely.  Text, boolean, and graphical data are more often left or center aligned.  In all, this entails some work, but the time spent seems to be justified

Ideally, the table headers, which are usually just the names of each column, should also be aligned to match their data.  You can painstakingly set up a custom renderer for each TableColumn, via something like myTable.getColumn().setHeaderRenderer().  For the common case where it is just a text label, this is tedium and overkill.  One could write some utility method to help out.

When recently confronted with this problem, I had a brainstorm that worked easily and simply for my client's code.  I had already painstaking setup the TableCellRenderers for each column.  Instead of duplicating that effort, why not just ask them?  The code looks like this:

public Component getTableCellRendererComponent(JTable table, Object value,
boolean selected, boolean focused, int row, int column)
{
// get the existing JLabel used for a renderer, for example
  JLabel jl = (JLabel) super.getTableCellRendererComponent(table, value, selected, focused, row, column);

// get the corresponding data renderer
  TableCellRenderer dr = table.getCellRenderer(row, column);
  if (dr instanceof JLabel)
    jl.setHorizontalAlignment(((JLabel)dr).getHorizontalAlignment());
  else
    jl.setHorizontalAlignment(SwingConstants.LEFT);  // or whatever works for a default for you

... // more code removed, 
  return jl;
}
}


You might worry that all the sets of HorizontalAlignment are slow and will fire a lot of property change events, but, assuming you are using a subclass of DefaultTableCellRenderer, they won't.  And ain't modern fast CPUs great?

Anyway, hoping this will help one of your projects.  I'm less familiar with the newfangled SwingX Highlighters, but seems like this would be a good place for them