【问题标题】:SwingWorker in another SwingWorker's done methodSwingWorker 在另一个 SwingWorker 的 done 方法中
【发布时间】:2014-04-17 05:58:01
【问题描述】:

首先,我需要通知您,我正在尽我最大的努力学习如何用 Java 编写代码。它有点困难,但是,我相信我拥有它。我过去曾提交过几个关于 SwingWorkers 等的问题。每一个我都以为我拥有它,但后来发现我仍然需要学习去做。希望这一次不是那种时代。

话虽如此,如果您发现任何不符合标准或将来可能导致问题的情况,请告诉我。


现在回答问题!

我已经构建了一个 JFrame,在它允许用户继续到另一个页面、按下按钮或其他任何东西之前,它会加载一些东西。加载数据后,它将解锁 JFrame 以允许用户与数据进行交互。

问题是,(这不是真正的问题,只是澄清一下)我需要执行另一个任务,同时用户可以以不会打扰他们的方式与 JFrame 交互,但是,将更新JFrame 基于它找到的结果。一个例子可能是版本检查。根据版本是否过期,通知用户。


示例 Sudo 代码

protected void startJFrame() {
    JFrame myFrame = new JFrame();//Starts with disable/invisible components. Preventing the user from doing to much before allowed.
    SwingWorker<Void, Progress> loadingWorker = new SwingWorker<Void, Progress>() {
        @Override
        protected Void doInBackground() throws Exception {
            publish(new Progress(0,"Loading This"));      // Set Percent
            loadingTasks.loadThis();                         // Do Work!!
            publish(new Progress(25,"Loading That"));     // Set Percent
            loadingTasks.loadThat();                         // Do Work!!
            publish(new Progress(50,"Loading More"));     // Set Percent
            loadingTasks.loadMore();                         // Do Work!!
            publish(new Progress(75,"Loading Last"));     // Set Percent
            loadingTasks.loadLast();                         // Do Work!!
            publish(new Progress(100,"Loading Complete"));// Set Percent
            return null;
        }
        @Override
        protected void process(List<Progress> ProgressList) {
            for (Progress p : ProgressList) {
                System.out.println(p.getInt() + "% " + p.getString()); //Show user percent and what its doing.
            }
        }
        @Override
        protected void done() {
            try {
                get();
                loadingTasks.WrapUp();//Set Variables or other small stuff.
                myFrame.userAllowed();//Lets the user interact with the whole JFrame.
                SwingWorker<Void, Void> secondWorker = new SwingWorker<Void, Void>() {
                    @Override
                    protected Void doInBackground() throws Exception {
                        versionCheck.makeItSo();// Do Work!!
                        return null;
                    }
                    @Override
                    protected void done() {
                        try {
                            get();
                            versionCheck.wrapUp();//Set Variables or other small stuff.
                            myFrame.showLabel();//Show a label with specific info.
                        } catch (InterruptedException | ExecutionException e) {
                            e.printStackTrace();
                        }
                    }
                };
                secondWorker.execute();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    };
    loadingWorker.execute();
}

涉及此代码的题外话问题。

我担心创建许多对象而不是处理它们,只是为了传递多个变量。特别是在第一个 doInBackground 方法中创建的 Progress 对象。

这样做可以吗?它会自动处理进度对象吗?如果没有,我处理完后如何处理它们?

【问题讨论】:

  • 两个任务可以同时运行吗?他们是否需要一个接一个地运行。 Java的垃圾回收非常擅长短命的对象,烦死了,不过应该不是什么大问题……
  • @MadProgrammer 不,是的。当第一个任务完成时,它会创建一个在其他方面无法访问的对象。这意味着如果第一个任务出现问题,它不会创建该对象。 “versionCheck”需要访问该对象。
  • 我意识到它们可以存在于同一个 swingworker 中。而且,这就是它最初的构建方式。但是,我正在努力寻找这样的解决方案,因为它非常适合我的情况。
  • 您创建了SwingWorker 的扩展,所以您需要做的就是new LoadingWorker().execute()...
  • static 不是你的朋友。我已经做了一个答案,我“希望”它能给你一些想法。在某些时候你需要传递一些东西给SwingWorker,你可以传递框架的引用,但我不喜欢这样做,给调用者很大的权力去做不应该做的事情,我更喜欢使用某种接口,这样我就可以决定两者之间的合同。更好的解决方案可能是只使用PropertyChangeListener...

标签: java swing jframe swingworker


【解决方案1】:

SwingWorker支持PropertyChange事件,即你可以监听SwingWorker何时改变状态或更新它的进度……是的,SwingWorker甚至支持进度通知,例如

这意味着您可以设置PropertyChangeListener 来监控progressstate 属性的更改并采取适当的措施...

一个简单设置进度更新的工人......

public class LoadMaster extends SwingWorker<Void, Progress> {

    @Override
    protected Void doInBackground() throws Exception {
        System.out.println("Working hard here, nothing to see...");
        for (int index = 0; index < 100; index++) {
            Thread.sleep(10);
            setProgress(index);
        }
        return null;
    }

    @Override
    protected void done() {
        try {
            get();
        } catch (Exception e) {
        }
    }

}

一个例子PropertyChangeListener...

public class LoadMasterPropertyChanegHandler implements PropertyChangeListener {

    private SwingWorkerExample example;

    public LoadMasterPropertyChanegHandler(SwingWorkerExample example) {
        this.example = example;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        System.out.println(evt.getPropertyName());
        if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
            int value = (int) evt.getNewValue();
            example.showProgress(value);
        } else if ("state".equalsIgnoreCase(evt.getPropertyName())) {
            SwingWorker worker = (SwingWorker) evt.getSource();
            if (worker.isDone()) {
                try {
                    worker.get();
                    example.loadCompleted();
                } catch (InterruptedException | ExecutionException exp) {
                    example.loadFailed();
                }
            }
        }
    }

}

现在,所有这一切都是将信息发送回SwingWorkerExample(它即将到来),这使它能够确定它应该做什么......

在本例中,loadCompleted 方法会更新 UI,然后启动第二个工作器...

protected void loadCompleted() {
    //...
    LoadStuffWorker stuffWorker = new LoadStuffWorker(this);
    stuffWorker.execute();
}

事实上,我可能会使用接口来代替,所以我不会公开暴露这个类,但这是另一天的话题......

还有完整的例子……

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class SwingWorkerExample {

    private JProgressBar pb;
    private JPanel content;

    public static void main(String[] args) {

        new SwingWorkerExample();

    }

    public SwingWorkerExample() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                pb = new JProgressBar();
                content = new JPanel();
                content.setBorder(new EmptyBorder(10, 10, 10, 10));

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(content);
                frame.setLayout(new GridBagLayout());
                frame.add(pb);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                LoadMaster master = new LoadMaster();
                master.addPropertyChangeListener(new LoadMasterPropertyChanegHandler(SwingWorkerExample.this));
                master.execute();
            }
        });
    }

    protected void showProgress(int value) {
        pb.setValue(value);
    }

    protected void loadCompleted() {
        content.removeAll();
        content.setLayout(new GridLayout(0, 1));
        content.add(new JLabel("All your base are belong to us"));
        content.revalidate();

        LoadStuffWorker stuffWorker = new LoadStuffWorker(this);
        stuffWorker.execute();
    }

    protected void loadFailed() {
        content.removeAll();
        content.setLayout(new GridLayout(0, 1));
        content.add(new JLabel("Fail"));
        content.revalidate();
    }

    protected void setVersion(String value) {
        content.add(new JLabel("Version: " + value));
        content.revalidate();
    }

    protected void failed(String fail) {
        content.add(new JLabel(fail));
        content.revalidate();
    }

    public class LoadMaster extends SwingWorker<Void, Progress> {

        @Override
        protected Void doInBackground() throws Exception {
            System.out.println("Working hard here, nothing to see...");
            for (int index = 0; index < 100; index++) {
                Thread.sleep(10);
                setProgress(index);
            }
            return null;
        }

        @Override
        protected void done() {
            try {
                get();
            } catch (Exception e) {
            }
        }

    }

    public class LoadStuffWorker extends SwingWorker<String, Void> {

        private SwingWorkerExample example;

        public LoadStuffWorker(SwingWorkerExample example) {
            this.example = example;
        }

        @Override
        protected String doInBackground() throws Exception {
            System.out.println("Hanging about in the background");
            Thread.sleep(3000);
            return "Hello from the dark side";
        }

        @Override
        protected void done() {
            try {
                String value = get();
                example.setVersion(value);
            } catch (InterruptedException | ExecutionException ex) {
                example.failed("Fail while doing version check");
            }
        }

    }

    public class Progress {
    }

    public class LoadMasterPropertyChanegHandler implements PropertyChangeListener {

        private SwingWorkerExample example;

        public LoadMasterPropertyChanegHandler(SwingWorkerExample example) {
            this.example = example;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            System.out.println(evt.getPropertyName());
            if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
                int value = (int) evt.getNewValue();
                example.showProgress(value);
            } else if ("state".equalsIgnoreCase(evt.getPropertyName())) {
                SwingWorker worker = (SwingWorker) evt.getSource();
                if (worker.isDone()) {
                    try {
                        worker.get();
                        example.loadCompleted();
                    } catch (InterruptedException | ExecutionException exp) {
                        example.loadFailed();
                    }
                }
            }
        }

    }

}

【讨论】:

  • O.O more than I asked for upvote button of supreme awesome 在哪里。这是一个完全不同寻常的答案!谢谢!
  • @TrinaryAtom 以为我跑题了:P
  • 看完你的示例代码,吸收和学习之后,我有一个问题。您在同一工人的done()propertyChange() 中有get();。我猜想多少次都可以拨打get()?不管怎样,只删除LoadMaster 中的done() 可以吗?由于get() 已经在propertyChange() 中被调用。
  • 如果您不需要它,请了解自己。是的,您可以随意拨打get...
  • 只是检查,确保没有我遗漏的东西,再次非常感谢你。你真棒!
猜你喜欢
  • 1970-01-01
  • 2011-09-06
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多