【问题标题】:Catch Exception thrown by a SwingWorker located in a different class捕获位于不同类中的 SwingWorker 引发的异常
【发布时间】:2012-02-29 15:43:52
【问题描述】:

我有一个主类 Gui,它处理我的 GUI 并调用一些 SwingWorkers(对 DB 和其他数据源的调用),这些类已经放在他们自己的类 TablesDataManager 中。我的问题是,当其中一个swingworkers 在其done90 方法中(即在EDT 上)抛出异常时,我希望能够在主类中以某种方式捕获它并采取相应的行动(在下面的SSCCE 中调用showErrorAndExit)。

欢迎提出任何想法。

Gui.java

import java.awt.event.WindowEvent;
import javax.swing.*;

public class Gui extends JFrame {

    private final JLabel waitLabel = new JLabel();
    private final JPanel panel = new JPanel();
    private final TablesDataManager tblData = new TablesDataManager();

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                createAndShowGui();
            }
        });
    }

    private static void createAndShowGui() {
        Gui frame = new Gui("My Great GUI");
        frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public Gui(String title) {
        super(title);
        panel.add(waitLabel);
        setContentPane(panel);
        try {
            initData();
        } catch (Exception e) {
            showErrorAndExit(e);
        }
    }

    //I WANT TO CALL THIS METHOD IF done() THROWS AN EXCEPTION
    private void showErrorAndExit(Exception e) {
        JOptionPane.showMessageDialog(this,
                "An unexpected error occured while initialising the tables. The application will close.\n"
                + (e.getMessage() == null ? "" : e.getMessage()),
                "Unrecoverable error",
                JOptionPane.ERROR_MESSAGE);
        this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
    }

    private void initData() {
        waitLabel.setText("Loading Data");
        tblData.initData(new Runnable() {

            public void run() {
                initTables();
            }
        });
    }

    private void initTables() {
        waitLabel.setText("Loading Tables");
        tblData.initTables(new Runnable() {

            public void run() {
                finishComponentsSetup();
            }
        });
    }

    private void finishComponentsSetup() {
        waitLabel.setText("We are done");
    }
}

TablesDataManager.java

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;

class TablesDataManager {

    private final InitData initData = new InitData();
    private final InitTables initTables = new InitTables();

    void initData(final Runnable runAfterInit) {
        launchWorker(initData, runAfterInit);
    }

    void initTables(final Runnable runAfterInit) {
        launchWorker(initTables, runAfterInit);
    }

    private void launchWorker(final SimpleSwingWorker worker, final Runnable runAfterWorkerDone) {
        worker.addPropertyChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals("progress")) {
                    if (worker.getProgress() == 100) { //update finished
                        runAfterWorkerDone.run();
                    }
                }
            }
        });
        worker.execute();
    }

    private class InitData extends SimpleSwingWorker {

        @Override
        protected Void doInBackground() throws Exception {
            //do something in the background
            //unfortunately there is a connection problem
            throw new IOException("Can't connect to database...");
        }
    }

    private class InitTables extends SimpleSwingWorker {

        @Override
        protected Void doInBackground() throws Exception {
            //do something else in the background
            return null;
        }
    }


    private abstract class SimpleSwingWorker extends SwingWorker<Void, Void>  {

        @Override
        protected abstract Void doInBackground() throws Exception;

        @Override
        public void done() {
            try {
                get();
                setProgress(100);
            } catch (ExecutionException | InterruptedException e) {
                System.out.println("Got that?");
                //WHAT DO I DO WITH IT???
                throw new RuntimeException(e);
            }
        }
    }
}

【问题讨论】:

  • somehow I disregarded this question,命名线程,命名,命名取决于异常类型,否则您可能会丢失参考,嗯,我不同意这里的答案
  • 使用Executor 限制并发运行的线程数
  • @mKorbel 感谢您的链接 - 我会看看。

标签: java swing swingworker


【解决方案1】:

在您的 GUI 中保留对您的工作人员的引用,并在您的工作中添加一个 try catch。在 catch 中将异常分配给一个变量并为其添加一个 getter。在您的 GUI 中,当您的工作人员完成后,只需检查工作人员中是否存在异常。

【讨论】:

    【解决方案2】:

    我现在正在使用的另一种选择(耦合度稍低)是让工作人员触发 propertyChange,但 newValue 除外

    @Override
    protected void done() {
        try {
            get();
        } catch (Exception e) {
            firePropertyChange("done-exception", null, e);
        }
    }
    

    【讨论】:

    • 我知道我尝试过,但在实际发生异常时找不到正确捕获更改的方法。我再看看。谢谢。
    • hmm ...您的意思是它没有被触发到 PropertyChangeListener?如果是这样,我会对您再次查看的结果感兴趣,很可能是我忽略了一些东西:-)
    • 类似的东西是的 - 但我没有花太多时间在这上面,因为 Guillaume 提出了他的简单高效的解决方案。
    猜你喜欢
    • 2012-02-07
    • 1970-01-01
    • 2018-01-04
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 2014-07-09
    • 1970-01-01
    • 2012-06-05
    相关资源
    最近更新 更多