Simplest JTable icon cell renderer ever

While there are many examples of JTable cell renderers spread on the Internet, they lack a clear understanding about how they were proposed to work. This article presents and explains a minimal and correct cell renderer, extending the default cell renderer as supposed by the Java API. The example explains how to display icons instead of text.

Originally published at https://techtavern.wordpress.com.

For the hurried, first the code:

public class EnumIconCellRenderer extends DefaultTableCellRenderer {

private final Map<!--?, ImageIcon--> icones;

  public EnumIconCellRenderer(final Map<!--?, ImageIcon--> icones) {
    // Initialize data used to render cells.
    this.icones = icones;

    // Set properties that never change.
    this.setHorizontalAlignment(JLabel.CENTER);
    this.setVerticalAlignment(JLabel.CENTER);
    this.setText(null);
  }

  @Override
  protected void setValue(Object value) {
    // Set properties that change on individual cells.
    this.setIcon(icones.get(value));
  }
}

A cell renderer works like a rubber-stamp for each cell in the table. The renders uses a Swing component to draw the first cell, changes the contents of that cell renderer, and for each following row shifts the origin of the component to the new location, then re-draws it. The default cell renderer uses the convenient JLabel to stamp a potentially inconvenient toString() representation of data objects. Note that getTableCellRendererComponent() returns itself (the JLabel), but properly configured for an individual cell. Therefore, setting properties of the renderes itself actually configures the component returned by getTableCellRendererComponent().

The proposed cell renderer extends DefaultTableCellRenderer as expected. The constructor sets those JLabel properties that will never change. And might initialize some internal data, in our example, a map of icons for each possible value.

I strongly discourage overriding getTableCellRendererComponent() as usually recommended by the Java community. It would incur separation of concerns, plainness and performance issues.

The getTableCellRendererComponent() method is intended to configure the JLabel appearance according to the focus and selection state. Handling the value in this method makes code more confusing by mixing appearance, look & feel and data. The setValue() method offers clearer and more reasonable location to adjust properties that depend solely on data.

By insisting on handling data in getTableCellRendererComponent() instead of setValue(), performance decreases. By design, setValue() is called by your customized code. Most implementations end up reseting or undoing properties from the default implementation of setValue(), which in turn resorts to the quite expensive and misleading toString() method over the data objects.

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

%d bloggers like this: