Java 调用repaint()后,paintComponent()绘制的内容将消失
在第一本Java书的开头,我们看到了一些小动画,我试图画一个画对角线的动画。我使用paintComponent()方法在x,y处绘制一个椭圆形(每次循环时都会更新该值)。为什么我会丢失先前绘制的椭圆?根据这本书,我应该在屏幕上得到一个涂片,在那里以前画的椭圆没有丢失。这需要通过在每次调用repaint()时向paintComponent()方法添加一个白色背景来解决,但我没有得到“错误”这是为什么?如何在面板上保留先前绘制的椭圆形?Java 调用repaint()后,paintComponent()绘制的内容将消失,java,swing,jpanel,paintcomponent,Java,Swing,Jpanel,Paintcomponent,在第一本Java书的开头,我们看到了一些小动画,我试图画一个画对角线的动画。我使用paintComponent()方法在x,y处绘制一个椭圆形(每次循环时都会更新该值)。为什么我会丢失先前绘制的椭圆?根据这本书,我应该在屏幕上得到一个涂片,在那里以前画的椭圆没有丢失。这需要通过在每次调用repaint()时向paintComponent()方法添加一个白色背景来解决,但我没有得到“错误”这是为什么?如何在面板上保留先前绘制的椭圆形?使用JDK 13.0.2和Mac OSX Catalina im
使用JDK 13.0.2和Mac OSX Catalina
import javax.swing.*;
import java.awt.*;
public class SimpleAnimation {
int x = 70;
int y = 70;
public static void main(String[] args) {
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
MyDrawPanel drawPanel = new MyDrawPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel);
frame.setSize(300,300);
frame.setVisible(true);
for (int i = 0; i < 130; i++) {
x++;
y++;
drawPanel.repaint();
try {
Thread.sleep(25);
} catch (Exception ex){};
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.orange);
g.fillOval(x,y,50,50);
}
} // close inner class
} // close outer class
import javax.swing.*;
导入java.awt.*;
公共类简化{
int x=70;
int y=70;
公共静态void main(字符串[]args){
SimpleAnimation gui=新建SimpleAnimation();
gui.go();
}
公开作废go(){
JFrame=新JFrame();
MyDrawPanel drawPanel=新建MyDrawPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel);
框架。设置尺寸(300300);
frame.setVisible(true);
对于(int i=0;i<130;i++){
x++;
y++;
drawPanel.repaint();
试一试{
睡眠(25);
}捕获(例外情况除外){};
}
}
类MyDrawPanel扩展了JPanel{
公共组件(图形g){
g、 setColor(颜色为橙色);
g、 椭圆形(x,y,50,50);
}
}//关闭内部类
}//关闭外部类
这就是防止卵子涂片的原因吗
代码应为:
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g); // added
g.setColor(Color.orange);
g.fillOval(x,y,50,50);
}
在进行自定义绘制之前,需要使用super.paintComponent(g)
清除面板的背景
是的,很棒的书。我得到的代码输出是“更正版本” 编辑: 这本书是正确的。你需要了解EDT是如何工作的。启动应用程序时,main()方法中调用的代码在单独的线程上执行。Swing事件和绘制在事件调度线程(EDT)上完成。因此,在go()方法中调用sleep()不应影响圆的绘制,您应该看到涂抹。如果在循环完成后只看到一个椭圆形,则这意味着您的IDE或平台在EDT上的main()方法中启动代码,这是不正常的 您可以通过添加以下内容来验证我的上述声明:
System.out.println( SwingUtilities.isEventDispatchThread() );
查看它是否在EDT上执行。嘿,我看你也读过Head First Java的书,不错吧 当我在同一本书中学习第12章时,我也遇到了同样的问题 在第15章学习了线程之后,我明白了为什么椭圆不会在屏幕上“涂抹” 首先,关于
repaint()
方法
调用repaint()
方法不会立即调用JPanel中的paintComponent(Graphics g)
。相反,它会安排对事件调度线程的调用以供以后使用
我不确定你得到了什么输出,因为你没有告诉我们
我假设根本没有动画。当你运行它时,在终端屏幕上可能只有一个椭圆形
如果是这样,程序就是这样运行的。循环运行了150次,因此调用了repaint()
150次。但是,正如我前面所说,repaint()
只调用事件调度线程中的计划,而不是立即运行paintComponent(Graphics g)
这意味着for循环在实际调用paintComponent(Graphics g)
之前完成。这很可能就是你没有在书中看到“错误”的原因
你怎么知道“错误”
尝试使线程睡眠更长时间。假设您是从EDT运行的(如果您还没有,则应该这样做),您肯定不想在swing应用程序中使用
thread.sleep()
。相反,使用swing计时器进行动画。尚未了解线程。这就是防止椭圆涂抹的原因吗?@vader,不,线程是一个单独的命令执行序列。想想几个处理器内核,每个内核都有自己必须运行的命令列表(但在Java中,它是模拟和调度的,而且……你明白了)。大多数Java应用程序都有多个这样的应用程序,Swing尤其有一个叫做“UI线程”的东西,它负责绘制应用程序,理想情况下,您永远不应该让它休眠,因为这样UI就会变得无响应。您发布的代码不完整。我们不知道go()方法是如何调用的,所以我们不知道您的代码是否在EDT上执行。如果代码在EDT上执行,则会导致EDT休眠,这意味着帧无法重新绘制自身。如果它不在EDT上,那么你应该看到圆圈的“涂抹”。但是如果没有可执行代码,我们无法确定您在做什么。不要告诉我们。张贴您正在执行的确切代码。所以我们可以复制/粘贴/编译/文本。这种方法被称为。每个问题都应该贴上“MRE”。不添加超级调用,绘制的椭圆将自动删除。我想知道如何保存它们,因为书中说我的代码应该保存所有以前绘制的椭圆,并且看起来就像在屏幕上绘制了一条粗对角线。为什么不是现在?你所描述的与应该发生的相反。发布你的代码。当我运行你的代码时,我在屏幕上看到椭圆形的“涂抹”,因为正如预期的那样,背景没有被清除。如果你加上我在上面建议的陈述,那么背景就会被清除,你只能看到一个椭圆形。我在Windows7上使用JDK8。如果您遇到问题,可能是您的平台造成的。我尝试添加isEventDispatchThread()并
System.out.println( SwingUtilities.isEventDispatchThread() );