有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Swing重写对象的paintComponent

如果我有一个无法修改的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
  }
}

共 (4) 个答案

  1. # 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中。这可能会使一些仓库、许可证作废,并给你带来其他麻烦。。。但至少它是可维护的

  2. # 2 楼答案

    我认为一种可能性是使用^{}并将其精确定位在JPanel上方(如果面板改变了位置,可以使用侦听器让它跟随面板)。然后你可以在玻璃窗格中简单地画出你的东西,然后将其覆盖

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

  3. # 3 楼答案

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

  4. # 4 楼答案

    我想这将完成@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();
                }
            });
        }
    }
    

    可以将灰度标志设置为false,以查看其正常渲染方式