如何使用Graphics相关指令修饰TableCellRenderer?

时间:2014-04-26 00:59:13

标签: java swing user-interface jtable rendering

我使用Decorator设计模式实现TableCellRenderer。 所有工作都很好,只要我需要的是从装饰渲染器中以可以在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);
    }
}

我有两种不同的解决方案:
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) 这将使装饰课程中的装饰责任保持不变,但在我看来,动态代理总是难以阅读和维护,如果我能找到更优雅的想法,我会非常高兴。

1 个答案:

答案 0 :(得分:0)

事实证明,您提供的原始示例代码接近正确,因为事实上,返回的组件是public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { //... return this; } 。也就是说,paint(Graphics gfx)返回它被调用的DefaultTableCellRenderer,因此在绘制组件期间将调用DefaultTableCellRenderer子类中的任何重写方法。

这里是DefaultTableCellRenderer的代码,显示了我正在谈论的内容:

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; } ,您将能够在单元格中绘制任何内容。

因此,您的paint应如下所示:

paintComponent

使用DefaultTableCellRenderer子类中的/** * 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); } 方法代替hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security PAGE_READWRITE, // read/write access 0, // maximum object size (high-order DWORD) BUF_SIZE, // maximum object size (low-order DWORD) szName); // name of mapping object ///.... // copy data to hMapFile ///.... ////... // create an instance of Word Application ///... /// now call open function and send hMapFile instead of a real file VARIANTARG varg; varg.vt = VT_BYREF; //varg.vt = BSTR; //varg.bstrVal = BSTR(L"F:\\sample2.docx"); varg.byref = hMapFile; DISPPARAMS dpOpen = { &varg, NULL, 1, 0 }; DISPID dispOpenID; LPOLESTR szOpenDoc = L"Open"; UINT err = 9; hr = m_pDocuments->GetIDsOfNames(IID_NULL, &szOpenDoc, 1, LOCALE_SYSTEM_DEFAULT, &dispOpenID); hr = m_pDocuments->Invoke(dispOpenID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dpOpen, &varRetVal, &excepInfo, &err); ,如下所示:

class