Java 在paintComponent()中绘制的图形立即丢失
我是Java、Swing和GUI编程的新手,因此我可能错过了使用Swing及其背后的线程模型构建GUI的一些要点。我正在尝试的练习包括在画布上创建、移动和调整图形大小的小应用程序。此外,我试图保持视图尽可能无行为,Presenter对象负责注入所需的行为。换句话说,我不希望视图知道图形或图形必须如何绘制,它只是为演示者提供了一个setUpdater()方法,以提供一个对象,该对象知道为了表示模型的状态必须绘制什么 但我发现了一个问题:在某些情况下,数据丢失了。例如,如果我将应用程序窗口图标化,然后取消图标化。我以为画布组件的paintComponent()没有被调用,但断点告诉我问题不同:它被调用,图形被绘制,但随后消失 我试图简化我的代码,在没有按钮、滑块甚至模型的情况下显示问题。但是,我为视图和演示者保留单独的类,因为这种分离对于我的目的很重要 在我测试简化示例的机器中,调用paintComponent时绘制的图形(始终是同一个圆)不仅在去锥化后消失,而且在每次绘制时消失 请帮我了解发生了什么。。。以及如何解决这个问题 蒂娅 PS1:简化代码如下:Java 在paintComponent()中绘制的图形立即丢失,java,swing,paintcomponent,Java,Swing,Paintcomponent,我是Java、Swing和GUI编程的新手,因此我可能错过了使用Swing及其背后的线程模型构建GUI的一些要点。我正在尝试的练习包括在画布上创建、移动和调整图形大小的小应用程序。此外,我试图保持视图尽可能无行为,Presenter对象负责注入所需的行为。换句话说,我不希望视图知道图形或图形必须如何绘制,它只是为演示者提供了一个setUpdater()方法,以提供一个对象,该对象知道为了表示模型的状态必须绘制什么 但我发现了一个问题:在某些情况下,数据丢失了。例如,如果我将应用程序窗口图标化,然
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:我阅读本书是为了理解使用Swing所涉及的线程模型,但我仍然没有在代码中做任何控制线程的特殊工作
PS3:我在谷歌搜索时没有找到问题的答案,最类似的问题可能是中没有回答的问题。您的问题是,您通过在JPanel上调用
getGraphics()
来获取图形对象,这样获得的任何图形对象都不会持久,这样,用它绘制的任何东西在下次重新绘制时也会消失
解决办法:不要这样做。或者
- 使用JVM或指定给paintComponent方法的图形对象绘制
- 在BuffereImage上调用
或getGraphics()
,以获取其图形或Graphics2D对象,使用此对象绘制,处理它,然后使用JVM传入的图形对象再次在JComponent或JPanel的createGraphics()
方法中绘制BuffereImagepaintComponent(…)
对于您的情况,我认为您最好使用BuffereImage或上面的第2点。我看这里没有什么问题,事实上,我运行了这个程序,它工作得非常好。你确定你看到了这个简化版本的问题吗?顺便说一句,这个关联的问题与你的问题完全不同——它与SWT内部嵌入的Swing有关,SWT是一个完全不相关的窗口工具包,它本身的一系列问题在技术上也很重要。@ernest friedman hill:你真的看到Deiconicion之后的圆圈了吗?我管理Eclipse中的代码,并“作为Java应用程序”运行它,这会有什么不同吗?。在我的Windows Vista中,圆圈最初没有显示(至少在相当长的一段时间内没有显示),在将窗口从部分外部移到桌面内部时出现,并且仅在去锥化后丢失。然而,在我的Ubuntu中,圆圈从未正确显示。我在MacOSX上运行这个,圆圈从未消失。我认为@hovercraftfullofels可能是对的,解决方案是将JCanvas.paintComponent()作为
g
的参数传递到updateView()
,然后它应该使用该参数,而不是调用getGraphics()。@ernest friedman hill:感谢您提供有关Mac OS X下行为的信息。非常感谢。我已经成功尝试了您提出的第一种方法:图形g现在从paintComponent()传递到updateView(),在这里它代替了canvasPanel.getGraphics()。对我来说,这就像魔术。是时候搜索有关getGraphics()和BuffereImage:-)的信息了,任何指针都可以。顺便说一句,你为什么推荐第二个选项?@federico.prat:如果某些内容是静态的,BufferedImage
可以呈现一次,然后通过drawImage()
重复复制+1.