Catch Exception thrown by a SwingWorker located in a different class

岁酱吖の 提交于 2020-01-14 14:21:29

问题


I have a main class Gui that handles my GUI and calls a few SwingWorkers (calls to DB and other data sources) that have been put in their own class TablesDataManager. My issue is that when one of those swingworkers throws an exception within its done90 method (i.e. on the EDT), I want to be able to catch it somehow in the main class and act accordingly (call showErrorAndExit in my SSCCE below).

Any ideas would be welcome.

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);
            }
        }
    }
}

回答1:


Keep a reference to your workers in your GUI and in your workes add a try catch. In the catch assign the exception to a variable and add a getter to it. IN your GUI, when your worker is done, just check if there is an exception in the worker or not.




回答2:


An alternative (with slightly lower coupling) I'm nowadays playing with is to let the worker fire a propertyChange with the exception as newValue

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


来源:https://stackoverflow.com/questions/9502149/catch-exception-thrown-by-a-swingworker-located-in-a-different-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!