Java 中的 repaint() 不会立即“重新绘制”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13453331/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 12:48:04  来源:igfitidea点击:

repaint() in Java doesn't "re-paint" immediately?

javaswingrepaintpaintcomponent

提问by Bood Carley

I have a code like that:

我有一个这样的代码:

// 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

But when I change panel.repaint()to panel.paintComponent(panel.getGraphics()), the out is right:

但是当我更改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
Test_count: 752, MyPanel_count: 752
Test_count: 753, MyPanel_count: 753
Test_count: 754, MyPanel_count: 754
Test_count: 755, MyPanel_count: 755

Why? paintComponentmethod works, but sometimes it's blind, so I don't want to use it. Anybody can give me some suggestions? Thanks!

为什么?paintComponent方法有效,但有时它是盲目的,所以我不想使用它。任何人都可以给我一些建议吗?谢谢!

回答by Simon Lehmann

If you read the documentation of repaintcarefully, you will notice that it states that (emphasis mine):

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

If this component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.

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

This means that AWT/Swing is allowed to optimize repainting by merging repaints that are requested in a rapid succession. There is also a repaint(long time)method, which allows you to control how long AWT/Swing is allowed to wait with fullfilling your repaint request. It might still merge requests though, especially if you do them in a loop.

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

It might be helpful to read the article "Painting in AWT and Swing", which tries to explain the various concepts involved.

阅读文章“在 AWT 和 Swing 中绘画”可能会有所帮助,该文章试图解释所涉及的各种概念。

To get the panel repainted for every iteration, you would have to wait for a paint to happen and then proceed with your loop. This means you need some synchronization between your processing thread (the loop) and the AWT/Swing thread. As a rough idea, you could for example wait()on the panel object at the end of your loop if it has not been repainted since the last call to repaint()and call notifyAll()at the end of your panel's paintComponent()method. However, this can be tricky to implement right, so you should only do this if you really need "real-time" redrawing of your component. As an alternative, paintImmediately(...)could be used, but you would have to do all your processing in the event dispatching thread, like this:

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

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

Note that this will stop any event processing including mouse and keyboard input from being processed while your loop is running. You can read more about Swing and Threading in "Concurrency in Swing"

请注意,这将在您的循环运行时停止处理任何事件处理,包括鼠标和键盘输入。您可以在“Swing中的并发”中阅读有关 Swing 和线程的更多信息

回答by Terry

As the other answers say: it's a problem of when AWT is calling paint().

正如其他答案所说:这是 AWT 何时调用paint().

If you do some work that needs information from painted/layouted Components, what helps is also to put this work into a worker thread that waits until the painting is done.

如果你做的一些工作需要来自绘制/布局组件的信息,那么将这项工作放入等待绘制完成的工作线程也是有帮助的。

In your case that would be something like:

在你的情况下,这将是这样的:

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);
    }
});

Although I'm not sure how it would behave in your whileloop.

虽然我不确定它在你的while循环中会如何表现。

回答by Mukul Goel

understand that you do not have complete control over if or when paint(...) get's called, and that repaint() calls are only a suggestion to the JVM to paint. If too many repaint() requests come in and they stack up as yours are doing, then they will be combined

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

refer : https://stackoverflow.com/a/13256847/1423083

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