如何从SwingWorker类返回值并在其他类中使用并在进程完成时启用MenuItem?

时间:2015-09-27 11:39:00

标签: java swing swingworker

我正在使用SwingWorker类来使进程在另一个线程中运行。我想要的是,一旦这个线程完成处理,它应该返回String并且它应该启用JMenuItem。我使用done()类中的SwingWorker方法来启用JMenuItem但我收到了NullPinterExceptiondoInBackground()方法返回一个我想在主GUI类中访问的String - GUIMain.java,它出现在同一个包中。我该怎么办?我看到很多实现done()onPostExecute()方法的例子,但我认为我在某处出错了。这是我实施的代码:

 public class GUIMain extends JFrame implements ActionListener, FocusListener, ItemListener, MouseListener, MouseMotionListener {

        private JMenuBar menuBar;    // Defined a menuBar item
        private JMenu recalibrationMenu;  // Define the recalibration menu item
        private JMenuItem CGMenuItem;
        private JMenuItem TGMenuItem;
        private JMenu viewResultsMenu;  // Define the View Results menu item
        public JMenuItem cgResults;
        public JMenuItem tgResults;    
        private JPanel TGImage;
        private JPanel TGPanel;
        private JPanel CGImage;
        private JPanel CGPanel;
        private JPanel CGRecalibrationParameters;

        private JDialog resultsParameters;
        private JLabel massPeakLabel = new JLabel("Select mass peak (m/z)");
        private JTextField massPeakField = new JTextField(5);
        private JLabel massWindowLabel = new JLabel("Mass window (Da)");
        private JTextField massWindowField = new JTextField(5);
        private float mzPeakValue;
        private float massWindowValue;
        private JButton massPeakSelectionButton = new JButton("OK");
        private JButton CloseDialogButton = new JButton("Cancel");
        private String CGRecalibratedFilesPath;
        private String TGRecalibratedFilesPath;


        /** Constructor to setup the GUI */
        public GUIMain(String title) {

            super(title);
            setLayout(new BorderLayout());



            menuBar = new JMenuBar();
            menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));

            // build the Recalibration menu
            recalibrationMenu = new JMenu("Recalibration");
            CGMenuItem = new JMenuItem("Crystal Growth");
            CGMenuItem.setEnabled(false); //initially disabled when app is launched
            CGMenuItem.addActionListener(this);

            TGMenuItem = new JMenuItem("Topological Greedy");
            TGMenuItem.setEnabled(false); //initially disabled when app is launched
            TGMenuItem.addActionListener(this);

            recalibrationMenu.add(CGMenuItem);
            recalibrationMenu.add(TGMenuItem);

            // build the View Results menu
            viewResultsMenu = new JMenu("View Results");
            cgResults = new JMenuItem("CG Recalibration");
            cgResults.setEnabled(false); //initially disabled when app is launched
            cgResults.addActionListener(this);
            tgResults = new JMenuItem("TG Recalibration");
            tgResults.setEnabled(false); //initially disabled when app is launched
            tgResults.addActionListener(this);

            viewResultsMenu.add(cgResults);
            viewResultsMenu.add(tgResults);

            // add menus to menubar
            menuBar.add(fileMenu);
            menuBar.add(recalibrationMenu);
            menuBar.add(viewResultsMenu);


            // put the menubar on the frame
            setJMenuBar(menuBar);      

            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exit program if close-window button clicked
            setPreferredSize(new Dimension(1300, 800)); // Set the preferred window size
            pack();
            setLocationRelativeTo(null);
            setVisible(true);
        }

        public GUIMain()
        {

        } 
    }


        public void actionPerformed(ActionEvent e) {

            //Handle CG menu item action
            **if ((e.getSource() == CGMenuItem)) {
                RecalibrationWorker rw = new RecalibrationWorker(file,"CG");
                rw.processCompleted();
                rw.setVisible(true);
                cgResults.setEnabled(true);
            }**


            if ((e.getSource() == cgResults)) {
                viewRecalibrationResults("CG Recalibration - View Results", "CG");
            }

            if ((e.getSource() == tgResults)) {
                viewRecalibrationResults("TG Recalibration - View Results", "TG");
            }

        }


        private void viewRecalibrationResults(String dialogTitle, final String recalibrationType) {
            resultsParameters = new JDialog();
            resultsParameters.setLayout(new GridBagLayout());
            resultsParameters.setTitle(dialogTitle);
            GridBagConstraints gc = new GridBagConstraints();

            gc.gridx = 0;
            gc.gridy = 0;
            gc.anchor = GridBagConstraints.WEST;

            gc.ipady = 20;
            // gc.anchor = GridBagConstraints.WEST;
            resultsParameters.add(massPeakLabel, gc);
            commonMassThresholdLabel.setLabelFor(massPeakField);

            gc.gridx = 1;
            gc.gridy = 0;
            gc.ipady = 0;
            gc.anchor = GridBagConstraints.CENTER;
            resultsParameters.add(massPeakField,gc);
            massPeakField.setText("");
            massPeakField.addActionListener(this);
            massPeakField.addFocusListener(this);

            gc.gridx = 0;
            gc.gridy = 1;
            gc.ipady = 20;
            gc.anchor = GridBagConstraints.WEST;
            resultsParameters.add(massWindowLabel, gc);
            massWindowLabel.setLabelFor(massWindowField);

            gc.gridx = 1;
            gc.gridy = 1;
            gc.ipady = 0;
            gc.anchor = GridBagConstraints.CENTER;
            resultsParameters.add(massWindowField,gc);
            massWindowField.setText("");
            massWindowField.addActionListener(this);
            massWindowField.addFocusListener(this);


            gc.gridx = 0;
            gc.gridy = 2;
            gc.anchor = GridBagConstraints.CENTER;
            resultsParameters.add(massPeakSelectionButton, gc);

            massPeakSelectionButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if ("CG".equals(recalibrationType))
                        recalibrationResults("CG");

                    else if ("TG".equals(recalibrationType))
                        recalibrationResults("TG");
                }
            });

            massPeakSelectionButton.addKeyListener(new KeyListener() {
                @Override
                public void keyTyped(KeyEvent e) {

                }

                @Override
                public void keyPressed(KeyEvent e) {

                    if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                        if ("CG".equals(recalibrationType))
                            recalibrationResults("CG");

                        else if ("TG".equals(recalibrationType))
                            recalibrationResults("TG");
                    }
                }

                @Override
                public void keyReleased(KeyEvent e) {

                }
            });

            gc.gridx = 1;
            gc.gridy = 2;
            gc.anchor = GridBagConstraints.EAST;
            resultsParameters.add(CloseDialogButton,gc);
            CloseDialogButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    resultsParameters.dispose();
                }
            });

            resultsParameters.setVisible(true);
            resultsParameters.setLocationRelativeTo(this);
            resultsParameters.setSize(270, 150);
            resultsParameters.setResizable(false);
        }
    }


