在多任务应用程序中管理GUI和EDT

dam*_*son 3 java user-interface swing multithreading event-dispatch-thread

我开发了一个用于创建和提取存档的Java应用程序 - 比如WinRAR.您可以使用多线程同时创建多个归档.最近,我希望在每个创建时在新的JFrame中以JProgressBar的形式在存档创建期间添加信息状态.

但我的问题是在新的状态框架和创建存档的线程中生成信息.这就是我在存档线程中创建JFrame以更新当前进度条的原因.

但就像我可以在各种信息源和你的答案/评论中阅读它一样,它反对Java Swing和性能; 我无法在EDT的其他地方创建摆动对象.

但那么,我该如何解决我的问题呢?如何在存档的写入和状态JFrame(使用JProgressBar)之间建立通信?


编辑:

我实现了SwingWorker来管理我的应用程序中的GUI.现在已经完成了,我还有一个问题:

使用SwingWorker,如何使用状态框架按钮上的事件对后台任务执行操作?(示例:暂停压缩或停止压缩.)

mKo*_*bel 5

  1. JProgressBar放在JDialog中并显示,不要创建新的顶级容器.创建一次并重复使用它

  2. 长时间和繁重的代码将更好地重定向到BackGround任务

  3. 您可以JProgressBar从后台任务进度移动

    • 只有在EDT上完成GUI相关代码时才能在Swing中实现更多并发性

    • 并且有两种正确的方法可以做到这一点

      • 通过使用SwingWorker

      • Runnable#Thread但GUI rellated代码必须被包裹成invokeLater()


jfp*_*ret 5

正如其他人所说,最好的方法是使用SwingWorker.

SwingWorker 属性是可听的,并且在EDT中总是调用侦听器,因此,您可以执行以下操作:

public class ArchivingWorker extends SwingWorker<Void, Void> {
    JProgressBar progressBar = null;
    // Other members here...
    ...

    public ArchivingWorker(...) {
        // Any specific initialization here (in EDT)
        addPropertyChangeListener(new PropertyChangeListener() {
            @Override void propertyChange(PropertyChangeEvent e) {
                if (    "state".equals(e.getPropertyName())
                    &&  e.getNewValue() == StateValue.STARTED) {
                    // Background thread has just started, show a progress dialog here
                    progressBar = new JProgressBar();
                    ...
                }
                else if ("progress".equals(e.getPropertyName())) {
                    // Update progress bar here with e.getNewValue()
                    ...
                }
            }
        });
    }

    @Override protected Void doInBackground() {
        // Archiving process here and update progress from time to time
        setProgress(progress);

        return null;
    }

    @Override protected void done() {
        // Ensure that archiving process worked correctly (no exception)
        try {
            get();
        } catch (Exception e) {
            // Handle exception (user feedback or whatever)
        } finally {
            // Close progress dialog
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以ArchivingWorker根据需要使用它:

ArchivngWorker worker = new ArchivingWorker(...);
worker.execute();
Run Code Online (Sandbox Code Playgroud)