我有一些我无法理解的东西:我的Swing GUI包含一个'播放'和'暂停'按钮。我还有一个定义'ON'和'OFF'状态的静态变量。 (主程序生成GUI)。 通过克服'play',我将静态变量的状态更改为'ON',并在一个也修改GUI的线程中启动一个耗时的过程。只要静态变量在同一进程中为'ON'循环。单击“暂停”会将静态变量更改为OFF。 但是通过点击“播放”,GUI就会冻结,因此:
我听说过EDT和SwingWorker但是我有一个简单的方法可以做到这一点。
感谢您的帮助并原谅我糟糕的英语......
答案 0 :(得分:6)
问题是你正在负责更新GUI的同一个线程上进行密集,耗时的工作。 SwingWorker允许您将耗时的任务移动到单独的执行线程中,从而使UI线程不受限制地执行其操作。
然而,它确实增加了一个复杂性:亲和力。在UI组件上调用方法通常需要您从UI线程执行此操作。因此,您需要使用特殊功能从工作线程返回UI线程。 SwingWorker也为您提供了这种能力。
我建议您通读this documentation。
答案 1 :(得分:3)
您需要阅读Concurrency in Swing以了解EDT和SwingWorkers的运作方式。
所有GUI更新都在EDT上执行,因此当您单击GUI组件时,此调用的任何方法都将在EDT上执行。如果这是一个耗时的过程,那么这将阻止EDT执行任何进一步的GUI更新。因此,您的GUI处于冻结状态,您无法单击暂停按钮。
您需要使用SwingWorker在另一个线程上执行耗时的进程。我上面提供的链接详细说明了如何执行此操作。
答案 2 :(得分:0)
你不应该在Swing的事件处理程序中启动长时间运行的进程,因为它会冻结你的GUI,你现在就知道了。 :)在新线程中启动它。如果您计划从工作线程操作GUI,则只需使用SwingWorker
(因为Swing不是线程安全的)。
答案 3 :(得分:0)
这是一个非常直接的原因:当Java正在处理您耗时的过程时,它无法更新GUI。解决方案:在单独的线程中运行耗时的进程。有很多方法可以编程,这可能在某种程度上取决于程序的编写方式。
答案 4 :(得分:0)
事件调度线程(EDT)是唯一可以安全读取或更新GUI的线程。
暂停按钮应该在事件发送线程中设置开/关变量。
耗时的操作和循环应该不在EDT中。 (循环也不应该一直运行,除了检查变量之外什么也不做,或者它可以很容易地占用你的所有CPU。如果没有别的办法,它应该检查,然后调用Thread.sleep()
一段时间(说100毫秒)。)
如果你可以证明开/关变量被设置为OFF,但是它总是被读为ON,那么可能是变量的值没有从EDT复制到工作线程。对其进行volatile
或synchronize
访问,或使用AtomicReference
,或使用SwingUtilities.invokeAndWait()
在EDT中阅读。
SwingWorker
可能是最简单的方法,在这里。使用doInBackground()
方法实现耗时的操作,开/关检查,以及done()
方法中的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<Void, Void> {
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();
}
});
}
}
(根据实际应用可以做很多事情来清理它,但你明白了。)
答案 5 :(得分:0)
@Override
public void actionPerformed(ActionEvent e) {
new Thread() {
public void run() {
//your code which runs on click event
}
}.start();
}