Java JPanel repaint()方法及其调试
所以我用Java创建了一个小窗口,上面有一个球在弹跳,我试着调试并观察程序的运行。以下是问题的重要代码:Java JPanel repaint()方法及其调试,java,swing,debugging,jpanel,paint,Java,Swing,Debugging,Jpanel,Paint,所以我用Java创建了一个小窗口,上面有一个球在弹跳,我试着调试并观察程序的运行。以下是问题的重要代码: public class Ball { private static final int SPEED = 2; private int x = 0, y = 0; private int xInc = SPEED, yInc = SPEED; -> public void paint(Graphics2D g) { g.fillOval(x, y, 30, 30); } }
public class Ball {
private static final int SPEED = 2;
private int x = 0, y = 0;
private int xInc = SPEED, yInc = SPEED;
-> public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
}
public class Game extends JPanel {
Ball gameBall = new Ball();
public void paint(Graphics g) {
super.paint(g); // cleans the panel
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
gameBall.paint(g2d);
}
public void updateBall() {
gameBall.move(this.getWidth(), this.getHeight());
}
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Simple Pong");
mainFrame.setSize(400, 400);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Game gamePanel = new Game();
mainFrame.add(gamePanel);
mainFrame.setVisible(true);
while (true) {
try {
gamePanel.updateBall();
gamePanel.repaint();
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println(e);
System.exit(1);
}
}
}
}
我为Ball的paint方法的入口设置了一个方法指针,认为这会导致程序在每次调用repaint()方法时停止,因为我认为它调用了paint方法。然后,我可以看着球一次移动一个增量,而不是在重绘方法所在的位置放置一个线指针
当我这样做时,程序不会随着球的位置的每次更新而停止,而是以看起来像随机增量的方式停止。球将接近边缘,然后在中间,这么多的油漆呼叫必须发生。
问题:对于我的轻量级容器,repaint方法是否总是调用paint方法?如果是这样的话,为什么调试器不随着球的每次增量而停止,而只是有时停止显示新的位置?很明显,如果球在运行时在屏幕上平稳移动,则会有东西完全按照我的希望将球对象绘制到我的游戏面板上
注意:如果我们为游戏的绘制方法的入口放置一个方法断点,也会发生同样的情况,我已经扩展了JPanel,这就是我绘制球的地方
repaint方法是否总是为我的轻量级容器调用paint方法
否。调用repaint
是请求更新。重绘管理器可以优化请求,并在可能的情况下将其整合到单个事件中
Swing使用被动绘制算法,该算法旨在提高不需要一直重新绘制的系统的性能,仅在需要进行绘制时才进行绘制
另一方面,您应该避免覆盖组件的paint
,而是更喜欢使用paintComponent
。还要注意,传递给绘制方法的图形
上下文与已绘制的所有其他内容共享,对其进行更改可能会产生不良的副作用
相反,您应该创建图形上下文状态的快照并对其进行修改
Graphics2D g2d = (Graphics2D g2d)g.create();
//... Update, modify, transform, do what you want...
g2d.dispose();
请查看和以了解更多详细信息
Swing在单个线程中运行。也就是说,所有绘制甚至通知都是在事件调度线程的上下文中完成的,有关更多详细信息,请参阅
当您到达断点时,事件调度线程停止,但您正在运行的while循环
没有停止,因此球
的x/y位置仍然被更新,这意味着当程序恢复时,球将显示为“跳转”到新位置
您可以通过在gamePanel.updateBall()上放置断点来测试这一点代码>,UI将继续更新(在每次请求重新绘制后),但会随着而增量更新,因为球的状态没有改变
调试过程不会停止正在运行的其他线程,而只是影响触发断点的线程
当Java调用main
方法时,它是从所谓的“主线程”调用的。在大型机上调用setVisible
时,将创建一个新线程(事件调度线程),这允许UI在上独立运行,而(true)
,防止它“挂起”UI。查看更多详细信息重新绘制
不直接调用绘制
。它只是设置了一个变量,以便Swing在某个时候记住调用paint
现在,你知道线程吗?因为这里发生的事情的解释涉及到线程
与Swing相关的一切通常都在一个线程上运行,称为“事件线程”。特别是,在事件线程上调用paint
在名为“主线程”的线程上调用main
。主线程不是事件线程。您的main
方法移动球(通过调用updateBall
间接地移动球)。主线程的代码大致是“移动球,设置'repain me later'变量,重复”
当您的断点被命中时,只有命中断点的线程被暂停。这意味着事件线程已暂停。更新球位置的主线程继续运行。当您认为程序暂停时,球的位置会不断更新(因为实际上只有一个线程暂停)
当您取消暂停事件线程时,事件线程将返回到正在执行的操作(即绘制)。因为现在,“以后重新绘制我”变量已经设置好,它将再次绘制游戏面板-但这次球已经移动了相当远。那么,如果没有调用我的重写方法,程序如何知道将球放置在何处呢?这是一种错觉。帧之间有足够的变化,允许球“出现”移动…这是动画的本质…任何人都希望突出显示投票失败的原因,以便我可以从您的观察中学习,甚至可能修复我做错的事情?但当运行时,球会像预期的那样在屏幕上平稳移动。调试时,它会在不同的位置出现,而不是以小的增量出现。为什么画法…这是唯一一个有关于我的球放在哪里的说明的东西。。。只会随机出现,但似乎每帧都会被调用。@mad程序员我对你不回答这个问题投了反对票,除非我误解了这个问题。非常感谢!我越来越生气了。你真的不能再清楚地回答我的问题了。@immibis还有一件事,如果main方法仍在运行,并且只有事件线程暂停,那么在main方法中的事件威胁上运行的方法(如repaint)会发生什么情况?@bmcentee148repaint
wi