1

我有一个小问题,现在我必须处理一个小型 Java 项目。我正在尝试从 Button 事件处理程序运行几个线程;那么最后一个线程必须更新 UI 上的 TextArea。线程正在做计算工作。最重要的部分是让 UI 工作正常 - 我不想冻结 UI,当然我想定期从其他线程之一更新 UI 的 TextArea(不是 ui 的线程)。所以这是我的代码的一部分:

在 Button 的事件处理程序中,我正在启动这 4 个线程:

Thread generate = new CombinaMaker();
generate.run();

Thread forward = new TranslateForward();
forward.run();

Thread backward = new TranslateBackward();
backward.run();

Thread refresh = new Refresher();
refresh.run();

我希望线程同时工作。Refresher 线程必须定期更新 UI TextArea 组件。

因此,这是我从 Refresher 线程更新 UI 的方法:

public static void updateProgress() 
{
    SwingUtilities.invokeLater(new Runnable() 
    {   
         public void run() 
         {
             //HERE
             //I have a loop that have to be looping at every 500 ms
         }
     }
}

我的问题是:我应该这样做吗?我需要简单有效。这个循环让我很难过,因为只要应用程序正常工作,它就必须循环。这可能是冻结用户界面的原因吗?我知道我在某个地方犯了大错误,但此刻我无法独自找到它。也许你可以建议我一些简单的解决方案。最后一个想法 - 前 4 个线程:我想“同时”启动它们,而不会冻结我的 UI。这种方式(从事件处理程序中像这样启动它们......)是正确的还是可能更好?非常感谢朋友!

PS。如果通过我的“刷新”线程刷新 UI 是一项艰巨的工作,我已经准备好妥协变体 - 通过他自己的线程(UI 线程)更新 UI。但在这种情况下,我可能必须使用一些“时间拍摄机制”——避免 UI 冻结。你在想什么?

4

4 回答 4

3

主要问题是你的算法。代替

SwingUtilities.invokeLater(new Runnable() {   
    public void run() {
        //HERE
        //I have a loop that have to be looping at every 500 ms
    }
}

你应该有

// HERE
// I have a loop that have to be looping at every 500 ms
// and when something must be updated in the GUI:
SwingUtilities.invokeLater(new Runnable() {   
    public void run() {
        // update the GUI as fast as possible
    }
});

IE

while (true) {
    Thread.sleep(500L);
    String update = getUpdate();
    SwingUtilities.invokeLater(new Runnable() {   
        public void run() {
            textArea.append(update);
        }
    });
}

传递给的 runnableSwingUtilities.invokeLater()在事件调度线程中执行。它不能执行长时间运行的任务。无休止地循环是一项非常耗时的任务。

于 2012-10-16T21:38:33.563 回答
2

您不想循环传递给invokeAndDoLater 的runnable。请参阅此示例:http ://www.javamex.com/tutorials/threads/invokelater.shtml

于 2012-10-16T21:38:10.693 回答
1

SwingUtilities.invokeLater 并未设计为调用长时间运行的线程。您的问题的一种解决方案可能是这个

您还可以尝试反转循环和 SwingUtilities.invokeLater 调用的嵌套,但这是否可行取决于您的代码的其余部分

do {
    // Sleep and other stuff
    SwingUtilities.invokeLater(new Runnable() {
        public void run()  {
        // Update UI
        }
    });
} while(...);
于 2012-10-16T21:32:09.830 回答
1

我不想冻结用户界面,当然

为不想冻结 UI 点赞。不幸的是

我想定期从其他线程之一更新 UI 的 TextArea

不是一种选择。更新 Swing 组件必须在 UI 线程(事件调度线程)上完成。幸运的是,Swing 有一个用于定期更新 UI 的内置类:javax.swing.Timer类。在Timer后台运行,并在 Event Dispatch Thread 上执行,因此它非常适合此任务。

于 2012-10-16T21:41:30.333 回答