I'm implemting TableCellRenderer
s 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.