如果我有一个我无法修改的JPanel
对象,有没有办法可以在不使用注入的情况下修改它的paintComponent
方法?
我想到的一种方法是获取JPanel
的{{1}}对象,将其传递给Graphics
,对此paintComponent()
对象执行操作,最后绘制在我的自定义Graphics
中。这个问题是我每次调用原始JPanel
的{{1}}时都需要这样做。
我不需要替换paintComponent()中的内容,我只需要添加它。
例如:
JPanel
答案 0 :(得分:6)
一种方法是使用Decorator Pattern来包装现有的类。然后,您的装饰器可以实现paintComponent以首先委托给原始组件,然后在其上面绘制。对于这种方法,您需要实际控制组件的创建,或者在创建组件层次结构后需要替换它们(使用父容器的getComponents()来查找要更改的组件)。
答案 1 :(得分:5)
我认为一种可能性是使用GlassPane
并将其准确定位在JPanel
上(如果面板更改其位置,可以让它使用侦听器跟随面板)。然后你可以简单地在玻璃板上画出你的东西,然后叠加。
当然这不是很优雅......但是我没有看到任何可能在没有注入的情况下更改已存在实例的paintComponents
行为的可能性。 (证明我错了,这个世界的Java极客!:P)
答案 2 :(得分:3)
我想这将完成@Durandal的回答:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestPanels {
private static final boolean GRAY_SCALE = true;
protected void initUI() {
final JFrame frame = new JFrame(TestPanels.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel unmodifiablePanel = new JPanel(new GridBagLayout());
JLabel label = new JLabel("Some unmodifiable test label");
unmodifiablePanel.add(label);
unmodifiablePanel.setBackground(Color.GREEN);
JPanel wrappingPanel = new JPanel(new BorderLayout()) {
private ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
private BufferedImage image;
@Override
public void paint(Graphics g) {
if (!GRAY_SCALE) {
super.paint(g);
return;
}
BufferedImage bi = getImage();
if (bi != null) {
Graphics big = bi.createGraphics();
super.paint(big);
big.dispose();
bi = op.filter(bi, null);
g.drawImage(bi, 0, 0, null);
}
}
protected BufferedImage getImage() {
if (image == null) {
if (getWidth() > 0 && getHeight() > 0) {
image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
}
} else if (image.getWidth() != getWidth() || image.getHeight() != image.getHeight()) {
image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
}
return image;
}
};
wrappingPanel.add(unmodifiablePanel);
frame.add(wrappingPanel);
frame.setSize(200, 200);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestPanels().initUI();
}
});
}
}
您可以将GRAY_SCALE标志设置为false,以查看它是如何正常渲染的。
答案 3 :(得分:1)
如果您能够修改类的构造,则可以扩展该类,然后在扩展类中调用super.paintComponent(g)
。例如:
public class NewPanel extends OldPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
// Insert additional painting here
}
}
在这种情况下,您需要一个新类才能构建现有类的绘画。
这样做是执行在父类绘画中完成的所有内容,并为您提供更多的选项(这似乎是您正在寻找的内容)。
修改强>
但是......鉴于您无法访问此选项,您的选项会受到更多限制。如果面板使用空布局管理器,则可以添加绘制父级的子jpanel(布局管理器会限制子项可以绘制的区域数量)。这是一个很长的镜头。
您也可以使用反射,但关于您获得的唯一选项(除了字节码注入)。这似乎与字节代码注入一样丑陋 - 这里是对你要做的事情的一个不错的概述:Java reflection: How do I override or generate methods at runtime?
我个人的偏好是反编译该类,按照您想要的方式对其进行修改,重新编译并将其插回到原始jar中。这可能会使一些警察,许可证无效并让你陷入其他麻烦......但至少它是可维护的。