1

我有数百个不同的函数在 EDT 中运行。其中很多包括长时间运行的任务,有些包括对 GUI 的更改。GUI 偶尔会为用户挂起,但由于 GUI 挂起并非 100% 的时间都发生在同一区域,因此很难跟踪发生这种情况的所有位置。这个问题不是高优先级,因为挂起通常在窗口最小化/最大化后开始工作,但最终需要完成。

经过一些研究,我发现我可以在SwingWorker下使用 doInBackground()来处理任何需要劳动密集型工作的方法,并使用 done() 来绘制 GUI。此外,我相信我可以对碰巧在 doInBackground() 函数中的每个 GUI 绘图使用SwingUtilities.invokeLater 。但是,我想避免调整代码中数百个函数中的每一个。

有没有办法可以使用单个 SwingWorker 并将任何长时间运行的方法发送到 doInBackground() 函数?对每个使用 SwingWorker 的错位 GUI 代码多次使用 invokeLater 函数不是问题,因为它并不频繁。

如果这是不可能的,我可以使用某种替代方法吗?谢谢你。

4

2 回答 2

2

All methods that update the GUI must be invoked on the EDT, otherwise you may end up with some unexplained GUI behavior (which sounds like what you are seeing). You could have repaints that don't happen properly, thread races, etc.

It is not advised to run long running tasks on the GUI because they will cause the GUI to become unresponsive, so for long running tasks, SwingWorker is a good solution to use (note that the process and done methods are called on the EDT automatically so your worker can do its long running work in doInBackground but you can safely update the GUI without using SwingUtilities.invokeLater from the done method).

As you mentioned you have hundreds of methods and you don't want to call SwingUtilities.invokeLater every time, you might want to look into one of the task frameworks. The Swing Application Framework was developer under JSR-296 http://java.sun.com/developer/technicalArticles/javase/swingappfr/ but is not actively supported, but still provides a nice framework. http://en.wikipedia.org/wiki/Swing_Application_Framework is a list of alternative frameworks.

It sounds like you are going to need to do some significant rewriting in your application. Calling GUI methods from outside the EDT is unsafe to do.

于 2012-05-28T15:55:01.960 回答
1

我不明白你的要求是怎么可能的。Swing 无法在执行前知道什么是“长时间运行”的方法调用。如果该方法已经在执行(在 EDT 上),Swing 不能简单地将其拾取并将其移动到新线程。即使您指出应该在后台线程中运行哪些方法调用,也很难将其关闭。我能想到的在 Java 中实现这一点的唯一方法是使用 AOP(您可以拦截方法调用)。但是实现AOP会比重新实现现有应用程序以使用 SwingWorkers 更难。

听起来您的 Swing 应用程序的体系结构已损坏。不得在 EDT 上执行长时间运行的任务。我很抱歉,但我认为你只需要在这个问题上硬着头皮。如果您希望您的应用程序感觉敏捷、响应迅速并具有可预测的行为,您必须通过将长时间运行的代码置于后台线程中来解决此问题。

如果您的应用程序使用大量后台任务,您可能希望使用出色的Swing Task API。否则你会很快发现自己陷入了 SwingWorker 意大利面条。

对于碰巧在 doInBackground() 中的每个 GUI 绘图

您不能在 'doInBackground()' 方法中调用 Swing 绘图、更新等方法(实际上可以,但不能这样做)。这是因为这是在 EDT 之外执行的方法。GUI 绘图和组件更新只能在 SwingWorker 的 'done()' 方法中调用。

于 2012-05-28T18:00:49.410 回答