0

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

  1. GUI 不更新
  2. 这个过程不能用我的“暂停”按钮“暂停”。

我听说过 EDT 和 SwingWorker,但你有一个简单的方法,我接受它。

谢谢你的帮助并原谅我的英语不好......

4

6 回答 6

6

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

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

我建议您通读此文档

于 2009-08-07T08:36:25.393 回答
3

您需要阅读Swing 中的并发以了解 EDT 和 SwingWorkers 的操作方式。

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

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

于 2009-08-07T08:38:14.127 回答
0

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

于 2009-08-07T08:36:32.460 回答
0

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

于 2009-08-07T08:37:18.183 回答
0

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

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

耗时的操作和循环应该在 EDT 中。(循环也不应该连续运行,除了检查变量之外什么都不做,否则它很容易吃掉你所有的 CPU。如果它没有别的事情要做,它应该检查,然后调用Thread.sleep()一段时间(比如 100 毫秒)。)

如果您可以证明 on/off 变量被设置为 OFF,但它始终被读取为 ON,则可能是该变量的值没有从 EDT 复制到工作线程。制作它volatile,或synchronize访问它,或使用AtomicReference,或在 EDT 中使用SwingUtilities.invokeAndWait().

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

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();
            }
        });
    }
}

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

于 2009-08-07T09:05:04.197 回答
0
@Override
public void actionPerformed(ActionEvent e) {
     new Thread() {
        public void run() {
            //your code which runs on click event
        }
    }.start();

}
于 2019-08-28T11:26:52.263 回答