Cell painters

NatTable user cell painters to paint each cell. These painters implement the ICellPainter interface. The default painter is the TextPainter. As the name suggests, it paints its content as text and reads the relevant style attributes from the
config registry. It takes into account font, colors and alignment when it paints.

Useful painters:

Fortunately NatTable has several cell painters already implemented for you.

CellPainterDecorator

Paints using a base painter and then decorates it using a second painter. For example, in the following snippet

    new CellPainterDecorator(new TextPainter(), CellEdgeEnum.RIGHT, new ImagePainter(myImage))

    Snippet from the ButtonCellExample

Will paint something like this

CellPainterWrapper

Paints the interior of the cell using a given painter. It then goes on put some decorations around/behind the cell.

Implementing classes are:

  • LineBorderDecorator - paints a border around the cell
  • PaddingDecorator - puts a padding around the cell contents
  • BeveledBorderDecorator - Gives the cell a button like look by drawing a beveled border
  • ImagePainter - Paints its background using the given image
  • BackgroundImagePainter - Paints the background of the cell it wraps using the given image

You can mix and match the above painters to create your own variations without needing to write much code.

For example the following snippet

        Image bgImage = new Image(Display.getDefault(), getClass().getResourceAsStream("column_header_bg.png"));
        TextPainter txtPainter = new TextPainter(false, false);
        ICellPainter bgImagePainter = new BackgroundImagePainter(txtPainter, bgImage, GUIHelper.getColor(192, 192, 192));

        Snippet from the StyledGridExample (StyledColumnHeaderConfiguration)

will paint something like this

Using a custom painter

In order to use a custom cell painter you need to:

  1. Create a custom implementation of the ICellPainter. Normally you would be able to reuse one of the existing ones.
  2. Apply a custom label to the cells which should use your painter.
  3. Register your painter in the config registry against the cell labels you applied in step 2. Custom painters are registered as CellConfigAttributes.CELL_PAINTER attributes.

We will go through the PercentageBarExample so that you can see it in action. In the example code we setup the BODY region to use the PercentageBarCellPainter. This is done by registering the new painter as shown the following snippet

            configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new PercentageBarCellPainter(),
                    DisplayMode.NORMAL, GridRegion.BODY.toString());

The painter itself looks like this

     public PercentageBarCellPainter() {
         super(new PaddingDecorator(new LineBorderDecorator(new PercentageBarDecorator(new TextPainter()), new BorderStyle())));
     }

The diagram below illustrates the various parts of the cell these painters paint

Comments

Painting CellPainters next to each other

The example using the CellPainterDecorator has the problem that the icon may hide the text. The following CellPainter solves that problem (I release it under the Eclipse Public License):


package org.acoveo.nattable.views;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import net.sourceforge.nattable.config.IConfigRegistry;
import net.sourceforge.nattable.layer.cell.LayerCell;
import net.sourceforge.nattable.painter.cell.ICellPainter;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;

public class HorizontalPainterWrapper implements ICellPainter {
List painters = new LinkedList();

public HorizontalPainterWrapper(Collection cellPainters) {
painters.addAll(cellPainters);
}

public HorizontalPainterWrapper(ICellPainter[] iCellPainters) {
painters.addAll(Arrays.asList(iCellPainters));
}

public int getPreferredWidth(LayerCell cell, GC gc, IConfigRegistry configRegistry) {
int width = 0;
for(ICellPainter painter : painters) {
width += painter.getPreferredWidth(cell, gc, configRegistry);
}
return width;
}

public int getPreferredHeight(LayerCell cell, GC gc, IConfigRegistry configRegistry) {
int height = 0;
for(ICellPainter painter : painters) {
height += painter.getPreferredHeight(cell, gc, configRegistry);
}
return height;
}

public void paintCell(LayerCell cell, GC gc, Rectangle bounds, IConfigRegistry configRegistry) {
Rectangle remainingBounds = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
for(Iterator iter = painters.iterator(); iter.hasNext();) {
ICellPainter painter = iter.next();
int width = painter.getPreferredWidth(cell, gc, configRegistry);
Rectangle interiorBounds =
new Rectangle(
remainingBounds.x,
remainingBounds.y,
iter.hasNext() ? width : remainingBounds.width,
remainingBounds.height
);
painter.paintCell(cell, gc, interiorBounds, configRegistry);
remainingBounds.x += width;
remainingBounds.width -= width;
if(bounds.x + bounds.width < remainingBounds.x) {
break;
}
}
}
}