【问题标题】:Manage GUI and EDT in a multi-task application在多任务应用程序中管理 GUI 和 EDT
【发布时间】:2011-11-21 20:31:12
【问题描述】:

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

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

但是就像我可以在不同的信息源和您的答案/cmets 中阅读它一样,它不利于 Java Swing 和性能;我无法在 EDT 之外的其他地方创建摇摆对象。

但是,我应该如何解决我的问题?如何在我的归档文件的写入与其状态 JFrame(使用 JProgressBar)之间建立通信?


编辑:

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

使用 SwingWorker,我如何通过状态框架按钮上的事件来处理后台任务? (例如:暂停或停止压缩。)

【问题讨论】:

    标签: java multithreading swing user-interface event-dispatch-thread


    【解决方案1】:
    1. JProgressBar 放入并显示在JDialog 中,不要创建新的Top-Level Container。创建一次并重复使用它

    2. 长时间且繁重的代码最好重定向到后台任务

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

      • 仅当 GUI 相关代码在 EDT 上完成时更多 Concurrency in Swing

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

        • 通过使用SwingWorker

        • 来自Runnable#Thread,但GUI相关代码必须封装到invokeLater()

    【讨论】:

    • 我想我理解挥杆性能的并发性。我开始用 SwingUtilities(invokeLater / isEventDispatchThread) 开发一个新的实现,但是代码太重并且状态 GUI 有一些错误和冻结。我会尝试使用 SwingWorker。
    • 是的,对,查看我标记为 Table 和 SwingWorker 的帖子,然后您可以选择更好和最简单的选项...
    • 好的。你知道吗 ?我将在我的应用程序中实现 SwingWorker,如果我有问题,我会回来检查你。
    • 再次 Runnable#Thread 更容易处理新手错误或出现错误,
    • @mKorbel:+1 干得好!如果您获得访问权限,请不要忘记邀请我加入 stackoverflow 职业;)
    【解决方案2】:

    按照其他人的建议,最好的方法是使用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
                ...
            }
        }
    }
    

    那么你可以根据需要使用ArchivingWorker

    ArchivngWorker worker = new ArchivingWorker(...);
    worker.execute();
    

    【讨论】:

    • 我真的忘了问你,你知道stackoverflow.com/questions/7053865/…的一些事情
    • @mKorbel 不,但我会学习。我想它谈论的是摇摆工人的行为。
    • @jfpoilpret 我同意,但您的方法 doInBackground 存在问题,因为 JprogressBar 不会在 EDT 中更新。否则感谢其余的,这给了我一些概念。但我会使用 swingWorker,因为 PropertyChangeListener 还有些模糊。
    • @damson 我认为进度条不会在 EDT 中更新。 SwingWorker.setProgress() 触发一个PropertyChangeEvent,所有注册的侦听器都将在在EDT中被调用,这就是我将进度条的实际更新放在PropertyChangeListener 中的原因。如果您不确定,只需从 PCL 中打印出SwingUtilities.isEventDispatchThread()
    • 好吧,我没看到这是 SwingWorker 方法。它非常适合我的情况。谢谢
    【解决方案3】:

    @mKorbel提供的答案很好,但确实没有必要使用另一个顶级容器(例如JDialog)来显示进度条。相反,您可以使用JFrame 实例的Glass Pane

    【讨论】:

    • 感谢您的回答。关于顶级容器,我没有任何选择使用它,因为 JDialog 占据了应用程序的所有焦点,多任务变得无用。 (我不知道我是否可以理解;如果我不知道,请告诉我)
    • @damson,不……这根本没有多大意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    • 2016-05-07
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    相关资源
    最近更新 更多