如何使用图形相关说明装饰 TableCellRenderer



我正在使用装饰器设计模式暗示TableCellRenderer s。只要我所需要的只是以可以在getTableCellRendererComponent(..)范围内执行的方式装饰装饰渲染器返回的组件,一切都很好。
但是,对于在油漆过程中需要Graphics对象的情况,我该如何装饰返回的组件?特别是 - 在他的paintComponent(Graphics g)方法中?
例如,当我想画一条简单的setBorder(..)是不够的线时:

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);
    }
}

我想到了 2 种不同的解决方案:
1. 引入一个名为 DecoratedTableCellRenderer 的接口:

import javax.swing.table.TableCellRenderer;
public interface DecoratedTableCellRenderer extends TableCellRenderer {
    public void setPostPaintComponentRunnable(Runnable postPaintComponentRunnable);
}

所以现在MyTableCellRendererDecorator将在他的构造函数中获得一个DecoratedTableCellRenderer而不是一个简单的TableCellRenderer,并且内部装饰的责任paintComponent转移到装饰类。如果我们假设渲染器是一个绘制自己的JComponent,这可以通过覆盖paintComponent(..)并在他自己的绘制代码之后应用postPaintComponentRunnable.run()来完成。
但是,如果我想支持此类装饰渲染器,这些渲染器将适用于我可能无法修改的任何TableCellRenderer,该怎么办?
2.使用java的反射和动态代理实例化一个新的ComponentUI委托给decoratedComponent,它将每个方法作为其原始ComponentUI对象执行,只有paint(Graphics g, JComponent c)的装饰版本。
这将使装饰类保持装饰责任,但动态代理在我的角度总是有些难以阅读和维护,如果我能找到一个更优雅的想法,我会很高兴。

事实证明,您给出的原始示例代码接近正确,因为实际上返回的组件是this 。也就是说,getTableCellRendererComponent返回调用它的 DefaultTableCellRenderer,因此在绘制组件期间将调用 DefaultTableCellRenderer 子类中的任何重写方法。

以下是 DefaultTableCellRenderer 的代码,显示了我在说什么:

public Component getTableCellRendererComponent(JTable table, Object value,
                      boolean isSelected, boolean hasFocus, int row, int column) {
    //...
    return this;
}

因此,如果您重写 paint(Graphics gfx) 方法并调用超类getTableCellRendererComponent您将能够在单元格中绘制您想要的任何内容。

所以你的getTableCellRendererComponent应该是这样的:

@Override
public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
    JLabel component = super.getTableCellRendererComponent(table, value,
        isSelected, hasFocus, row, column);
    //an example for a decoration which works fine
    component.setBackground(Color.red);
    return component;
}

并在 DefaultTableCellRenderer 的子类中使用 paint 方法,而不是像这样paintComponent

/**
 * This code WILL be executed.
 */
@Override
public void paint(Graphics g) {
    super.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);
}

相关内容

  • 没有找到相关文章

最新更新