Java中的repaint()不会立即“重新绘制”?
我有这样的代码:
// In MyPanel.java public void paintComponent(Graphics g) { super.paintComponent(g); // Draw something mypanel_count++; } // In Test.java public void testLargeData() { while (notDone) { panel.repaint(); // do huge work test_count++; System.out.println("Test_count: " + test_count + ", MyPanel_count: " + mypanel_count); } } // Output !!! Test_count: 752, MyPanel_count: 23 Test_count: 753, MyPanel_count: 23 Test_count: 754, MyPanel_count: 23 Test_count: 755, MyPanel_count: 24
但是当我将panel.repaint()
更改为panel.paintComponent(panel.getGraphics())
,out是正确的:
Test_count: 752, MyPanel_count: 752 Test_count: 753, MyPanel_count: 753 Test_count: 754, MyPanel_count: 754 Test_count: 755, MyPanel_count: 755
为什么? paintComponent
方法有效,但有时它是盲目的,所以我不想使用它。 有人能给我一些建议吗? 谢谢!
如果您仔细阅读repaint
的文档,您会注意到它(强调我的):
如果此组件是轻量级组件,则此方法会尽快调用此组件的paint方法。 否则,此方法会尽快调用此组件的更新方法。
这意味着允许AWT / Swing通过合并快速连续请求的重绘来优化重新绘制。 还有一个repaint(long time)
方法,它允许您控制AWT / Swing在完全填充重绘请求时等待的时间。 它可能仍然合并请求,特别是如果你在循环中执行它们。
阅读文章“绘画在AWT和swing”可能会有所帮助,该文章试图解释所涉及的各种概念。
要让每次迭代都重新绘制面板,您必须等待绘制,然后继续循环。 这意味着您需要在处理线程(循环)和AWT / Swing线程之间进行一些同步。 作为一个粗略的想法,你可以在循环结束时的面板对象上wait()
,如果它自上次调用repaint()
没有重新repaint()
并在面板的paintComponent()
结束时调用notifyAll()
paintComponent()
方法。 但是,实现这一点可能很棘手,所以只有在真正需要“实时”重新绘制组件时才应该这样做。 作为替代方案,可以使用paintImmediately(...)
,但是您必须在事件调度线程中执行所有处理,如下所示:
SwingUtilities.invokeLater(new Runnable() { public void run() { while(notDone) { // Do your processing panel.paintImmediately(...); } } });
请注意,这将停止任何事件处理,包括在循环运行时处理鼠标和键盘输入。 您可以在“Swutch中的并发”中阅读有关Swing和Threading的更多信息
正如其他答案所说:这是AWT何时调用paint()
。
如果你做一些需要绘制/布局组件信息的工作,那么将这项工作放到一个等待绘画完成的工作线程中也会有所帮助。
在你的情况下,这将是:
panel.repaint(); SwingUtilities.invokeLater(new Runnable() { public void run() { // do huge work test_count++; System.out.println("Test_count: " + test_count + ", MyPanel_count: " + mypanel_count); } });
虽然我不确定它在你的while
循环中的表现如何。
理解你无法完全控制是否或何时调用paint(…),而且repaint()调用只是建议JVM绘制的。 如果有太多的repaint()请求进入并且它们像你的那样堆叠起来,那么它们将被合并
参考: https : //stackoverflow.com/a/13256847/1423083