paintComponent多次调用重叠组件

时间:2015-07-07 14:48:51

标签: java swing jpanel paintcomponent

我在父JPanel内有几个JPanel层叠在一起。当我在其中一个上调用repaint()时,所有这些都会重新绘制层数。这增长了二次方!对于3个面板,我看到每个3次重绘,这是9次重绘。有5个面板,有25个重绘。

我发现对于重叠组件,我应该覆盖父项中的isOptimizedDrawingEnabled()并返回false。或者使用JLayeredPane作为父级。我试过了两个,结果是一样的。

造成这种情况的原因是什么?

如何停止多次重新绘制面板?

编辑:SSCCE / MCVE如下:

public class JPanelTest extends JPanel {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new JPanelTest();
            }
        });
    }

    public JPanelTest() {
        super(null);
        setLayout(new OverlayLayout(this));

        JFrame f = new JFrame(getClass().getSimpleName());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(600, 600);

        final Model model = new Model();

        f.getContentPane().add(this);
        this.add(new MyPanel(model));
        this.add(new MyPanel(model));
        this.add(new MyPanel(model));
        this.add(new MyPanel(model));
        this.add(new MyPanel(model));

        f.setLocationRelativeTo(null);
        f.setVisible(true);

        addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent ex) {
                model.setColor(new Color((int)ex.getWhen()));
            }
        });
    }

    @Override
    public boolean isOptimizedDrawingEnabled() {
        return false;
    }
}

// My own containers/listeners/events are larger, so this is shorter for SSCCE/MCVE.
class Model extends PropertyChangeSupport {
    Color color = Color.BLACK;

    public Model() {
        super(Color.BLACK);
    }

    public void setColor(Color color) {
        this.color = color;
        firePropertyChange("color", null /* meh */, color);
    }
}

class MyPanel extends JPanel implements PropertyChangeListener {
    static int  instanceCounter = 0;
    int         repaintCounter  = 0;
    final int   instance;

    private Model model;

    public MyPanel(Model model) {
        super(null);
        instance = ++instanceCounter;
        setOpaque(false);

        this.model = model;
        model.addPropertyChangeListener(this);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(model.color);
        g.drawString("panel " + instance + ", repaint " + ++repaintCounter, 1, instance * 15);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        System.out.println("panel " + instance + ": Value is now " + evt.getNewValue());
        repaint();
    }
}

一些额外的说明: 我注意到,对于每次重复绘制的面板,我必须多次调用repaint()。但是,当所有面板并排(不重叠)时,它们都会重新粉刷一次。

2 个答案:

答案 0 :(得分:2)

  

造成这种情况的原因是什么?

我猜测原因是因为所有面板都是非透明的。

绘制非不透明组件时,RepaintManager必须找到第一个不透明的父组件,然后绘制父组件和所有子组件。这种情况发生了5次,因此您可以进行25次重绘。

在您的简单示例中,您可以更改propertyChanged(...)方法中的代码:

getParent().repaint();

现在将在父容器而不是单个面板上进行5次重绘请求。 RepaintManager会将这些请求合并到一个请求中,然后面板及其5个子项将被绘制一次。

答案 1 :(得分:0)

您已使用相同的Model实例创建了每个MyPanel。然后,每个MyPanel实例都将自己添加为该模型的PrpoertyChangeListenert。因此,任何面板上的任何属性更改都会广播到每个面板,最终会在每个面板上调用repaint()。