【问题标题】:Swing overriding object's paintComponentSwing 覆盖对象的paintComponent
【发布时间】:2012-07-28 08:44:55
【问题描述】:

如果我有一个无法修改的JPanel 对象,有没有办法在不使用注入的情况下修改它的paintComponent 方法?

我想到的一种方法是获取JPanelGraphics 对象,将其传递给paintComponent(),对这个Graphics 对象执行操作,最后在我的自定义JPanel 中绘制它。问题在于,每次调用原始 JPanelpaintComponent() 时,我都需要能够做到这一点。

我不需要替换paintComponent()中的内容,我只需要添加它。

例如:

JFrame frame = null;
for (Frame f : JFrame.getFrames()) {
  if (((JFrame) f).getTitle().equals("Title")) {
    JPanel panel = null;
    // ... Cycle through all components and get the one that's a JPanel

    // I want to use ColorConvertOp to make panel greyscale
  }
}

【问题讨论】:

  • 我的意思是不用注入来修改paintComponent
  • 表示不这样做new JPanel(){paintComponent(Graphics g){...}};
  • 所以澄清一下:您可以访问JPanels 实例,您只是不能修改该实例?
  • 请详细说明这个注入的事情..
  • 我明白了,为什么不注入painComponent

标签: java swing paintcomponent


【解决方案1】:

一种方法是使用Decorator Pattern 来包装现有的类。然后,您的装饰器可以实现 paintComponent 以首先委托给原始组件,然后在其上绘制。对于这种方法,您需要实际控制组件的创建,或者您需要在创建组件层次结构后替换它们(使用父容器的 getComponents() 查找要更改的组件)。

【讨论】:

  • @LanguagesNamedAfterCofee JPanel panel = new JPanel(new BorderLayout()) { ... overrides...}; panel.add(instanceYouCantModify);
  • @LanguagesNamedAfterCofee 只有当它是您的问题的解决方案时,您才应该接受答案,而不是一遍又一遍地切换接受的答案。您不必立即接受答案,您可以等待几天再做出决定。不太可能有人会就“已解决”的问题发布另一个答案。
【解决方案2】:

我认为一种可能性是使用GlassPane 并将其准确定位在您的JPanel 上(如果面板更改其位置,则可以使用侦听器让它跟随面板)。然后你可以简单地在玻璃窗格中绘制你的东西,它就会被覆盖。

当然,这不是很优雅...但是我看不出有任何可能在不注入的情况下更改已经存在的实例的paintComponents 行为。 (证明我错了,这个世界的 Java 极客!:P)

【讨论】:

  • 谢谢,我会调查的。我特别想使用 ColorConvertOp 使其成为灰度。
  • @LanguagesNamedAfterCofee 您可以查看this link 以获取有关如何使用GlassPane 的更多信息
【解决方案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,以查看它如何正常呈现。

【讨论】:

    【解决方案4】:

    如果您有能力修改您的类的构造,您可以扩展该类,然后在您的扩展类中调用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中。这可能会使一些担保、许可证无效并给您带来其他麻烦……但至少它是可维护的。

    【讨论】:

    • 谢谢,但就像我在上一个答案中所说的那样,我得到了这个 JPanel 的一个实例,但我无法创建一个新实例。这就是我考虑注射的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-12
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    • 2014-09-21
    相关资源
    最近更新 更多