【问题标题】:repaint() in Java doesn't "re-paint" immediately?Java 中的 repaint() 不会立即“重新绘制”?
【发布时间】:2012-11-07 08:19:56
【问题描述】:

我有这样的代码:

// 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()) 时,结果是正确的:

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 方法有效,但有时它是盲目的,所以我不想使用它。有人可以给我一些建议吗?谢谢!

【问题讨论】:

标签: java swing repaint paintcomponent


【解决方案1】:

正如其他答案所说:这是 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 循环中会如何表现。

【讨论】:

    【解决方案2】:

    如果您仔细阅读repaint 的文档,您会注意到它声明(强调我的):

    如果此组件是轻量级组件,则此方法会导致 尽快调用这个组件的paint方法。否则, 此方法会立即调用此组件的更新方法 可能

    这意味着允许 AWT/Swing 通过合并快速连续请求的重绘来优化重绘。还有一个repaint(long time) 方法,它允许您控制允许AWT/Swing 等待多长时间来完成您的重绘请求。但它可能仍会合并请求,尤其是如果您在循环中执行它们。

    阅读文章"Painting in AWT and Swing" 可能会有所帮助,该文章试图解释所涉及的各种概念。

    要为每次迭代重新绘制面板,您必须等待绘制发生,然后继续执行循环。这意味着您需要在处理线程(循环)和 AWT/Swing 线程之间进行一些同步。作为一个粗略的想法,例如,如果自上次调用 repaint() 以来尚未重新绘制面板对象,则可以在循环结束时在面板对象上使用 wait() 并在面板的 paintComponent() 末尾调用 notifyAll()方法。但是,这可能很难正确实施,因此只有在确实需要“实时”重绘组件时才应该这样做。作为替代方案,可以使用paintImmediately(...),但您必须在事件调度线程中完成所有处理,如下所示:

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            while(notDone) {
                // Do your processing
                panel.paintImmediately(...);
            }
        }
    });
    

    请注意,这将在循环运行时停止处理任何事件处理,包括鼠标和键盘输入。你可以在"Concurrency in Swing"阅读更多关于 Swing 和 Threading 的内容

    【讨论】:

    • repaint(long time) 在我的系统上什么都不做,仍然等待 0.5 秒或类似的时间(我知道,因为我正在实现一个时钟)。整个 Swing 时间都很糟糕,至少在 Ubuntu 上是这样,而且是在 AMD 3600X 上,它不仅在一个内核上而且在所有内核上都是零负载。
    【解决方案3】:

    了解您无法完全控制是否或何时 paint(...) get 被调用,而 repaint() 调用只是一个 建议 JVM 绘制。如果有太多的 repaint() 请求进来 并且它们像你一样堆叠起来,然后它们将被合并

    参考: https://stackoverflow.com/a/13256847/1423083

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      • 1970-01-01
      相关资源
      最近更新 更多