我正在将文件导入到项目中,一旦用户单击选择此文件,我就会执行某些操作,包括通过命令行执行的操作。

我已经用这种方法做到了:

p = Runtime.getRuntime().exec(command, null, new File(directory));
p.waitFor();


由于此过程可能需要一些时间,因此我决定将进度条弹出窗口显示在新框架中,以显示当前过程的所有输出。我一直按照来自@trashgod的this代码进行调整,以适应我的项目。出于这个问题的目的,我们可以说它完全是正确的。

我只希望此窗口在命令运行时出现,然后自行关闭。我可以通过从override done方法中放置框架来做到这一点。

我的问题是我正在从其他类创建该类,并且在执行该类时会继续执行代码。例如:

 method1();
 method2();
 new SwingWorkerExample().displayGUI(); //Process continues in background
 method3();


在这里,我的method3()是在SwingWorkerExample类的过程完成之前执行的。我该如何解决?

我已经尝试在displayGUI方法的末尾放置以下内容:

while(!backgroundTask.isDone()){
//do nothing
}


但这会使整个框架无法正常工作或冻结。
在backgrandtask类中将p设为全局变量后,我还尝试编写一种方法:

public Process getProcess(){
return p;
}


然后从displaGUI()调用以下命令:

backgroundTask.getProcess().waitFor();


但是它返回一个空指针异常。

在显示命令窗口的输出时,我还能做些什么来等待进程结束?

谢谢。
更新:
这是链接代码的副本,其中进行了一些更改以显示我的意思。在此过程完成之前,我不希望打印第二个文本:

package mcve;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.swing.*;

/**
* @se https://stackoverflow.com/a/20603012/230513
 * @see https://stackoverflow.com/a/17763395/230513
 * @seehttps://stackoverflow.com/questions/20600721/
 */
public class SwingWorkerExample {

private JFrame frame;
private final JLabel statusLabel = new JLabel("Status: ", JLabel.CENTER);
private final JTextArea textArea = new JTextArea(20, 20);
private JButton startButton = new JButton("Start");
private JButton stopButton = new JButton("Stop");
private JProgressBar bar = new JProgressBar();
private BackgroundTask backgroundTask;
private final ActionListener buttonActions = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent ae) {
        JButton source = (JButton) ae.getSource();
        if (source == startButton) {
            textArea.setText(null);
            startButton.setEnabled(false);
            stopButton.setEnabled(true);
            backgroundTask = new BackgroundTask();
            backgroundTask.execute();
            bar.setIndeterminate(true);
        } else if (source == stopButton) {
            backgroundTask.cancel(true);
            backgroundTask.done();
        }
    }
};

private void displayGUI() {
    frame = new JFrame("Swing Worker Example");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    JPanel panel = new JPanel();
    panel.setBorder(
        BorderFactory.createEmptyBorder(5, 5, 5, 5));
    panel.setLayout(new BorderLayout(5, 5));

    JScrollPane sp = new JScrollPane();
    sp.setBorder(BorderFactory.createTitledBorder("Output: "));
    sp.setViewportView(textArea);

    startButton.addActionListener(buttonActions);
    stopButton.setEnabled(false);
    stopButton.addActionListener(buttonActions);
    JPanel buttonPanel = new JPanel();
    buttonPanel.add(startButton);
    buttonPanel.add(stopButton);
    buttonPanel.add(bar);

    panel.add(statusLabel, BorderLayout.PAGE_START);
    panel.add(sp, BorderLayout.CENTER);
    panel.add(buttonPanel, BorderLayout.PAGE_END);

    frame.setContentPane(panel);
    frame.pack();
    frame.setLocationByPlatform(true);
    frame.setVisible(true);
}

private class BackgroundTask extends SwingWorker<Integer, String> {

    private int status;

    public BackgroundTask() {
        statusLabel.setText((this.getState()).toString());
    }

