【问题标题】:getting the cancel event of Java ProgressMonitor获取 Java ProgressMonitor 的取消事件
【发布时间】:2012-08-19 22:37:36
【问题描述】:

我有一个 ProgressMonitor pm 和一个 SwingWorker sw。当我按下pm 上的cancel 按钮时,我想取消 SwingWorker。我想这应该不会太难,我阅读了一些关于 SwingWorker 和 ProgressMonitor 的教程,但我无法让它工作。

final ProgressMonitor pm = new ProgressMonitor(frame, "checking", "...", 0, 100);
final SwingWorker sw = new SwingWorker()
{
    protected Object doInBackground() throws Exception 
    {
        doSomethingAndUpdateProgress();
    }
};

sw.addPropertyChangeListener(new PropertyChangeListener()
{
    public void propertyChange(PropertyChangeEvent evt)
    {
        if(evt.getPropertyName().equals("progress"))
        {
            updateProgress();
        }
        if(pm.isCanceled())
        {
            cancelAction();
        }
        if(pm.isDone())
        {
            doneAction();
        }
    }
});

sw.execute();

进度更新工作正常,但pm.isCanceled() 永远不是true。我想我需要一个用于 ProgressMonitor 的 propertyChangeListener,但我不知道如何在那里添加一个。

【问题讨论】:

    标签: java multithreading swing swingworker progressmonitor


    【解决方案1】:

    在执行长时间运行的任务期间,您希望定期检查 ProgressMonitor 是否被取消。您的工作是检查在哪些点取消任务是有意义的 - 否则谁知道您可能会挂起哪些资源。

    所以基本上,您想更改您的 doSomethingAndUpdateProgress() 方法,以便它还检查 ProgressMonitor 是否被取消。

    这是一个演示它是如何工作的演示:

    import java.awt.*;
    import javax.swing.*;
    
    public class TempProject extends Box{
    
        public TempProject(){
            super(BoxLayout.Y_AXIS);
            final ProgressMonitor pm = new ProgressMonitor(this, "checking", "...", 0, 100);
            final SwingWorker sw = new SwingWorker<Integer, Integer>()
            {
                protected Integer doInBackground() throws Exception 
                {
                    int i = 0;
                    //While still doing work and progress  monitor wasn't canceled
                     while (i++ < 100 && !pm.isCanceled()) {
                         System.out.println(i);
                         publish(i);
                         Thread.sleep(100);
                     }
                     return null;
                }
    
    
                 @Override
                 protected void process(java.util.List<Integer> chunks) {
                     for (int number : chunks) {
                         pm.setProgress(number);
                     }
                 }
    
            };
    
            sw.execute();
        }
    
    
        public static void main(String args[])
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                    frame.setContentPane(new TempProject());    
                    frame.pack();
                    frame.setVisible(true);
                }
            });
        }   
    
    
    }
    

    【讨论】:

    • 尽管 mKorbel 的回答提供了很多信息,但它缺少我实际询问的 ProgressMonitor - 所以我选择了这个作为答案。
    【解决方案2】:

    我阅读了一些关于 SwingWorker 和 ProgressMonitor 的教程,但我无法让它工作。

    取消总是调用 InteruptedExeption,

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.util.ArrayList;
    
    public class SwingWorkerExample extends JFrame implements ActionListener {
    
        private static final long serialVersionUID = 1L;
        private final JButton startButton, stopButton;
        private JScrollPane scrollPane = new JScrollPane();
        private JList listBox = null;
        private DefaultListModel listModel = new DefaultListModel();
        private final JProgressBar progressBar;
        private mySwingWorker swingWorker;
    
        public SwingWorkerExample() {
            super("SwingWorkerExample");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            getContentPane().setLayout(new GridLayout(2, 2));
            startButton = makeButton("Start");
            stopButton = makeButton("Stop");
            stopButton.setEnabled(false);
            progressBar = makeProgressBar(0, 99);
            listBox = new JList(listModel);
            scrollPane.setViewportView(listBox);
            getContentPane().add(scrollPane);
            //Display the window.
            pack();
            setVisible(true);
        }
    //Class SwingWorker<T,V> T - the result type returned by this SwingWorker's doInBackground
    //and get methods V - the type used for carrying out intermediate results by this SwingWorker's
    //publish and process methods
    
        private class mySwingWorker extends javax.swing.SwingWorker<ArrayList<Integer>, Integer> {
    //The first template argument, in this case, ArrayList<Integer>, is what s returned by doInBackground(),
    //and by get(). The second template argument, in this case, Integer, is what is published with the
    //publish method. It is also the data type which is stored by the java.util.List that is the parameter
    //for the process method, which recieves the information published by the publish method.
    
            @Override
            protected ArrayList<Integer> doInBackground() {
    //Returns items of the type given as the first template argument to the SwingWorker class.
                if (javax.swing.SwingUtilities.isEventDispatchThread()) {
                    System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() returned true.");
                }
                Integer tmpValue = new Integer(1);
                ArrayList<Integer> list = new ArrayList<Integer>();
                for (int i = 0; i < 100; i++) {
                    for (int j = 0; j < 100; j++) { //find every 100th prime, just to make it slower
                        tmpValue = FindNextPrime(tmpValue.intValue());
    //isCancelled() returns true if the cancel() method is invoked on this class. That is the proper way
    //to stop this thread. See the actionPerformed method.
                        if (isCancelled()) {
                            System.out.println("SwingWorker - isCancelled");
                            return list;
                        }
                    }
    //Successive calls to publish are coalesced into a java.util.List, which is what is received by process,
    //which in this case, isused to update the JProgressBar. Thus, the values passed to publish range from
    //1 to 100.
                    publish(new Integer(i));
                    list.add(tmpValue);
                }
                return list;
            }//Note, always use java.util.List here, or it will use the wrong list.
    
            @Override
            protected void process(java.util.List<Integer> progressList) {
    //This method is processing a java.util.List of items given as successive arguments to the publish method.
    //Note that these calls are coalesced into a java.util.List. This list holds items of the type given as the
    //second template parameter type to SwingWorker. Note that the get method below has nothing to do with the
    //SwingWorker get method; it is the List's get method. This would be a good place to update a progress bar.
                if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
                    System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
                }
                Integer percentComplete = progressList.get(progressList.size() - 1);
                progressBar.setValue(percentComplete.intValue());
            }
    
            @Override
            protected void done() {
                System.out.println("doInBackground is complete");
                if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
                    System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
                }
                try {
    //Here, the SwingWorker's get method returns an item of the same type as specified as the first type parameter
    //given to the SwingWorker class.
                    ArrayList<Integer> results = get();
                    for (Integer i : results) {
                        listModel.addElement(i.toString());
                    }
                } catch (Exception e) {
                    System.out.println("Caught an exception: " + e);
                }
                startButton();
            }
    
            boolean IsPrime(int num) { //Checks whether a number is prime
                int i;
                for (i = 2; i <= num / 2; i++) {
                    if (num % i == 0) {
                        return false;
                    }
                }
                return true;
            }
    
            protected Integer FindNextPrime(int num) { //Returns next prime number from passed arg.
                do {
                    if (num % 2 == 0) {
                        num++;
                    } else {
                        num += 2;
                    }
                } while (!IsPrime(num));
                return new Integer(num);
            }
        }
    
        private class TaskListener implements PropertyChangeListener {
    
            private String name;
    
            TaskListener(String name) {
                this.name = name;
            }
    
            @Override
            public void propertyChange(PropertyChangeEvent e) {
                System.out.println(name + ": "
                        + e.getOldValue() + " -> " + e.getNewValue());
            }
        }
    
        private JButton makeButton(String caption) {
            JButton b = new JButton(caption);
            b.setActionCommand(caption);
            b.addActionListener(this);
            getContentPane().add(b);
            return b;
        }
    
        private JProgressBar makeProgressBar(int min, int max) {
            JProgressBar progressBar1 = new JProgressBar();
            progressBar1.setMinimum(min);
            progressBar1.setMaximum(max);
            progressBar1.setStringPainted(true);
            progressBar1.setBorderPainted(true);
            getContentPane().add(progressBar1);
            return progressBar1;
        }
    
        private void startButton() {
            startButton.setEnabled(true);
            stopButton.setEnabled(false);
            System.out.println("SwingWorker - Done");
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) {
                startButton.setEnabled(false);
                stopButton.setEnabled(true);
    // Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
                (swingWorker = new mySwingWorker()).execute(); // new instance
                swingWorker.addPropertyChangeListener(new TaskListener("Task"));
    
            } else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) {
                startButton.setEnabled(true);
                stopButton.setEnabled(false);
                swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
                swingWorker = null;
            }
        }
    
        public static void main(String[] args) {
    // Notice that it kicks it off on the event-dispatching thread, not the main thread.
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    SwingWorkerExample swingWorkerExample = new SwingWorkerExample();
                }
            });
        }
    }
    

    【讨论】:

    • @Andrew Thompson 这些 cmets 来自 ateraidarryl 我来自 sun.forum.57 的问题