Swing是一个单线程环境,它也不是线程安全的。
这意味着任何长时间运行或阻塞的进程都不应在“事件调度线程”的上下文中运行,因为它将阻止其处理新事件,包括重绘请求,从而使程序看起来像已挂起。
这也意味着您永远不要在EDT上下文之外创建或修改ANY UI组件的状态。
有关更多详细信息,请参见Swing中的并发。
您可以使用
Thread在其中运行该过程,但是您将负责确保要对UI进行的任何更改都在EDT上下文中手动进行。特别是当您要将信息从线程传递到EDT时,这可能会变得很麻烦。
另一个解决方案是使用,
SwingWorker它提供的功能可以更轻松地在其后台线程和EDT之间同步数据。它支持通过
setProgress方法和支持进行进度通知
PropertyListener,以及
publish从后台线程和
processEDT上下文中获取数据的功能。它还有一个很好的
done方法,可以让您知道后台线程何时完成,但是可以在EDT的上下文中执行,例如…
public static class FormatWorker extends SwingWorker<Integer, Integer> { private String drive; public FormatWorker(String drive) { this.drive = drive; } @Override protected Integer doInBackground() throws Exception { String[] command = {"CMD", "/C", "MyCmdCommand"}; ProcessBuilder probuilder = new ProcessBuilder(command); probuilder.directory(new File(drive + ":\")); Process process = probuilder.start(); return process.waitFor(); return 0; }}现在,您可能很想将传递
JProgressBar给,
SwingWorker并在
done方法中重置其状态,但这确实使它挂了一点,不知道工作程序实际上是什么时候开始的,当然,您应该在调用之前设置状态。工作人员,但管理UI状态不是工作人员的责任
相反,您可以利用工人的
PropertyChangeListener支持,例如…
PropertyChangeListener listener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { System.out.println(evt.getPropertyName() + "; " + evt.getNewValue()); if ("state".equals(evt.getPropertyName())) { SwingWorker.Statevalue state = (SwingWorker.Statevalue) evt.getNewValue(); switch (state) { case DONE: try { int exitLevel = ((SwingWorker<Integer, ?>)evt.getSource()).get(); JOptionPane.showMessageDialog(null, "Format command completed with exit level of " + exitLevel); } catch (InterruptedException | ExecutionException ex) { JOptionPane.showMessageDialog(progressBar, ex.getMessage()); } finally { progressBar.setIndeterminate(true); } break; case STARTED: progressBar.setIndeterminate(true); break; } } } }; FormatWorker worker = new FormatWorker("G"); worker.addPropertyChangeListener(listener); worker.execute();这使您可以决定如何响应工作人员,而无需将您与特定的工作流程联系在一起。
请参阅工作线程和SwingWorker



