我是Swing的新手。我正在尝试创建一个swing包装器,允许用户浏览并选择一个文件夹,该文件夹路径用作控制台.exe程序的命令行参数。在他们选择文件夹并单击“启动程序”按钮后,我希望摆动窗口显示一条消息,告诉他们程序正在处理(并显示一个时钟的GIF动画),运行外部程序,然后显示另一条消息当该程序完成执行时。我遇到的问题是“处理”消息直到外部程序完成执行后才会显示。在下面的代码中,单击“启动程序”按钮时会执行onLaunchProgram方法。我尝试过revalidate()和repaint(),但是没有变化。我有一个“完成”消息的waitFor(),但即使我把它拿出来,“处理”消息和gif也不会显示,直到外部程序完成执行。
...
JTextField txtFolder = new JTextField();
JLabel lblMessage = new JLabel();
JLabel lblPic = new JLabel();
JButton btnLaunchApplication = new JButton("Launch Program");
...
btnLaunchApplication.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
onLaunchProgram(evt);
}
});
...
if (returnVal == JFileChooser.APPROVE_OPTION){
file = fc.getSelectedFile();
txtFolder.setText(file.getAbsolutePath());
}
...
private void onLaunchProgram(ActionEvent evt) {
String strExecutableFilename = "MyExecutableProgam";
String strSourceFolder = txtFolder.getText();
String strCommand = strExecutableFilename + " " + strSourceFolder;
lblMessage.setText("Processing");
ImageIcon icon = new ImageIcon("clock.gif");
lblPic.setIcon(icon);
try {
Process procCommand = Runtime.getRuntime().exec(strCommand);
try {
procCommand.waitFor();
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
}
lblMessage.setText("Finished");
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
答案 0 :(得分:3)
您的示例代码很难确定如何执行onLaunchProgram
方法,但是从您的描述中,假设您在事件调度线程的上下文中执行它将是一种安全的方法。 / p>
Event Dispatching Thread负责(除其他事项外)调度重绘请求。阻止此线程的任何事情都会阻止它更新UI。
因为procCommand.waitFor()
是阻止操作,所以这将阻止任何重绘请求(或任何事件)在返回之前被处理。
您应该在单独的线程中执行所有耗时或阻塞进程。但是你遇到的问题是,所有对UI的更新都要在EDT的上下文中执行(也就是说,你永远不应该从EDT以外的任何线程更改/更新/修改/创建任何UI组件)
在Swing中你有很多选择,在你的情况下,我建议使用SwingWorker
。它允许您在后台线程中执行该过程,但有一些易于使用的方法来重新同步UI的更新。
public class ProcessWorker extends SwingWorker<Integer, String> {
private String program;
private String sourceFolder;
public ProcessWorker(String program, String sourceFolder) {
this.program = program;
this.sourceFolder = sourceFolder;
}
@Override
protected void process(List<String> chunks) {
// Back on the EDT
for (String value : chunks) {
if (value.equalsIgnoreCase("PROCESSING")) {
lblMessage.setText("Processing");
ImageIcon icon = new ImageIcon("clock.gif");
lblPic.setIcon(icon);
} else if (value.equalsIgnoreCase("FINISHED")) {
lblMessage.setText("Finished");
} else {
// Possible some other message...
}
}
}
@Override
protected Integer doInBackground() throws Exception {
int result = -1;
String strExecutableFilename = program;
String strSourceFolder = sourceFolder;
String strCommand = strExecutableFilename + " " + strSourceFolder;
publish("PROCESSING");
// lblMessage.setText("Processing");
// ImageIcon icon = new ImageIcon("clock.gif");
// lblPic.setIcon(icon);
try {
ProcessBuilder pb = new ProcessBuilder(program);
pb.redirectError();
pb.directory(new File(strSourceFolder));
Process procCommand = pb.start();
// Process procCommand = Runtime.getRuntime().exec(strCommand);
try {
result = procCommand.waitFor();
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
}
// lblMessage.setText("Finished");
publish("FINISHED");
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
您还应该熟悉ProcessBuilder
。它有许多有用的方法来构建过程,并克服了人们在尝试Runtime.getRuntime().exec
工作时遇到的一些困难。
您应该查看http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html了解更多详情
答案 1 :(得分:0)
看来你在一个线程中都在做这一切。
使用事件派发线程来调用你的gui代码。
private void onLaunchProgram(ActionEvent evt) {
String strExecutableFilename = "MyExecutableProgam";
String strSourceFolder = txtFolder.getText();
String strCommand = strExecutableFilename + " " + strSourceFolder;
ImageIcon icon = new ImageIcon("clock.gif");
javax.swing.SwingUtilities.invokeLater(
new Runnable() {
public void run() {
lblMessage.setText("Processing");
lblPic.setIcon(icon);
}
});
try {
Process procCommand = Runtime.getRuntime().exec(strCommand);
try {
procCommand.waitFor();
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
}
javax.swing.SwingUtilities.invokeLater(
new Runnable() {
public void run() {
lblMessage.setText("Finished");
}
});
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}