我正在將文件導入到項目中,一旦用戶單擊選擇此文件,我會執行一些操作,其中包括通過命令行執行的操作。等待後臺進程以不同類別的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
你好@Hovercraft,謝謝你的回答。顯示輸出已經由鏈接中提供的代碼完成。我不明白你如何告訴代碼在其他地方等待。我的意思是,你調用myworker.execute(),然後繼續使用那個方法。你如何等待(SwingWorker.StateValue.DONE == evt.getNewValue())下的代碼被執行? – nck
@nck:你不告訴代碼「等待」,而是這是事件驅動的編程 - 你響應**事件**,這裏事件是SwingWorker正在完成。如果您仍不確定要做什麼,請考慮通過發佈有效且體面的[mcve]來澄清您的問題和代碼,這是一個小型可編譯和可運行的演示程序,可以幫助我們瞭解您的問題。也許在這個MCVE中,使用Thread.sleep來模擬你的後臺進程。 –
我剛剛添加了代碼副本,顯示我的意思,我不希望在ping完成之前打印第二個字符串。 – nck