Core Java Books

Wednesday 16 March 2011

Java Tables: Simple Column to Row Highlighting

In this post I show a simple solution for highlighting table rows based on the value in a particular column on the row.





(Java 1.6 required!)

Firstly I make use of SwingX libraries which provide highlighting functionality. I replace the normal JTable with a JXTable and then add a Highlighter to the table.

The highlighter (code below) is given a column name and two maps for background and foreground colors. The map is keyed on a String with color values. The highlighter takes the value of the specified column on each row and that is used to get the colors required for highlighting



package com.webbyit.swing;

import java.awt.Color;
import java.awt.Component;
import java.util.Map;
import org.jdesktop.swingx.JXLabel;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.painter.Painter;
import static org.jdesktop.swingx.color.ColorUtil.blend;

/**
 *
 @author webbyit
 */
public class ColumnToRowHighlighter extends ColorBlendHighlighter {

    protected Map<String, Color> foregrounds;
    protected Map<String, Color> backgrounds;
    protected String columnName;

    public ColumnToRowHighlighter(String columnName, HighlightPredicate predicate) {
        this(columnName, predicate, null, null);
    }

    public ColumnToRowHighlighter(String columnName, HighlightPredicate predicate, Map<String, Color> backgrounds,
                                  Map<String, Color> foregrounds) {
        super(predicate);
        this.backgrounds = backgrounds;
        this.foregrounds = foregrounds;
        this.columnName = columnName;
    }

    public void setForegrounds(Map<String, Color> foregrounds) {
        this.foregrounds = foregrounds;
    }

    public void setBackgrounds(Map<String, Color> backgrounds) {
        this.backgrounds = backgrounds;
    }

    @Override
    protected void applyBackground(Component renderer, ComponentAdapter adapter) {
        if (backgrounds != null) {
            Color color = null;
            if (adapter.isSelected()) {
                color = getBackground();
            else {
                int columnIndex = adapter.getColumnIndex(columnName);
                String str = adapter.getFilteredStringAt(adapter.row, columnIndex);
                color = backgrounds.get(str);
            }
            if (color != null) {
                if (renderer instanceof JXLabel) {
                    // might have a background painter
                    Painter painter = ((JXLabelrenderer).getBackgroundPainter();
                    renderer.setBackground(blend(renderer.getBackground(), color));
                else {
                    renderer.setBackground(blend(renderer.getBackground(), color));
                }
            }
        }
    }

    @Override
    protected void applyForeground(Component renderer, ComponentAdapter adapter) {
        if (foregrounds != null) {
            Color color = null;
            if (adapter.isSelected()) {
                color = getSelectedForeground();
            else {
                int columnIndex = adapter.getColumnIndex(columnName);
                String str = adapter.getFilteredStringAt(adapter.row, columnIndex);
                color = foregrounds.get(str);
            }
            if (color != null) {
                renderer.setForeground(blend(renderer.getForeground(), color));
            }
        }
    }
}

To make use of the highlighter a JXTable must be used instead of a JTable, to be honest I don't use JTables anymore I always use JXTable. This is how the highlighter in the demo is added:



Map<String, Color> backgrounds = new HashMap<String, Color>();
backgrounds.put("Visa", Color.BLUE);
backgrounds.put("Cash", Color.RED);
backgrounds.put("Cheque", Color.BLACK);
Map<String, Color> foregrounds = new HashMap<String, Color>();
foregrounds.put("Visa", Color.WHITE);
foregrounds.put("Cash", Color.YELLOW);
foregrounds.put("Cheque", Color.ORANGE);

// Use default predicate
ColumnToRowHighlighter highlighter = new ColumnToRowHighlighter("Payment Method", HighlightPredicate.ALWAYS,
      backgrounds, foregrounds);
table.addHighlighter(highlighter);

Notice that the highlighter allows a predicate to be set. This is another feature which provides the capability to filter when a highlight is used or not. In the example for instance I could have provided a predicate which defines the highlights is only used for balances outstanding over 50. It's worth searching around for article elsewhere on SwingX and highlighting as its very flexible and very easy to use.

Enjoy.

1 comment: