JTable row highlighting and Decorator design pattern

I’ve been looking a moment to find how add row highlighting on JTables. To modify the behaviour of the cell rendering, you’ll have to set a new CellRenderer to JTable for each data types you want to show in the table.

The way I use is to apply the Decorator pattern.

The reason is that  we only want to add row highlighting behaviour to existing cell renderer, and not to recode all the behaviour of cell renderers. This is particularly right for booleans values, which are shown by check boxes in JTable. With this pattern, you won’t have to rewrite the behaviour of the cell renderer.

So here is the code of our new cell renderer. It inherits of DefaultTableRenderer. It will apply a background to a cell depending of :

  • the row is selected : then apply default background for selected rows
  • the row is even or not : apply an alternate background color
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;

/**
 * This is just a basic extension of the DefaultTableCellRender from the current L&F
 */
public class AlternateCellRenderer extends DefaultTableRenderer {

    private TableCellRenderer cellRenderer;

    public AlternateCellRenderer(TableCellRenderer cellRenderer) {
        if (cellRenderer == this || cellRenderer == null) {
            throw new IllegalArgumentException();
        }
        this.cellRenderer = cellRenderer;
    }

    /**
     * Fetch the component which renders the cell ordinarily
     * @param JTable The current JTable the cell is in
     * @param Object The value in the cell
     * @param boolean If the cell is in the selected row
     * @param boolean If the cell is in focus
     * @param int The row number of the cell
     * @param int The column number of the cell
     * @return Component
     */
    public Component getTableCellRendererComponent(JTable tbl, Object v, boolean isSelected, boolean isFocused, int row, int col) {
        Component c = cellRenderer.getTableCellRendererComponent(tbl, v, isSelected, isFocused, row, col);
        if (isSelected) {
            c.setBackground(
                    UIManager.getLookAndFeelDefaults().getColor("Table.selectionBackground"));
        } else if ((row % 2) == 0 && !isSelected) {
            c.setBackground(
                    UIManager.getLookAndFeelDefaults().getColor("ScrollBar.thumb")
                    );
        } else {
            c.setBackground(new Color((float) 1.0, (float) 1.0, (float) 1.0));
        }
        return c;
    }
}

Then all we have to do to use this cell renderer is to get existing cell renderers from the table, apply our decorator on them and set this new renderers to the JTable.

Look at the second one : we keep the behaviour of the cells showing booleans as we apply our new renderer upon the existing one : the check boxes are kept to show booleans values in the JTable.


eTable1.setDefaultRenderer(Object.class, new AlternateCellRenderer(eTable1.getDefaultRenderer(Object.class)));
eTable1.setDefaultRenderer(Boolean.class, new AlternateCellRenderer(eTable1.getDefaultRenderer(Boolean.class)));

CellRenderer Decorator in action

CellRenderer Decorator in action

Advertisements

About this entry