直到Runtime.getRuntime()。exec()完成执行后才会显示Swing消息

我是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 { } } 

您的示例代码很难确定如何执行onLaunchProgram方法,但是从您的描述中,假设您在事件调度线程的上下文中执行它将是一个安全的节拍。

Event Dispatching Thread负责(除其他事项外)调度重绘请求。 阻止此线程的任何事情都会阻止它更新UI。

因为procCommand.waitFor()是一个阻塞操作,所以这将阻止任何重绘请求(或任何事件)在返回之前被处理。

您应该在单独的线程中执行所有耗时或阻塞进程。 但是你遇到的问题是,所有对UI的更新都要在EDT的上下文中执行(也就是说,你永远不应该从EDT以外的任何线程更改/更新/修改/创建任何UI组件)

在Swing中你有很多选择,在你的情况下,我建议使用SwingWorker 。 它允许您在后台线程中执行该过程,但有一些易于使用的方法来重新同步UI的更新。

 public class ProcessWorker extends SwingWorker { private String program; private String sourceFolder; public ProcessWorker(String program, String sourceFolder) { this.program = program; this.sourceFolder = sourceFolder; } @Override protected void process(List 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://sofzh.miximages.com/java/ring 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 { } }