Java 暂停并继续SwingWorker.doInBackground()的操作

Java 暂停并继续SwingWorker.doInBackground()的操作,java,multithreading,swing,swingworker,Java,Multithreading,Swing,Swingworker,我有一个基本的Swing UI,有一个标记为“播放”的按钮。当按下按钮时,标签变为“暂停”。现在按下按钮时,它会变为“恢复” 在“播放”中,我实例化并执行一个SwingWorker。我想要的是能够暂停这个线程(而不是取消它),并根据上面描述的按钮按下恢复它。但是,我不想求助于doInBackground()中的Thread.sleep()。这似乎有点老套。运行doInBackground的线程是否有阻止的方法 暂停并继续SwingWorker.doInBackground()的操作 首先,你必须

我有一个基本的Swing UI,有一个标记为“播放”的按钮。当按下按钮时,标签变为“暂停”。现在按下按钮时,它会变为“恢复”

在“播放”中,我实例化并执行一个SwingWorker。我想要的是能够暂停这个线程(而不是取消它),并根据上面描述的按钮按下恢复它。但是,我不想求助于doInBackground()中的Thread.sleep()。这似乎有点老套。运行doInBackground的线程是否有阻止的方法

暂停并继续SwingWorker.doInBackground()的操作

首先,你必须确保正在执行的后台任务可以暂停,否则这个问题就没有意义了。假设任务可以暂停,那么您可以扩展类并使用一个简单的标志变量来控制后台线程状态:暂停或未暂停,从而创建自己的可暂停工作线程

您还可以向worker添加一个,并侦听
暂停的
属性更改:

worker.addPropertyChangeListener(new PropertyChangeListener() {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if ("paused".equals(evt.getPropertyName())) {
           System.out.println("Old status: " + evt.getOldValue());
           System.out.println("New status: " + evt.getNewValue());
        }
    }
});

示例(更新以使用PropertyChangeListener) 下面是一个完整的示例。请注意,如果工作进程已停止,则无法再暂停或恢复

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class Demo {

    private void createAndShowGUI() {

        final JTextArea textArea = new JTextArea(20, 50);

        final PausableSwingWorker<Void, String> worker = new PausableSwingWorker<Void, String>() {
            @Override
            protected Void doInBackground() throws Exception {
                while (!isCancelled()) {
                    if (!isPaused()) {
                        publish("Writing...");
                    } else {
                        Thread.sleep(200);
                    }
                }
                return null;
            }

            @Override
            protected void process(List<String> chunks) {
                String text = String.format("%s%n", chunks.get(chunks.size() - 1));
                textArea.append(text);
            }
        };

        worker.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ("paused".equals(evt.getPropertyName())) {
                    String text = (Boolean)evt.getNewValue() ? "Paused..." : "Resumed...";
                    textArea.append(String.format("%s%n", text));
                }
            }
        });

        Action pause = new AbstractAction("Pause") {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker.pause();
            }
        };

        Action resume = new AbstractAction("Resume") {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker.resume();
            }
        };

        Action stop = new AbstractAction("Stop") {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker.cancel(true);
            }
        };

        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        buttonsPanel.add(new JButton(pause));
        buttonsPanel.add(new JButton(resume));
        buttonsPanel.add(new JButton(stop));

        JPanel content = new JPanel(new BorderLayout(8, 8));
        content.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        content.add(new JScrollPane(textArea), BorderLayout.CENTER);
        content.add(buttonsPanel, BorderLayout.SOUTH);

        JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                if (!worker.isDone()) {
                    worker.cancel(true);
                }
                e.getWindow().dispose();
            }
        });

        frame.add(content);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

        worker.execute();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Demo().createAndShowGUI();
            }
        });
    }

    abstract class PausableSwingWorker<K, V> extends SwingWorker<K, V> {

        private volatile boolean isPaused;

        public final void pause() {
            if (!isPaused() && !isDone()) {
                isPaused = true;
                firePropertyChange("paused", false, true);
            }
        }

        public final void resume() {
            if (isPaused() && !isDone()) {
                isPaused = false;
                firePropertyChange("paused", true, false);
            }
        }

        public final boolean isPaused() {
            return isPaused;
        }
    }
}
导入java.awt.BorderLayout;
导入java.awt.FlowLayout;
导入java.awt.event.ActionEvent;
导入java.awt.event.WindowAdapter;
导入java.awt.event.WindowEvent;
导入java.beans.PropertyChangeEvent;
导入java.beans.PropertyChangeListener;
导入java.util.List;
导入javax.swing.AbstractAction;
导入javax.swing.Action;
导入javax.swing.BorderFactory;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.JTextArea;
导入javax.swing.SwingUtilities;
导入javax.swing.SwingWorker;
公开课演示{
私有void createAndShowGUI(){
最终JTextArea textArea=新的JTextArea(20,50);
最终PausableSwingWorker工作者=新的PausableSwingWorker(){
@凌驾
受保护的Void doInBackground()引发异常{
而(!isCancelled()){
如果(!isPaused()){
出版(“写作…”);
}否则{
睡眠(200);
}
}
返回null;
}
@凌驾
受保护的无效进程(列表块){
String text=String.format(“%s%n”,chunks.get(chunks.size()-1));
textArea.append(文本);
}
};
worker.addPropertyChangeListener(新的PropertyChangeListener(){
@凌驾
公共作废属性更改(属性更改事件evt){
如果(“暂停”。等于(evt.getPropertyName()){
字符串文本=(布尔值)evt.getNewValue()?“暂停…”:“继续…”;
textArea.append(String.format(“%s%n”,text));
}
}
});
动作暂停=新的抽象动作(“暂停”){
@凌驾
已执行的公共无效操作(操作事件e){
worker.pause();
}
};
操作恢复=新抽象操作(“恢复”){
@凌驾
已执行的公共无效操作(操作事件e){
worker.resume();
}
};
动作停止=新的抽象动作(“停止”){
@凌驾
已执行的公共无效操作(操作事件e){
worker.cancel(true);
}
};
JPanel buttonpanel=新的JPanel(新的FlowLayout(FlowLayout.CENTER));
添加(新的JButton(暂停));
按钮面板添加(新的JButton(resume));
按钮面板添加(新按钮(停止));
JPanel内容=新JPanel(新边界布局(8,8));
content.setboorder(BorderFactory.createEmptyBorder(8,8,8,8));
添加(新的JScrollPane(textArea),BorderLayout.CENTER);
内容。添加(按钮面板,边框布局。南);
JFrame=新JFrame(“演示”);
frame.setDefaultCloseOperation(JFrame.DO\u NOTHING\u ON\u CLOSE);
frame.addWindowListener(新的WindowAdapter(){
@凌驾
公共无效窗口关闭(WindowEvent e){
如果(!worker.isDone()){
worker.cancel(true);
}
e、 getWindow().dispose();
}
});
框架。添加(内容);
frame.pack();
frame.setLocationByPlatform(真);
frame.setVisible(true);
worker.execute();
}
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
新建演示().createAndShowGUI();
}
});
}
抽象类PausableSwingWorker扩展了SwingWorker{
私营部门的支持;
公共最终无效暂停(){
如果(!isPaused()&&!isDone()){
isPaused=真;
firePropertyChange(“暂停”,假,真);
}
}
公开最终作废简历(){
如果(isPaused()&&!isDone()){
isPaused=false;
firePropertyChange(“暂停”,真,假);
}
}
公共最终布尔值isPaused(){
返回是有理由的;
}
}
}

这是一个奇妙而彻底的答案。谢谢。谢谢@mKorbel:)我已经更新了抽象类,以包含对“暂停”属性的PropertyChange支持。现在我想它已经完成了。请看我的更新代码。我已经为“暂停”属性添加了PropertyChange支持,因此您现在可以在@barkbarkI'm love firePropertyChange中收听此属性
worker.addPropertyChangeListener(new PropertyChangeListener() {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if ("paused".equals(evt.getPropertyName())) {
           System.out.println("Old status: " + evt.getOldValue());
           System.out.println("New status: " + evt.getNewValue());
        }
    }
});
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class Demo {

    private void createAndShowGUI() {

        final JTextArea textArea = new JTextArea(20, 50);

        final PausableSwingWorker<Void, String> worker = new PausableSwingWorker<Void, String>() {
            @Override
            protected Void doInBackground() throws Exception {
                while (!isCancelled()) {
                    if (!isPaused()) {
                        publish("Writing...");
                    } else {
                        Thread.sleep(200);
                    }
                }
                return null;
            }

            @Override
            protected void process(List<String> chunks) {
                String text = String.format("%s%n", chunks.get(chunks.size() - 1));
                textArea.append(text);
            }
        };

        worker.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ("paused".equals(evt.getPropertyName())) {
                    String text = (Boolean)evt.getNewValue() ? "Paused..." : "Resumed...";
                    textArea.append(String.format("%s%n", text));
                }
            }
        });

        Action pause = new AbstractAction("Pause") {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker.pause();
            }
        };

        Action resume = new AbstractAction("Resume") {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker.resume();
            }
        };

        Action stop = new AbstractAction("Stop") {
            @Override
            public void actionPerformed(ActionEvent e) {
                worker.cancel(true);
            }
        };

        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        buttonsPanel.add(new JButton(pause));
        buttonsPanel.add(new JButton(resume));
        buttonsPanel.add(new JButton(stop));

        JPanel content = new JPanel(new BorderLayout(8, 8));
        content.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        content.add(new JScrollPane(textArea), BorderLayout.CENTER);
        content.add(buttonsPanel, BorderLayout.SOUTH);

        JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                if (!worker.isDone()) {
                    worker.cancel(true);
                }
                e.getWindow().dispose();
            }
        });

        frame.add(content);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

        worker.execute();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Demo().createAndShowGUI();
            }
        });
    }

    abstract class PausableSwingWorker<K, V> extends SwingWorker<K, V> {

        private volatile boolean isPaused;

        public final void pause() {
            if (!isPaused() && !isDone()) {
                isPaused = true;
                firePropertyChange("paused", false, true);
            }
        }

        public final void resume() {
            if (isPaused() && !isDone()) {
                isPaused = false;
                firePropertyChange("paused", true, false);
            }
        }

        public final boolean isPaused() {
            return isPaused;
        }
    }
}