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