我的GUI被冻结了

我有一些我无法理解的东西:我的Swing GUI包含一个“播放”和“暂停”按钮。 我还有一个定义’ON’和’OFF’状态的静态变量。 (主程序生成GUI)。 通过克服’play’,我将静态变量的状态更改为’ON’,并在一个也修改GUI的线程中启动一个耗时的过程。 只要静态变量是’ON’循环在同一个进程中。 单击“暂停”会将静态变量更改为OFF。 但是通过点击“播放”,GUI就会冻结,因此:

  1. GUI不会更新
  2. 使用“暂停”按钮无法“暂停”此过程。

我听说过EDT和SwingWorker,但是我有一个简单的方法可以做到这一点。

谢谢你的帮助,原谅我的英语不好……

问题是你正在负责更新GUI的同一个线程上进行密集,耗时的工作。 SwingWorker允许您将耗时的任务移动到单独的执行线程,从而使UI线程不受限制地执行其操作。

但是,它确实增加了一个复杂性:亲和力。 在UI组件上调用方法通常需要您从UI线程执行此操作。 因此,您需要使用特殊function从工作线程返回UI线程。 SwingWorker还为您提供此function。

我建议你仔细阅读本文档 。

您需要阅读Swing中的Concurrency以了解EDT和SwingWorkers的运行方式。

所有GUI更新都在EDT上执行,因此当您单击GUI组件时,此调用的任何方法都将在EDT上执行。 如果这是一个耗时的过程,那么这将阻止EDT执行任何进一步的GUI更新。 因此,您的GUI处于冻结状态,您无法单击暂停按钮。

您需要使用SwingWorker在另一个线程上执行耗时的进程。 我上面提供的链接详细说明了如何执行此操作。

你不应该在Swing的事件处理程序中启动长时间运行的进程,因为它会冻结你的GUI,你现在就知道了。 :)在一个新的线程中启动它。 如果您计划从工作线程操作GUI(因为Swing不是线程安全的),您只需要使用SwingWorker

这是一个非常直接的原因:虽然Java正在处理您耗时的过程,但它无法更新GUI。 解决方案:在单独的线程中运行耗时的进程。 有很多方法可以编程,这可能在某种程度上取决于程序的编写方式。

事件调度线程(EDT)是唯一可以安全地读取或更新GUI的线程。

暂停按钮应该在事件派发线程中设置开/关变量。

耗时的操作和循环应该在EDT中。 (循环也不应该一直运行,除了检查变量之外什么也不做,或者它可以很容易地占用你所有的CPU。如果它没有别的办法,它应该检查,然后调用Thread.sleep()一段时间(说100毫秒)。)

如果你可以certificate开/关变量被设置为OFF,但是它总是被读为ON,那么可能是变量的值没有从EDT复制到工作线程。 使其volatile ,或synchronize对它的访问,或使用AtomicReference ,或使用SwingUtilities.invokeAndWait()在EDT中读取它。

在这里, SwingWorker可能最简单的方法。 在doInBackground()方法中执行耗时的操作和开/关检查,在doInBackground()方法中执行GUI更新。

 public enum State { RUNNING, STOPPED } public class ThreadSafeStateModel { private State state = State.STOPPED; public synchronized void stop() { state = State.STOPPED; } public synchronized void start() { state = State.RUNNING; } public boolean isRunning() { return state == State.RUNNING; } } public class ExpensiveProcessWorker extends SwingWorker { private final ThreadSafeStateModel model; public ExpensiveProcessWorker(ThreadSafeStateModel model) { this.model = model; } @Override // Runs in background protected Void doInBackground() throws Exception { while (model.isRunning()) { // do one iteration of something expensive } return null; } @Override // Runs in event dispatch thread protected void done() { // Update the GUI } } public class StopButton extends JButton { public StopButton(final ThreadSafeStateModel model) { super(new AbstractAction("Stop") { @Override public void actionPerformed(ActionEvent e) { model.stop(); } }); } } public class StartButton extends JButton { public StartButton(final ThreadSafeStateModel model) { super(new AbstractAction("Start") { @Override public void actionPerformed(ActionEvent e) { model.start(); new ExpensiveProcessWorker(model).execute(); } }); } } 

(根据实际应用,可以做很多事情来清理它,但你明白了。)