简体   繁体   English

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

[英]repaint() in Java doesn't “re-paint” immediately?

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()) ,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 

Why? 为什么? paintComponent method works, but sometimes it's blind, so I don't want to use it. paintComponent方法有效,但有时它是盲目的,所以我不想使用它。 Anybody can give me some suggestions? 有人可以给我一些建议吗? Thanks! 谢谢!

If you read the documentation of repaint carefully, 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. 如果此组件是轻量级组件,则此方法会尽快调用此组件的paint方法。 Otherwise, this method causes a call to this component's update method as soon as possible . 否则,此方法会尽快调用此组件的更新方法。

This means that AWT/Swing is allowed to optimize repainting by merging repaints that are requested in a rapid succession. 这意味着允许AWT / Swing通过合并快速连续请求的重绘来优化重新绘制。 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. 还有一个repaint(long time)方法,它允许您控制AWT / Swing在完全填充重绘请求时等待的时间。 It might still merge requests though, especially if you do them in a loop. 它可能仍会合并请求,特别是如果你在循环中执行它们。

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. 这意味着您需要在处理线程(循环)和AWT / Swing线程之间进行一些同步。 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. 作为一个粗略的想法,你可以在循环结束时的面板对象上wait() ,如果它自上次调用repaint()以来没有重新repaint()并在面板的paintComponent()结束时调用notifyAll() paintComponent()方法。 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: 作为替代方案,可以使用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和Threading的更多信息

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 while loop. 虽然我不确定它在你的while循环中的表现如何。

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. 了解到你无法完全控制是否或何时调用paint(...),而且repaint()调用只是建议JVM绘制的。 If too many repaint() requests come in and they stack up as yours are doing, then they will be combined 如果有太多repaint()请求进入并且它们正在进行堆叠,那么它们将被合并

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM