I'm implemting TableCellRenderers using the Decorator design-pattern.
All works nice and well as long as all I need is to decorate the returned component from the decorated renderer in such manner that can be performed inside the scope of getTableCellRendererComponent(..).
But how can I decorate the returned component for such cases which need the Graphics object in the paint process? In particular - inside his paintComponent(Graphics g) method?
For example, when I want to draw a certain line where a simple setBorder(..) will not be suffice:
import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.DefaultTableCellRenderer;
public class MyTableCellRendererDecorator extends DefaultTableCellRenderer {
private TableCellRenderer decoratedRenderer;
private Component decoratedComponent;
public MyTableCellRendererDecorator(TableCellRenderer decoratedRenderer) {
super();
this.decoratedRenderer = decoratedRenderer;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
this.decoratedComponent = decoratedRenderer.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
//an example for a decoration which works fine
decoratedComponent.setBackground(Color.red);
return decoratedComponent;
}
/**
* This code will NOT be executed, because the paint will be called on the returned component
* from getTableCellRendererComponent() and NOT on this JLabel in which this renderer subclasses.
*/
@Override
public void paintComponent(Graphics g) {
decoratedComponent.paint(g);
//an example for a needed decoration in paintComponent()
Rectangle bounds = g.getClipBounds();
g.setColor(Color.BLUE);
g.drawLine(0, 0, bounds.width, bounds.height);
}
}
I had 2 different solutions in mind:
1. Introduce an interface called DecoratedTableCellRenderer:
import javax.swing.table.TableCellRenderer;
public interface DecoratedTableCellRenderer extends TableCellRenderer {
public void setPostPaintComponentRunnable(Runnable postPaintComponentRunnable);
}
So now MyTableCellRendererDecorator will receive a DecoratedTableCellRenderer in his constructor instead of a simple TableCellRenderer, and the responsability for decorating inside paintComponent moves to the decorated class. If we assume a renderer is a JComponent which paints itself, this can be done by overriding paintComponent(..) and applying postPaintComponentRunnable.run() after his own paint code.
But, what if I want to support such decoration renderers which will apply on any TableCellRenderer in which I may not be able to modify?
2. Using java's reflection and a dynamic proxy to instantiate a new ComponentUI delegate to decoratedComponent, which will perform each method as its original ComponentUI object, only with a decorated version of paint(Graphics g, JComponent c).
This will keep the decoration responsibilty in the decorating class, but dynamic proxies are always somewhat hard to read and maintain in my perspective, I would be very happy if I will find a more elegant idea.