Java Tips Weblog

  • Blog Stats

    • 2,571,880 hits
  • Categories

  • Archives

Icon Table Cell Renderer

Posted by Darryl Burke on December 18, 2008

The suplied default renderer for JTable columns of class Icon and ImageIcon, JTable.IconRenderer, is known to give rise to a ClassCastException when attempting to render an Icon whose implementation of paintIcon(…) requires a cast of its Component parameter to a specific subclass of Component. Several icons obtained from standard JDK classes trigger this ClassCastException.

IconTableCellRenderer addresses this issue by attempting to paint the Icon in 3 different ways before falling back on a default icon which can be customized via a parameter to the constructor.

  • First, an attempt is made to paint the Icon to the Graphics context of a BufferedImage with a reference to the renderer itself as the Component parameter.
  • In case of a ClassCastException, the desired class is identified by parsing the exception’s message. An attempt is made to instantiate a Component of the desired class and use it as a valid reference.
  • In case an InstantiationException is thrown because the desired class is abstract, a final attempt is made to draw the icon with a concretized AbstractButton furnished with a DefaultButtonModel as the Component parameter.
  • All else failing, the icon is rendered as a crossed rectangle of the same size as the original icon, or the default icon if supplied as a parameter to the constructor.

Using IconTableCellRenderer is no different from using any custom renderer.

table.setDefaultRenderer(Icon.class, new IconTableCellRenderer());

This is a view of some of the default Metal L&F icons as rendered by IconTableCellRenderer

icontablecellrenderer

IconTableCellRenderer extends DefaultTableCellRenderer.

Get The Code

IconTableCellRenderer.java

See Also:

The Java™ Tutorials: How to Use Tables: Using Custom Renderers

Related Reading

Java API: javax.swing.table.DefaultTableCellRenderer

7 Responses to “Icon Table Cell Renderer”

  1. Kleopatra said

    Darryl,

    nasty trick :-) A couple of comments and a question:

    – in your example, how did you force the actual loading of the icons?
    – better not resize the row in the renderer: general rule is to regard the target component (here the table) as strictly read-only, no state changes allowed in a callback method
    – better not create a new AbstractButton in each call, should be enough to keep one around for re-use (but could be missing something here)

    CU
    Jeanette

  2. Darryl Burke said

    Thank you for the insights, Jeanette.

    The icons were obtained by scanning the UIDefaults for instances of Icon.

    @SuppressWarnings(value = “unchecked”)
    private TableModel getIconTableModel() {
       UIDefaults defaults = UIManager.getDefaults();
       Enumeration keys = defaults.keys();
       Vector<Vector> data = new Vector<Vector>();
       while (keys.hasMoreElements()) {
          Object key = keys.nextElement();
          Object value = defaults.get(key);
          if (value instanceof Icon) {
             Vector rowData = new Vector();
             rowData.add(key);
             rowData.add(value);
             data.add(rowData);
          }
       }
       return new DefaultTableModel(data, columnNames);
    }

    I understand your second point, but cannot see any alternative way to resize the table rows to accommodate each icon. A suggestion would be more than welcome.

    And I’ve made the change to use one static instance of a concretized AbstractButton, the updated code will be available shortly.

    Regards, Darryl

  3. Kleopatra said

    Hi Darryl,

    thanks for your answer – what I missed with the properties is that I built the TableModel from the Entries, thus not forcing the LazyValues to be created. Haha … there’s always something left to learn/remember :-)

    The only safe place to do row (and/or column resizing if wanted) is external to the renderer. Some handler walking the model and adjust the heights as appropriate.

    The reason I looked into this is that I wanted to see how SwingX would handle it: we don’t really think in terms of renderer but in terms of “content” and “visual decoration”. Typically, an Icon is considered part of the content with a custom converter: then the converter does all the nasty tricks around the CCEs (actually delegating the real work to a SafeIcon and keeping a cache of those wrappers). The big advantage is that we can re-use the converters, kind of small coin which is pluggable to any kind of renderer.

    https://jdnc-incubator.dev.java.net/source/browse/jdnc-incubator/src/kleopatra/java/org/jdesktop/swingx/renderer/UIPropertiesViewer.java?rev=1.2&view=markup

    Shameless plug – I know – hope you don’t mind too much

    Thanks again
    Jeanette

  4. Darryl Burke said

    Jeanette, thank you again for the professional point of view and the link to the polished version. I still have a lot to learn about breaking up methods into smaller, more manageable units.

    Have you noticed the first-ever post on this blog?
    UIManager Defaults

    And, er, the plug is fine, seeing as how there’s a reverse plug for this blog in the linked page ;)

    Darryl

  5. Rob Camick said

    Jeanette,

    I just used your SafeIcon class to wrap all the Icons found in the UIManagerDefaults class mentioned above. It was a simple one line if statement added to the existing class. I know this is not the way you would use it in SwingX but it works great for what I need.

    So, is it ok to use the class stand alone? If so, how should I credit you in the code? Just include the link provided above?

    Thanks,

    Rob

  6. Kleopatra said

    Hi Darryl, Rob,

    glad you liked it :-)

    Yeah, sure – that’s completely free code, free as in take-it-and-suffer-the-consequences Adding my name and/or a link to the code is good enough for me.

    no, didn’t yet reach the start of this series – just browsing around a bit, good work!. Will do.

    Keep up your good work!
    Jeanette

  7. Rob Camick said

    free as in take-it-and-suffer-the-consequences

    Thats the way I offer all of my code, thanks.

Leave a comment