How do I correctly use custom renderers to paint specific cells in a JTable?

This is not an answer (*), just too long for a comment on both answers: both are correct in that the else block is the important thingy to ensure that the default color is used for cell that are not supposed to be highlighted. They err slightly in how to reach that, both to the same overall effect: they miss any special coloring, like f.i. due to selection, focus, editable, dnd …

They reach that “miss” by different means with slightly different effects

setBackground(Color.WHITE);

set’s a fixed color which may or may not be the default “normal” table background

setBackground(null);

set’s no color which leads to showing the “normal” background color – due to internal tricksery of the DefaultTableCellRenderer isOpaque implementation 🙂

The basic reason for the problem (also known the infamous color memory, TM) is an unusually bad implementation of the default renderer which leaves it essentially un-extendable:

 /**
 * Overrides <code>JComponent.setBackground</code> to assign
 * the unselected-background color to the specified color. 
 *
 * JW: The side-effect is documented and looks innocent enough :-) 
 */
public void setBackground(Color c) {
    super.setBackground(c); 
    unselectedBackground = c; 
}

// using that side-effect when configuring the colors in getTableCellRendererComp
// is what leads to the horrendeous problems
// in the following lines of the else (not selected, that is normal background color)
 Color background = unselectedBackground != null
           ? unselectedBackground : table.getBackground();
 super.setBackground(background);

Seeing that, the way out (other than using SwingX and its flexible, clean, powerful, consistent .. 🙂 renderer support is @Hovercraft’s but inverse: first do the custom coloring (or null if none intended) then call super:

  @Override
  public Component getTableCellRendererComponent(JTable table,
        Object value, boolean isSelected, boolean hasFocus, int row,
        int column) {
      if (myHighlightCondition) {
          setBackground(Color.RED);
      } else {
          setBackground(null);
      }
     super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
           row, column);
     return this;
  }

(*) After all, this comment led to an answer, forgot that it’s fixable on the custom renderer level 🙂

BTW: Catching the “first” call to the renderer is highly brittle, there is no guaratee on which cell that will happen, might well be the last row of the last column.

Leave a Comment