gpt4 book ai didi

java - Swing 消息只有在 Runtime.getRuntime().exec() 完成执行后才会显示

转载 作者:行者123 更新时间:2023-12-01 23:57:11 25 4
gpt4 key购买 nike

我是 Swing 新手。我正在尝试创建一个 swing 包装器以允许用户浏览并选择一个文件夹,并且该文件夹路径用作控制台 .exe 程序的命令行参数。他们选择文件夹并单击“启动程序”按钮后,我希望 Swing 窗口显示一条消息,告诉他们程序正在处理(并显示时钟的动画 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 {
}
}

最佳答案

从您的示例代码中很难确定您如何执行 onLaunchProgram 方法,但从您的描述来看,可以安全地假设您正在事件调度的上下文中执行它线程。

事件调度线程负责(除其他外)调度重绘请求。任何阻塞该线程的事情都会阻止它更新 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了解更多详情

关于java - Swing 消息只有在 Runtime.getRuntime().exec() 完成执行后才会显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15396694/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com