【问题标题】:GUI not updating visually before running ActionEvent在运行 ActionEvent 之前 GUI 未在视觉上更新
【发布时间】:2013-08-01 05:56:42
【问题描述】:

为了解释更多,我有一个如下所示的 GUI:

然后我在 OK 按钮上有一个动作监听器,开始如下:

//OK Button Action Listener
private void okButtonActionPerformed(ActionEvent e) {   
    //Enable/Disable Buttons
    okButton.setEnabled(false);
    cancelButton.setEnabled(true);
    updateCheckbox.setEnabled(false);
    //Move on to a series of other methods here...

理论上,应该这样做:

然而,我得到以下信息,直到所有方法和连接到 OK 按钮的其他事情都完成:

这显然不可能发生,因为这个想法是让取消按钮可用,而确定按钮和其他几个复选框在程序期间不可用(图 2),相反,它冻结在一个半状态(图 3)。有没有办法解决这个问题?

【问题讨论】:

  • actionListener 里面的一切都在一瞬间完成(在屏幕上),在所有代码行执行之后,请问真正的目标是什么
  • 我很难理解你的意思,但基本上我有一个长期运行的过程需要进行,同时还要保持 GUI 可用。根据其他答案,我应该通过SwingWorker 使用另一个线程。
  • 我有一个长期运行的过程 ---> 然后在这里接受并接受其中一个答案,一堆代码示例,其中一些具有出色的描述
  • :-) 这里的这个问题和答案就像基于猜测和贴图的狂野短裤,很好,很好,但你得到了一个回答

标签: java swing user-interface swingworker actionevent


【解决方案1】:

每次从 GUI 执行逻辑时,您都应该按以下方式使用 SwingWorker:

SwingWorker myWorker= new SwingWorker<String, Void>() {
    @Override
    protected String doInBackground() throws Exception {
        //Execute your logic
        return null;
    }
};
myWorker.execute();

如果您想从这个逻辑内部更新 GUI,请使用 InvokeLater:

SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        //To update your GUI
    }
});

这样,您可以确保您的逻辑和 GUI 都保持响应。

编辑:

如果这更适合您的需要,您也可以使用invokeAndWaitLink to related answer

【讨论】:

  • 呃,没那么多。在SwingWorker 中有一个非常好的框架,用于使用publishprocess 传回中间更新;你到底为什么要使用invokeLater?!
  • 我遵循的逻辑在这里:stackoverflow.com/a/7196920/1611957 你能解释一下为什么你认为它不适用吗?我的意思是-它确实很容易。
  • 因为SwingWorker 已经有一个异步任务队列,您可以将项目传递到process,然后EDT 将调用publish。您覆盖 publish 并使用该项目来更新 GUI。您的方法需要创建另一个匿名类(即Runnable),如果您想将任何数据传递给它,那么它必须是final 等。您还需要考虑线程安全,因为Runnable 将被调用美国东部时间。
  • 听起来很合理,您可以将其添加到您的解决方案中,以便在这里有两种实现方式。
  • 我以前从未真正使用过 SwingWorker。以最基本的形式,我基本上是想在 ActionEvent 方法中包装所有与 SwingWorker 内的 GUI 不直接相关的 ActionListener 代码吗?
【解决方案2】:

//这里继续其他一系列方法……

确保您不会因长时间运行的操作而阻塞 GUI 线程 (EDT)。请改用SwingWorker

【讨论】:

    【解决方案3】:

    您是否在处理 GUI 的同一线程上进行一些处理?您可能希望查看 SwingWorker 线程在后台执行繁重的工作,以便您的 UI 在这样的情况下保持响应。

    【讨论】:

    • 这正是我正在做的事情,我知道我做错了什么。我现在只需要尝试理解实现另一个线程。
    【解决方案4】:

    是的,那是因为你用 EDT 用你的其他方法阻止了。

    您需要使用另一个Thread 在后台执行该工作,否则 GUI 将被阻止。

    在 Swing 应用程序中,建议在 SwingWorker 上执行任何长时间运行的任务。

    看看documentation的介绍。

    SwingWorker 将执行给定的任务,并在完成后向 GUI 报告。这将以非阻塞方式完成,因此您在执行任务时仍然可以使用 GUI。

    如果您希望能够取消后台任务,您需要保留对SwingWorker 的引用,以便您可以调用cancel 方法。这种情况下工作方法需要是可中断的,否则无法取消任务。

    【讨论】:

    • Cancel 将在这种情况下完全退出程序而不是中断它。各种答案听起来的方式,似乎它可能需要我不想做的主要代码重组。不过,我可能解释错了。您是否建议使用 SwingWorker 封装所有与 GUI 无关的动作侦听器代码?
    • 是的,这就是你应该做的。如果您想在处理过程中提供 GUI 更新,那么您可以使用 publish 方法发布更新并覆盖 process 方法。 process 方法将在 EDT 上运行,因此不会破坏 Swing 的单线程模型。
    • 我现在正在做我的研究,但我的逻辑有点问题。例如,如果我想在运行doSomething() 方法时执行cancelButton.setEnabled(true),那会是什么样子?此处逻辑的可视化表示将帮助我最好地应用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多