Search code examples
javaswingjoptionpaneswingworker

How to prompt a JOptionPane after SwingWorker task is complete


I'm trying to learn SwingWorker and I have this simple code running and working, but I can't figure out how to prompt a JOptionPane.showMessageDialog when the task is complete. I've to tried to put

if (isDone())
    JOptionPane.showMessageDialog(null, "Task Complete");

in different locations, but can't get anything to work. I've read that I may have to put it in the invokeLater() for it to run in the EDT, I'm not really sure how to accomplish that.

I tried to have my SwingWorker as a class member of my panel, but I can't instantiate it because it gets intantiaated in a listener. So I get a null pointer trying to put if (task.isDone()) in my invokeLater().

What is the proper way to accomplish this task?

I have an SSCCE here (all you do is enter a number and it prints my name that many times to a text area).

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.*;

public class RepeatNameSwingWorker extends JPanel {

    private JProgressBar jpb = new JProgressBar(0, 100);
    private JTextArea jtaNames = new JTextArea(20, 50);
    private final JTextField jtfTimes = new JTextField(8);
    private final JButton jbtExecute = new JButton("Execute");
    private final JLabel jlblNumTimes = new JLabel("Enter number of times: ");

    public RepeatNameSwingWorker(){
        jpb.setStringPainted(true);

        jtaNames.setLineWrap(true);
        jtaNames.setWrapStyleWord(true);

        JPanel panel = new JPanel();
        panel.add(jlblNumTimes);
        panel.add(jtfTimes);
        panel.add(jbtExecute);

        setLayout(new BorderLayout());
        add(jpb, BorderLayout.NORTH);
        add(new JScrollPane(jtaNames), BorderLayout.CENTER);
        add(panel, BorderLayout.SOUTH);

        jbtExecute.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                RepeatNames task = new RepeatNames(
                        Integer.parseInt(jtfTimes.getText()), jtaNames);

                task.addPropertyChangeListener(new PropertyChangeListener(){
                    @Override
                    public void propertyChange(PropertyChangeEvent e) {
                        if ("progress".equals(e.getPropertyName())) {
                            jpb.setValue((Integer)e.getNewValue());
                        }
                    }
                });
                task.execute();
                if (task.isDone())
                    JOptionPane.showMessageDialog(null, "Task Complete");
            }
        });

    }

    static class RepeatNames extends SwingWorker<String, String>{
        int times;
        JTextArea result;

        public RepeatNames(int times, JTextArea result) {
            this.times = times;
            this.result = result;
        }

        @Override
        protected String doInBackground(){
            publishNames(times);

            return null;
        }

        @Override
        protected void done() {
            try {
                result.append(get().toString()); // Display in text field
            } catch (Exception ex) {
                result.append(ex.getMessage());
            }
        }

        @Override
        protected void process(List<String> list) {
            for (int i = 0; i < list.size(); i++) {
                result.append(list.get(i) + " ");
            }
        }

        private void publishNames(int n) {
            int count = 0; 
            int number = 2;

            while (count <= n) {

                if (isPrime(number)) {
                    count++; 
                    setProgress(100 * count / n); 
                    publish("Paul");
                }
                number++;
            }
        }

        private static boolean isPrime(int number) {
            for (int divisor = 2; divisor <= number / 2; divisor++) {
                if (number % divisor == 0) { 
                    return false; 
                }
            }
            return true; 
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new RepeatNameSwingWorker());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLocationByPlatform(true);
                frame.pack();
                frame.setVisible(true);

            }
        });
    }
}

Solution

  • , but I can't figure out how to prompt a JOptionPane.showMessageDialog when the task is complete

    Show the JOptionPane in the done() method.