    @Override
    protected Integer doInBackground() {
        try {
            ProcessBuilder pb = new ProcessBuilder("ping", "-c", "5","google.com");//change -c for -n in windows
            pb.redirectErrorStream(true);
            Process p = pb.start();
            String s;
            BufferedReader stdout = new BufferedReader(
                new InputStreamReader(p.getInputStream()));
            while ((s = stdout.readLine()) != null && !isCancelled()) {
                publish(s);
            }
            if (!isCancelled()) {
                status = p.waitFor();
            }
            p.getInputStream().close();
            p.getOutputStream().close();
            p.getErrorStream().close();
            p.destroy();
        } catch (IOException | InterruptedException ex) {
            ex.printStackTrace(System.err);
        }
        return status;
    }

    @Override
    protected void process(java.util.List<String> messages) {
        statusLabel.setText((this.getState()).toString());
        for (String message : messages) {
            textArea.append(message + "\n");
        }
    }

    @Override
    protected void done() {
        statusLabel.setText((this.getState()).toString() + " " + status);
        stopButton.setEnabled(false);
        startButton.setEnabled(true);
        bar.setIndeterminate(false);
        frame.dispose();
    }

}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            System.out.println("Here I start");
            new SwingWorkerExample().displayGUI();
            System.out.println("I'll show up when the SwingWorkerExample has finnished");
        }
    });
}


Update2:我也尝试过将流程放入主方法(displayGUI)并发送对该流程的引用,但是它不起作用,窗口只是冻结而没有显示:

frame.setVisible(true);
    bar.setIndeterminate(true);
    try {
        ProcessBuilder pb = new ProcessBuilder("ping", "-c", "20", "google.com");
        pb.redirectErrorStream(true);
        Process p;
        p = pb.start();
        backgroundTask = new BackgroundTask(p);
        backgroundTask.execute();
        p.waitFor();
    } catch (IOException | InterruptedException ex) {
        ex.printStackTrace(System.err);
    }


更新3:在@Hovercraft Full of Eals答案之后,我得到了这个结果,由于该字符串在过程结束之前出现,因此仍然无法按预期工作。也许我理解错了,或者在这种情况下不起作用:

package mcve;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import static javax.swing.Action.MNEMONIC_KEY;

public class SwingWorkerExample {

private JFrame frame;
private ExecuteFrame backgroundTask;


private class properyListener implements PropertyChangeListener {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        // the above percolates from the SwingWorker to the containing
        // JPanel
        if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
            int processState = backgroundTask.getProcessStatus();
            System.out.println("Process State: " + processState + "\n");
        }
    }
}
private void displayGUI() {
    frame = new JFrame("Swing Worker Example");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    backgroundTask = new ExecuteFrame();
    frame.add(backgroundTask);
    backgroundTask.addPropertyChangeListener(new properyListener());

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

    backgroundTask.startProcess();
    }
 public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            System.out.println("Here I start");
            SwingUtilities.invokeLater(() -> new SwingWorkerExample().displayGUI());
            System.out.println("I'll show up when the SwingWorkerExample has finnished");
        }
    });
}
}

@SuppressWarnings("serial")
class ExecuteFrame extends JPanel {

private final JLabel statusLabel = new JLabel("Status: ", JLabel.CENTER);
private final JTextArea textArea = new JTextArea(20, 30);
private StartAction startAction = new StartAction("Start", KeyEvent.VK_S);
private StopAction stopAction = new StopAction("Stop", KeyEvent.VK_T);
private JProgressBar bar = new JProgressBar();
private BackgroundTask backgroundTask;
private int processStatus;

public ExecuteFrame() {
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    setLayout(new BorderLayout(5, 5));

    textArea.setFocusable(false);
    JScrollPane sp = new JScrollPane();
    sp.setBorder(BorderFactory.createTitledBorder("Output: "));
    sp.setViewportView(textArea);

    stopAction.setEnabled(false);
    JPanel buttonPanel = new JPanel();
    buttonPanel.add(new JButton(startAction));
    buttonPanel.add(new JButton(stopAction));
    buttonPanel.add(bar);

    add(statusLabel, BorderLayout.PAGE_START);
    add(sp, BorderLayout.CENTER);
    add(buttonPanel, BorderLayout.PAGE_END);
}

public void startProcess() {
    if (backgroundTask != null && !backgroundTask.isDone()) {
        return; // background task not yet done
    }
    textArea.setText("");
    startAction.setEnabled(false);
    stopAction.setEnabled(true);
    backgroundTask = new BackgroundTask();
    backgroundTask.addPropertyChangeListener(new BGTaskListener());
    backgroundTask.execute();
    bar.setIndeterminate(true);
}

public void cancelProcess() {
    if (backgroundTask != null && !backgroundTask.isDone()) {
        backgroundTask.cancel(true);
    }
}

public void processStopped() {
    statusLabel.setText((backgroundTask.getState()).toString() + " "
            + processStatus);
    stopAction.setEnabled(false);
    startAction.setEnabled(true);
    bar.setIndeterminate(false);

    // Window thisWindow = SwingUtilities.getWindowAncestor(textArea);
    // thisWindow.dispose();
}

public int getProcessStatus() {
    return processStatus;
}

public class BGTaskListener implements PropertyChangeListener {

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
            processStopped();
        }

        // percolate this listener up to the main JPanel's Prop Chng
        // Listener
        ExecuteFrame.this.firePropertyChange(evt.getPropertyName(), evt.getOldValue(),
                evt.getNewValue());
    }
}

private class BackgroundTask extends SwingWorker<Integer, String> {

    @Override
    protected Integer doInBackground() throws Exception {
        List<String> list = new ArrayList<>();
        list.add("ping");
        String name = System.getProperty("os.name");
        if (name.startsWith("Win")) {
            list.add("-n");
        } else {
            list.add("-c");
        }
        list.add("5");
        list.add("google.com");
        try {
            ProcessBuilder pb = new ProcessBuilder(list);
            pb.redirectErrorStream(true);
            Process p = pb.start();
            String s;
            BufferedReader stdout = new BufferedReader(
                    new InputStreamReader(p.getInputStream()));
            while ((s = stdout.readLine()) != null && !isCancelled()) {
                publish(s);
            }
            if (!isCancelled()) {
                processStatus = p.waitFor();
            }
            p.getInputStream().close();
            p.getOutputStream().close();
            p.getErrorStream().close();
            p.destroy();
        } catch (IOException | InterruptedException ex) {
            ex.printStackTrace(System.err);
        }
        return processStatus;
    }

    @Override
    protected void process(java.util.List<String> messages) {
        statusLabel.setText((this.getState()).toString());
        for (String message : messages) {
            textArea.append(message + "\n");
        }
    }

}

private class StartAction extends AbstractAction {

    public StartAction(String name, int mnemonic) {
        super(name);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        startProcess();
    }
}

private class StopAction extends AbstractAction {

    public StopAction(String name, int mnemonic) {
        super(name);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        cancelProcess();
    }
}
 }


输出为:

Here I start
I'll show up when the SwingWorkerExample has finnished
Process State: 0


代替:

Here I start
Process State: 0
I'll show up when the SwingWorkerExample has finnished

最佳答案

最好的解决方案是将PropertyChangeListener添加到您的SwingWorker,并在其回调方法中检查过程是否结束。这将允许您的Swing事件线程运行,并在工作程序完成时在Swing事件线程上通知您。您甚至可以侦听worker的progress属性的更改,并从此侦听器中更改JProgressBar。例如(代码未经测试):

private class TaskListener implements PropertyChangeListener {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        SwingWorker task = (SwingWorker) evt.getSource();

        // here we can listen for changes to the worker's progress property
        // if we desire
        if ("progress".equals(evt.getPropertyName())) {
            int progress = task.getProgress();
            progressBar.setValue(progress);
        }

        // listen for the worker to be done
        if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
            // always need to know when the SW is done
            // so we can call get() and trap exceptions
            try {
                task.get();  // do something with the result returned?

                // !! here do things that you want done when the SwingWorker has completed ***

            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}


别处...

MySwingWorker myWorker = new MySwingWorker();
myWorker.addPropertyChangeListener(new TaskListener());
myWorker.execute();


关于:


  在显示命令窗口的输出时,我还能做些什么来等待进程结束?


获取和显示命令窗口输出是一个完全不同的问题,并且需要您从正在运行的后台进程获取InputStream。



编辑我正在玩这个代码,它显示了两个窗口,第二个代码在执行Swing工作,第二个代码在JPanel上监听第二个组成部分的属性更改,但是它不是很干净的代码,因为它没有很好的MVC关注点分离:

import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

public class SwingWorkerExample2 {

    private static void createAndShowGui() {
        SWEx2MainPanel mainPanel = new SWEx2MainPanel();

        JFrame frame = new JFrame("SwingWorker Example");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

@SuppressWarnings("serial")
class SWEx2MainPanel extends JPanel {
    public static final ModalityType DLG_MODALITY_TYPE = ModalityType.MODELESS;
    private JTextArea statusArea = new JTextArea(15, 30);
    private JDialog workerDialog;
    private SWEx2WorkerPanel workerPanel = new SWEx2WorkerPanel();

    public SWEx2MainPanel() {
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton(new ShowWorkerDialogAction()));
        statusArea.setFocusable(false);
        JScrollPane scrollPane = new JScrollPane(statusArea);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        setLayout(new BorderLayout(5, 5));
        add(scrollPane);
        add(buttonPanel, BorderLayout.PAGE_END);

        workerPanel.addPropertyChangeListener(new WorkerPanelListener());
    }

    private class WorkerPanelListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            // the above percolates from the SwingWorker to the containing
            // JPanel
            if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                int processState = workerPanel.getProcessStatus();
                statusArea.append("Process State: " + processState + "\n");
            }
        }
    }

    private class ShowWorkerDialogAction extends AbstractAction {
        public ShowWorkerDialogAction() {
            super("Show Worker");
            putValue(MNEMONIC_KEY, KeyEvent.VK_S);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (workerDialog == null) {
                Window window = SwingUtilities.getWindowAncestor(statusArea);
                workerDialog = new JDialog(window, "Worker Dialog", DLG_MODALITY_TYPE);
                workerDialog.add(workerPanel);
                workerDialog.pack();
                workerDialog.setLocationByPlatform(true);
            } else if (workerDialog.isVisible()) {
                // dialog is still visible -- do nothing
                return;
            }
            workerDialog.setVisible(true);
        }
    }
}

// class that holds the JPanel that does background communication
@SuppressWarnings("serial")
class SWEx2WorkerPanel extends JPanel {
    private final JLabel statusLabel = new JLabel("Status: ", JLabel.CENTER);
    private final JTextArea textArea = new JTextArea(20, 30);
    private StartAction startAction = new StartAction("Start", KeyEvent.VK_S);
    private StopAction stopAction = new StopAction("Stop", KeyEvent.VK_T);
    private JProgressBar bar = new JProgressBar();
    private BackgroundTask backgroundTask;
    private int processStatus;

    public SWEx2WorkerPanel() {
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        setLayout(new BorderLayout(5, 5));

        textArea.setFocusable(false);
        JScrollPane sp = new JScrollPane();
        sp.setBorder(BorderFactory.createTitledBorder("Output: "));
        sp.setViewportView(textArea);

        stopAction.setEnabled(false);
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton(startAction));
        buttonPanel.add(new JButton(stopAction));
        buttonPanel.add(bar);

        add(statusLabel, BorderLayout.PAGE_START);
        add(sp, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.PAGE_END);
    }

    public void startProcess() {
        if (backgroundTask != null && !backgroundTask.isDone()) {
            return; // background task not yet done
        }
        textArea.setText("");
        startAction.setEnabled(false);
        stopAction.setEnabled(true);
        backgroundTask = new BackgroundTask();
        backgroundTask.addPropertyChangeListener(new BGTaskListener());
        backgroundTask.execute();
        bar.setIndeterminate(true);
    }

    public void cancelProcess() {
        if (backgroundTask != null && !backgroundTask.isDone()) {
            backgroundTask.cancel(true);
        }
    }

    public void processStopped() {
        statusLabel.setText((backgroundTask.getState()).toString() + " "
                + processStatus);
        stopAction.setEnabled(false);
        startAction.setEnabled(true);
        bar.setIndeterminate(false);

        // Window thisWindow = SwingUtilities.getWindowAncestor(textArea);
        // thisWindow.dispose();
    }

    public int getProcessStatus() {
        return processStatus;
    }

    private class BGTaskListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                processStopped();
            }

            // percolate this listener up to the main JPanel's Prop Chng
            // Listener
            SWEx2WorkerPanel.this.firePropertyChange(evt.getPropertyName(), evt.getOldValue(),
                    evt.getNewValue());
        }
    }

    private class BackgroundTask extends SwingWorker<Integer, String> {

        @Override
        protected Integer doInBackground() throws Exception {
            List<String> list = new ArrayList<>();
            list.add("ping");
            String name = System.getProperty("os.name");
            if (name.startsWith("Win")) {
                list.add("-n");
            } else {
                list.add("-c");
            }
            list.add("5");
            list.add("google.com");
            try {
                ProcessBuilder pb = new ProcessBuilder(list);
                pb.redirectErrorStream(true);
                Process p = pb.start();
                String s;
                BufferedReader stdout = new BufferedReader(
                        new InputStreamReader(p.getInputStream()));
                while ((s = stdout.readLine()) != null && !isCancelled()) {
                    publish(s);
                }
                if (!isCancelled()) {
                    processStatus = p.waitFor();
                }
                p.getInputStream().close();
                p.getOutputStream().close();
                p.getErrorStream().close();
                p.destroy();
            } catch (IOException | InterruptedException ex) {
                ex.printStackTrace(System.err);
            }
            return processStatus;
        }

        @Override
        protected void process(java.util.List<String> messages) {
            statusLabel.setText((this.getState()).toString());
            for (String message : messages) {
                textArea.append(message + "\n");
            }
        }

    }

    private class StartAction extends AbstractAction {
        public StartAction(String name, int mnemonic) {
            super(name);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            startProcess();
        }
    }

    private class StopAction extends AbstractAction {
        public StopAction(String name, int mnemonic) {
            super(name);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            cancelProcess();
        }
    }

}




编辑2

在最新的代码迭代中:

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            System.out.println("Here I start");

            // note that the use of invokeLater twice is not necessary
            SwingUtilities.invokeLater(() -> new SwingWorkerExample().displayGUI());

            // there is nothing in the code that pauses or delays this line of code
            System.out.println("I'll show up when the SwingWorkerExample has finnished");
        }
    });
}


附带问题:无需将代码从已排队等待在Swing线程上调用的代码中放入Swing线程。

关键问题是:在启动GUI之后立即执行您的println语句-阻止它被调用的原因是什么?您需要两种机制之一来实现此延迟。


使用某种,任何形式的回叫,或者
将图像处理GUI显示为模式对话框,这样,它将使来自处于同一线程中并在对话框变得可见之后被调用的调用程序的任何代码延迟。延迟的代码将暂停直到对话框不再存在。


第一种方法是两者中的一种较为灵活,因为它不需要使用模式对话框。

下面是上述两种机制的一个示例。注意对代码所做的更改已用\\ !!注释表示:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Dialog.ModalityType;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

import static javax.swing.Action.MNEMONIC_KEY;

public class SwingWorkerExample2 {
    private JDialog modalDialog; // !! a modal JDialog
    private ExecuteFrame backgroundTask;
    private Runnable myCallback; // !!

    private class properyListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                int processState = backgroundTask.getProcessStatus();
                System.out.println("Process State: " + processState + "\n");

                // !! added
                myCallback.run(); // simply run it. No need to place into a new thread
            }
        }
    }

    // !! set myCallback field. This could also be done as a parameter to
    // !! the displayGUI(Runnable myCallback) method  if desired
    public SwingWorkerExample2(Runnable myCallback) {
        this.myCallback = myCallback;
    }

    private void displayGUI() {
        // !! create it as a modal dialog
        modalDialog = new JDialog(null, "Swing Worker Example", ModalityType.APPLICATION_MODAL);
        modalDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); // !!
        backgroundTask = new ExecuteFrame();
        modalDialog.add(backgroundTask);
        backgroundTask.addPropertyChangeListener(new properyListener());
        modalDialog.pack();
        modalDialog.setLocationByPlatform(true);
        modalDialog.setVisible(true);
        backgroundTask.startProcess();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                System.out.println("Here I start");
                Runnable myCallback = new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("This is being displayed from a Runnable");
                    }
                };

                // pass callback Runnable into SwingWorkerExample2's constructor
                new SwingWorkerExample2(myCallback).displayGUI(); // !! not wrapped in a Runnable
                System.out.println("This is displayed after the dialog is no longer visible");
            }
        });
    }
}