public class RecalibrationWorker extends JDialog {

    private boolean isStarted = false;
    private JLabel counterLabel = new JLabel("Recalibration not yet started");
    private Worker worker = new Worker();
    private JPanel recalibrationParameters;
    private ButtonGroup radioButtonGroup = new ButtonGroup();
    private JRadioButton rawSpectra = new JRadioButton("Use raw spectra");
    private JRadioButton preprocessedSpectra = new JRadioButton("Use preprocessed spectra");
    private static float commonMassThresholdValue;
    private static float recalibrationThresholdValue;
    private static double mergeSpectraThresholdValue;
    private JLabel commonMassThresholdLabel = new JLabel("<html>Common Mass Window<br>(value between 0.01-0.9 Da)</html>");
    private JTextField commonMassThresholdField = new JTextField(String.valueOf(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            commonMassThresholdValue = Float.parseFloat(commonMassThresholdField.getText());
            recalibrationThresholdField.requestFocusInWindow();

        }
    }));
    private JLabel recalibrationThresholdLabel = new JLabel("<html>Mass threshold to recalibrate two spectra<br>(value between 0.01-0.9 Da)</html>");
    private JTextField recalibrationThresholdField = new JTextField(String.valueOf(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            recalibrationThresholdValue = Float.parseFloat(recalibrationThresholdField.getText());
            mergeSpectraThresholdField.requestFocusInWindow();

        }
    }));
    private JLabel mergeSpectraThresholdLabel = new JLabel("<html>Mass threshold to merge spectra<br>(value between 0.01-0.9 Da)</html>");
    private JTextField mergeSpectraThresholdField= new JTextField(String.valueOf(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            mergeSpectraThresholdValue = Float.parseFloat(mergeSpectraThresholdField.getText());
            startButton.requestFocusInWindow();

        }
    }));
    private JTextArea recalibrationStatus = new JTextArea(7,32);
    private JScrollPane textAreaScrolling = new JScrollPane(recalibrationStatus);


    private JButton startButton = new JButton(new AbstractAction("Recalibrate") {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            if(!isStarted) {
                Worker w = new Worker();
                w.addPropertyChangeListener(new RecalibrationWorkerPropertyHandler(RecalibrationWorker.this));
                w.execute();
                isStarted = false;
            }
        }

    });
    private JButton stopButton = new JButton(new AbstractAction("Stop") {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            worker.cancel(true);
        }

    });

    public File file;
    public String type;
    public String resultFilePath;


    public RecalibrationWorker(File dataFile, String recalibrationType) {

        file = dataFile;
        type = recalibrationType;

        setLayout(new GridBagLayout());
        if("CG".equals(recalibrationType))
            setTitle("Crystal Growth Recalibration");
        else if("TG".equals(recalibrationType))
            setTitle("Topological Greedy Recalibration");

        recalibrationParameters = new JPanel(new GridBagLayout());
        GridBagConstraints gc = new GridBagConstraints();

        radioButtonGroup.add(rawSpectra);
        radioButtonGroup.add(preprocessedSpectra);

        gc.gridx = 0;
        gc.gridy = 0;
        gc.anchor = GridBagConstraints.WEST;
        recalibrationParameters.add(preprocessedSpectra,gc);

        gc.gridx = 1;
        gc.gridy = 0;
        recalibrationParameters.add(rawSpectra,gc);

        gc.gridx = 0;
        gc.gridy = 1;
        gc.ipady = 20;
        gc.anchor = GridBagConstraints.WEST;
        recalibrationParameters.add(commonMassThresholdLabel, gc);
        commonMassThresholdLabel.setLabelFor(commonMassThresholdField);
        commonMassThresholdField.setColumns(3);
        commonMassThresholdField.setText("");

        gc.gridx = 1;
        gc.gridy = 1;
        gc.ipady = 0;
        gc.anchor = GridBagConstraints.CENTER;
        recalibrationParameters.add(commonMassThresholdField, gc);
        commonMassThresholdField.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {

            }

            @Override
            public void focusLost(FocusEvent e) {
                commonMassThresholdValue = Float.parseFloat(commonMassThresholdField.getText());
                recalibrationThresholdField.requestFocusInWindow();
            }
        });

        gc.gridx = 0;
        gc.gridy = 2;
        gc.ipady = 20;
        gc.anchor = GridBagConstraints.WEST;
        recalibrationParameters.add(recalibrationThresholdLabel, gc);
        recalibrationThresholdLabel.setLabelFor(recalibrationThresholdField);
        recalibrationThresholdField.setColumns(3);
        recalibrationThresholdField.setText("");

        gc.gridx = 1;
        gc.gridy = 2;
        gc.ipady = 0;
        gc.anchor = GridBagConstraints.CENTER;
        recalibrationParameters.add(recalibrationThresholdField, gc);
        recalibrationThresholdField.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {

            }

            @Override
            public void focusLost(FocusEvent e) {
                recalibrationThresholdValue = Float.parseFloat(recalibrationThresholdField.getText());
                mergeSpectraThresholdField.requestFocusInWindow();
            }
        });

        gc.gridx = 0;
        gc.gridy = 3;
        gc.ipady = 20;
        gc.anchor = GridBagConstraints.WEST;
        recalibrationParameters.add(mergeSpectraThresholdLabel, gc);
        mergeSpectraThresholdLabel.setLabelFor(mergeSpectraThresholdField);
        mergeSpectraThresholdField.setText("");

        gc.gridx = 1;
        gc.gridy = 3;
        gc.ipady = 0;
        gc.anchor = GridBagConstraints.CENTER;
        recalibrationParameters.add(mergeSpectraThresholdField, gc);
        mergeSpectraThresholdField.setColumns(3);
        mergeSpectraThresholdField.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {

            }

            @Override
            public void focusLost(FocusEvent e) {
                mergeSpectraThresholdValue = Double.parseDouble(mergeSpectraThresholdField.getText());
                startButton.requestFocusInWindow();
            }
        });

        recalibrationParameters.setBorder(
                BorderFactory.createCompoundBorder(
                        BorderFactory.createTitledBorder("Parameters"),
                        BorderFactory.createEmptyBorder(5, 5, 5, 5)));

        gc.gridx = 0;
        gc.gridy = 4;
        gc.anchor = GridBagConstraints.EAST;
        recalibrationParameters.add(startButton, gc);

        gc.gridx = 1;
        gc.gridy = 4;
        gc.anchor = GridBagConstraints.WEST;
        recalibrationParameters.add(stopButton, gc);

        gc.gridx = 0;
        gc.gridy = 0;
        gc.anchor = GridBagConstraints.CENTER;
        add(recalibrationParameters, gc);

        textAreaScrolling.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder("Recalibration status"),
                BorderFactory.createEmptyBorder(5, 5, 5, 5)));

        gc.gridx = 0;
        gc.gridy = 1;
        gc.anchor = GridBagConstraints.CENTER;
        add(textAreaScrolling, gc);

        recalibrationStatus.setWrapStyleWord(true);
        recalibrationStatus.setLineWrap(true);
        recalibrationStatus.setEditable(false);

        setVisible(true);
        setLocationRelativeTo(this);
        setSize(415, 425);
        setResizable(false);
        pack();
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

    }

    // constructor
    public RecalibrationWorker()
    {

    }

    public float commonMassThreshold() {
        return commonMassThresholdValue;
    }

    public float recalibrationThreshold() {
        return recalibrationThresholdValue;
    }

    public double mergeSpectraThreshold() {
        return mergeSpectraThresholdValue;
    }

    protected String processCompleted() {
        return resultFilePath;
    }

    protected void processFailed() {
        System.out.println("Recalibration failed");
    }



    class Worker extends SwingWorker<String,String> {


      //  String  resultfilePath;

        @Override
        public String doInBackground() throws Exception {

            InputData inputDataObject1 = new InputData();
            if(type == "CG")
            {
                resultFilePath = inputDataObject1.startRecalibration(file, type);
                publish("Recalibration Successful!\nFiles can be found at: " + resultFilePath);
            }
            else if (type == "TG")
            {
                resultFilePath = inputDataObject1.startRecalibration(file, type);
                publish("Recalibration Successful!\nFiles can be found at: " + resultFilePath);
            }
            return resultFilePath;
        }

       public void done() {
           try {
               get();
           } catch (Exception e) {
           }
       }

        @Override
        protected void process(java.util.List<String> chunks) {
            String value = chunks.get(chunks.size() - 1);
            recalibrationStatus.append("\n"+value);
            // recalibrationStatus.append(chunks.toString());
        }

    }

import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;

/**
 * Created by localadm on 27/09/15.
 */
public class RecalibrationWorkerPropertyHandler implements PropertyChangeListener {

    private RecalibrationWorker rwObject;

    public RecalibrationWorkerPropertyHandler(RecalibrationWorker rwObject) {
        this.rwObject = rwObject;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
      //  System.out.println(evt.getPropertyName());
        if ("progress".equalsIgnoreCase(evt.getPropertyName())) {
            //  int value = (int) evt.getNewValue();
            // rwObject.showProgress(value);
        } else if ("state".equalsIgnoreCase(evt.getPropertyName())) {
            SwingWorker worker = (SwingWorker) evt.getSource();
            if (worker.isDone()) {
                try {
                    worker.get();
                    System.out.println("I am here");
                    rwObject.processCompleted();
                } catch (InterruptedException exp) {
                    rwObject.processFailed();
                } catch (ExecutionException e) {
                    rwObject.processFailed();
                }
            }
        }
    }

}

1 个答案:

答案 0 :(得分:4)

由于您使用JDialog来管理SwingWorker,因此您可以实际使用对话框的模态状态。

基本上,当一个对话框是模态的时,它将阻止对话框执行,使对话框可见。它将一直阻塞,直到隐藏对话框,此时代码将继续执行。

因此,您可以在对话框可见之前禁用该按钮,并在对话框关闭时重新启用它。

Worker

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

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

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            JButton btn = new JButton("Go");
            add(btn);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    btn.setEnabled(false);
                    SomeWorkerDialog worker = new SomeWorkerDialog(TestPane.this);
                    // This is just so we can see the button ;)
                    Point point = btn.getLocationOnScreen();
                    worker.setLocation(worker.getX(), point.y + btn.getHeight());
                    worker.setVisible(true);
                    btn.setEnabled(true);
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class SomeWorkerDialog extends JDialog {

        private JProgressBar progressBar;
        private SomeWorkerSomeWhere worker;


        public SomeWorkerDialog(JComponent parent) {
            super(SwingUtilities.getWindowAncestor(parent), "Working Hard", DEFAULT_MODALITY_TYPE);

            progressBar = new JProgressBar();
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1;
            gbc.insets = new Insets(10, 10, 10, 10);

            add(progressBar, gbc);

            worker = new SomeWorkerSomeWhere();
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    String name = evt.getPropertyName();
                    switch (name) {
                        case "state":
                            switch (worker.getState()) {
                                case DONE:
                                    setVisible(false);
                                    break;
                            }
                            break;
                        case "progress":
                            progressBar.setValue(worker.getProgress());
                            break;
                    }
                }
            });

            addWindowListener(new WindowAdapter() {

                @Override
                public void windowOpened(WindowEvent e) {
                    worker.execute();
                }

                @Override
                public void windowClosed(WindowEvent e) {
                    worker.cancel(true);
                }

            });

            pack();
            setLocationRelativeTo(parent);

        }

    }

    public class SomeWorkerSomeWhere extends SwingWorker {

        @Override
        protected Object doInBackground() throws Exception {
            for (int index = 0; index < 100 && !isCancelled(); index++) {
                setProgress(index);
                Thread.sleep(10);
            }
            return "AllDone";
        }

    }

}

<强>更新

要获取工作返回的值,可以在对话框中添加一个返回计算值的方法...

public String getValue() throws Exception {
    return worker.get()
}

因此,一旦关闭对话框并继续执行代码,您就可以启用所需的组件并调用getValue方法

您还可以在状态更改并通知PropertyChangeListener时存储结果