简体   繁体   English

paintComponent()中绘制的图形立即丢失

[英]Figure drawn in paintComponent() is immediately lost

I am a newcomer to Java, Swing, and GUI programming, so I am probably missing a number of central points about building a GUI with Swing and the thread model behind. 我是Java,Swing和GUI编程的新手,所以我可能遗漏了许多关于使用Swing构建GUI以及后面的线程模型的中心观点。 The exercise I am trying consist in a little application for creating, moving and resizing figures on a canvas. 我正在尝试的练习包括一个用于在画布上创建,移动和调整图形大小的应用程序。 Moreover, I am trying to keep the View as behaviourless as possible, with a Presenter object being responsible for injecting the desired behaviour. 此外,我试图保持View尽可能无行为,Presenter对象负责注入所需的行为。 In other words, I do not want the View to know about figures or how they must be drawn, it simply offers a setUpdater() method for the Presenter to provide an object that knows what must be drawn in order to represent the state of a Model. 换句话说,我不希望View了解数字或必须如何绘制它们,它只是为Presenter提供了一个setUpdater()方法来提供一个对象,该对象知道必须绘制什么才能表示一个状态。模型。

But I have found a problem: under some circumstances, figures are lost. 但我发现了一个问题:在某些情况下,数字会丢失。 For instance, if I iconify and then deiconify the application window. 例如,如果我图标化然后取消图标化应用程序窗口。 I thought the paintComponent() of my canvas component was not called, but a breakpoint showed me the problem was different: it was called and the figures were painted, but then dissapeared. 我认为我的canvas组件的paintComponent()没有被调用,但断点显示我的问题不同:它被调用并且数字被绘制,但随后消失了。

I have tried to simplify my code to show the problem without buttons, sliders or even a Model. 我试图简化我的代码,以显示没有按钮,滑块甚至模型的问题。 However, I keep separate classes for the View and the Presenter as this separation is important for my purposes. 但是,我为View和Presenter保留了单独的类,因为这种分离对我的目的很重要。

In the machine where I am testing the simplified example, the figure that is drawn when paintComponent is called (always the same circle) dissapears not only after deiconification, but every time it is painted. 在我测试简化示例的机器中,调用paintComponent时绘制的图形(始终是相同的圆)不仅在去除图像后消失,而且每次绘制时都消失。

Please, help me understand what is happening... and how to solve it. 请帮助我了解正在发生的事情......以及如何解决它。

TYIA. TYIA。

PS1: The simplified code follows: PS1:简化代码如下:

import java.awt.*;
import javax.swing.*;

interface ViewUpdater {
    void updateCanvas(Graphics2D g2d);
}

class View {
    private JFrame windowFrame;
    private JPanel canvasPanel;
    private ViewUpdater updater;
    public static final Color CANVAS_COLOR = Color.white;
    public static final int CANVAS_SIDE = 500;

    public View() {
        windowFrame = new JFrame();
        windowFrame.
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvasPanel = new JCanvas();
        canvasPanel.setBackground(CANVAS_COLOR);
        canvasPanel.
            setPreferredSize(new Dimension(CANVAS_SIDE,
                                           CANVAS_SIDE));
        windowFrame.getContentPane().add(canvasPanel);
        windowFrame.pack();
        windowFrame.setResizable(false);
    }

    public void setVisible() {
        windowFrame.setVisible(true);
    }

    public void setUpdater(ViewUpdater updater) {
        this.updater = updater;
    }

    public void updateView() {
        System.out.println("BEGIN updateView");
        Graphics2D g2d =(Graphics2D) canvasPanel.getGraphics();
        g2d.setColor(CANVAS_COLOR);
        g2d.fillRect(0, 0, CANVAS_SIDE, CANVAS_SIDE);
        if (updater != null) {
            System.out.println("GOING TO updateCanvas");
            updater.updateCanvas(g2d);
        }
        System.out.println("END updateView");
   }

    private class JCanvas extends JPanel {

        private static final long serialVersionUID =
                                    7953366724224116650L;

        @Override
        protected void paintComponent(Graphics g) {
            System.out.println("BEGIN paintComponent");
            super.paintComponent(g);
            updateView();
            System.out.println("END paintComponent");
        }
    }
}

class Presenter {
    private View view;
    private static final Color FIGURE_COLOR = Color.black;

    public Presenter(View view) {
        this.view = view;
        this.view.setUpdater(new ProjectViewUpdater());
        this.view.setVisible();
    }

    private class ProjectViewUpdater
        implements ViewUpdater {
        @Override
        public void updateCanvas(Graphics2D g2d) {
            g2d.setColor(FIGURE_COLOR);
            g2d.drawOval(100, 100, 300, 300);
            // The circle immediately disappears!
        }
    }
}

public class Main {
    public static void main(String[] args) {
        new Presenter(new View());
    }
}

PS2: I am reading http://www.javaworld.com/javaworld/jw-08-2007/jw-08-swingthreading.html in order to understand the thread model involved in using Swing, but I still have not done anything special for controlling threads in my code. PS2:我正在阅读http://www.javaworld.com/javaworld/jw-08-2007/jw-08-swingthreading.html以了解使用Swing所涉及的线程模型,但我仍然没有做任何特别的事情用于控制代码中的线程。

PS3: I have not found the answer to my problem googling, the most similar issue is maybe the one unanswered in http://www.eclipse.org/forums/index.php/t/139776/ . PS3:我还没有找到我的问题谷歌搜索的答案,最相似的问题可能是http://www.eclipse.org/forums/index.php/t/139776/中没有答案的问题。

Your problem is that you're getting your Graphics object by calling getGraphics() on JPanel, and any Graphics object thus obtained will not be long-lasting, so that anything drawn with it will likewise disappear on the next repaint. 你的问题是你通过在JPanel上调用getGraphics()得到你的Graphics对象,并且这样获得的任何Graphics对象都不会持久,所以用它绘制的任何东西同样会在下一次重绘时消失。

The solution: don't do this. 解决方案:不要这样做。 Either

  • draw with the Graphics object given to the paintComponent method by the JVM or 使用JVM或者给予paintComponent方法的Graphics对象进行绘制
  • call getGraphics() or createGraphics() on a BufferedImage to get its Graphics or Graphics2D object, draw with this, dispose of it, and then draw the BufferedImage in the JComponent or JPanel's paintComponent(...) method again using the Graphics object passed in by the JVM. 在BufferedImage上调用getGraphics()createGraphics()以获取其Graphics或Graphics2D对象,使用它进行绘制,处理它,然后使用传递的Graphics对象再次在JComponent或JPanel的paintComponent(...)方法中绘制BufferedImage在JVM中。

For your situation, I think your best off using a BufferedImage, or point 2 above. 对于您的情况,我认为您最好使用BufferedImage,或上面的第2点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM