2016-11-12 47 views
1

我正在将文件导入到项目中,一旦用户单击选择此文件,我会执行一些操作,其中包括通过命令行执行的操作。等待后台进程以不同类别的SwingWorker结束

我已经使用这个方法来完成它:

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

由于这一过程可能需要一些时间,我决定把显示新帧当前进程的所有输出一个进度条弹出。我遵循@trashgod的this代码适应了我的项目。为了这个问题的目的,让我们说我完全按照它的样子。

我只想让这个窗口在命令运行时出现,然后关闭它自己。我可以通过从override override方法中放置框架来完成此操作。

我的问题是,我从其他类创建这个类,而这是正在执行它继续与代码。例如:

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

这里我的方法3()在SwingWorkerExample类的过程完成之前正在执行。我怎么能解决这个问题?

我已经试图把在displayGUI方法本月底:

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

但它使整个框架无法正常工作或可能冻结它。 我也试着写了使p在backgrandtask类的全局变量后的方法:

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:我也试图把在main方法(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:继Eals答案我有这样结束了,仍然没有按的@Hovercraft全” t如预期的那样工作,因为字符串在过程结束之前出现。也许我的理解是错误的或者它只是没有在这方面的工作:

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 

回答

1

最好的解决方案是将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。


编辑我玩这个,代码显示两个窗口,第二个做摆动工人的工作,对上是第二部分的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语句立即生效 - 阻止它被调用的是什么?你需要两种机制中的一种来实现这种延迟。

  1. 或者使用回叫某种,任何形式的,或
  2. 显示的图像处理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(); 
     } 
    } 
} 
+0

你好@Hovercraft,谢谢你的回答。显示输出已经由链接中提供的代码完成。我不明白你如何告诉代码在其他地方等待。我的意思是,你调用myworker.execute(),然后继续使用那个方法。你如何等待(SwingWorker.StateValue.DONE == evt.getNewValue())下的代码被执行? – nck

+1

@nck:你不告诉代码“等待”,而是这是事件驱动的编程 - 你响应**事件**,这里事件是SwingWorker正在完成。如果您仍不确定要做什么,请考虑通过发布有效且体面的[mcve]来澄清您的问题和代码,这是一个小型可编译和可运行的演示程序,可以帮助我们了解您的问题。也许在这个MCVE中,使用Thread.sleep来模拟你的后台进程。 –

+0

我刚刚添加了代码副本,显示我的意思,我不希望在ping完成之前打印第二个字符串。 – nck

-1

可以使用代替线程。试试这个:

Thread t = new Thread(new Runnable(){ 
    @Override 
    public void run() 
    { 
    //The stuff you want to finish first 
    } 
}).start(); 
t.join(); 

这将创建一个新的线程并等待它完成。

+0

对不起,但这并不能解决他的问题。通过加入线程,您完全消除了线程在后台进程中的运行,因此此代码将冻结Swing GUI。更好地使用回调机制,监听器,幸运的是,这种机制已经嵌入到SwingWorker中。 –