@SuppressWarnings("serial")
class ExecuteFrame2 extends JPanel {
    private final JLabel statusLabel = new JLabel("Status: ", JLabel.CENTER);
    private final JTextArea textArea = new JTextArea(20, 30);
    private StartAction startAction = new StartAction("Start", KeyEvent.VK_S);
    private StopAction stopAction = new StopAction("Stop", KeyEvent.VK_T);
    private JProgressBar bar = new JProgressBar();
    private BackgroundTask backgroundTask;
    private int processStatus;

    public ExecuteFrame2() {
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        setLayout(new BorderLayout(5, 5));
        textArea.setFocusable(false);
        JScrollPane sp = new JScrollPane();
        sp.setBorder(BorderFactory.createTitledBorder("Output: "));
        sp.setViewportView(textArea);
        stopAction.setEnabled(false);
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton(startAction));
        buttonPanel.add(new JButton(stopAction));
        buttonPanel.add(bar);
        add(statusLabel, BorderLayout.PAGE_START);
        add(sp, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.PAGE_END);
    }

    public void startProcess() {
        if (backgroundTask != null && !backgroundTask.isDone()) {
            return; // background task not yet done
        }
        textArea.setText("");
        startAction.setEnabled(false);
        stopAction.setEnabled(true);
        backgroundTask = new BackgroundTask();
        backgroundTask.addPropertyChangeListener(new BGTaskListener());
        backgroundTask.execute();
        bar.setIndeterminate(true);
    }

    public void cancelProcess() {
        if (backgroundTask != null && !backgroundTask.isDone()) {
            backgroundTask.cancel(true);
        }
    }

    public void processStopped() {
        statusLabel.setText((backgroundTask.getState()).toString() + " " + processStatus);
        stopAction.setEnabled(false);
        startAction.setEnabled(true);
        bar.setIndeterminate(false);
        // Window thisWindow = SwingUtilities.getWindowAncestor(textArea);
        // thisWindow.dispose();
    }

    public int getProcessStatus() {
        return processStatus;
    }

    public class BGTaskListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                processStopped();
            }
            // percolate this listener up to the main JPanel's Prop Chng
            // Listener
            ExecuteFrame2.this.firePropertyChange(evt.getPropertyName(), evt.getOldValue(),
                    evt.getNewValue());
        }
    }

    private class BackgroundTask extends SwingWorker<Integer, String> {
        @Override
        protected Integer doInBackground() throws Exception {
            List<String> list = new ArrayList<>();
            list.add("ping");
            String name = System.getProperty("os.name");
            if (name.startsWith("Win")) {
                list.add("-n");
            } else {
                list.add("-c");
            }
            list.add("5");
            list.add("google.com");
            try {
                ProcessBuilder pb = new ProcessBuilder(list);
                pb.redirectErrorStream(true);
                Process p = pb.start();
                String s;
                BufferedReader stdout = new BufferedReader(
                        new InputStreamReader(p.getInputStream()));
                while ((s = stdout.readLine()) != null && !isCancelled()) {
                    publish(s);
                }
                if (!isCancelled()) {
                    processStatus = p.waitFor();
                }
                p.getInputStream().close();
                p.getOutputStream().close();
                p.getErrorStream().close();
                p.destroy();
            } catch (IOException | InterruptedException ex) {
                ex.printStackTrace(System.err);
            }
            return processStatus;
        }

        @Override
        protected void process(java.util.List<String> messages) {
            statusLabel.setText((this.getState()).toString());
            for (String message : messages) {
                textArea.append(message + "\n");
            }
        }
    }

    private class StartAction extends AbstractAction {
        public StartAction(String name, int mnemonic) {
            super(name);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            startProcess();
        }
    }

    private class StopAction extends AbstractAction {
        public StopAction(String name, int mnemonic) {
            super(name);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            cancelProcess();
        }
    }
}

07-24 09:44
查看更多