【问题标题】:Swing, how to properly update the UISwing,如何正确更新 UI
【发布时间】:2011-02-07 11:54:47
【问题描述】:

在 Swing 上做一些操作后更新 UI 的正确方法是什么?

例如,单击按钮后,调用可能几乎是即时的或需要几秒钟的方法。事实上,所有的应用程序逻辑都是通过 Web 服务远程完成的,所以等待应用程序响应是正常的。

我的按钮事件处理程序可能如下所示:

myButton.addActionListener(new java.awt.event.ActionListener() {
   public void actionPerformed(java.awt.event.ActionEvent evt) {
       //callWebService();
       //do stuff
       //updateUI(); // <----- repaint? revalidate? what?
   }
});

我当前的实现调用 updateUI 方法,该方法在内部调用 validate() 和 repaint() 到拥有 UI 的父组件。这可行,但有时我可以看到屏幕闪烁。我做错了吗?有没有更好的方法?

【问题讨论】:

  • 据我了解,这个问题是关于在做某事后更新 UI,而不是在另一个线程中做某事以保持 UI 响应。不过,我不太明白为什么问题中提到了该方法的执行时间。
  • 我提到了执行时间,因为看起来 Swing 在尝试加载组件时的行为有点不同,加载时间过长,因此可能需要重绘屏幕。
  • 我仍然会使用 SwingWorker 提供的回调来执行此操作 - 这是一个已经提供的模型,虽然 OP 没有提到保持 UI 响应作为问题的一部分,但这是一个很好的做法无论如何都要这样做。

标签: java swing user-interface


【解决方案1】:

正确的方法是使用SwingWorker,但如果您想手动执行,则必须实现以下模式:

@Override public void actionPerformed(java.awt.event.ActionEvent evt) {
  new Thread() {
    @Override public void run () {
      //callWebService();
      //do stuff
      SwingUtilities.invokeLater(new Runnable(){
        @Override public void run() {
          //updateUI(); // <----- repaint? revalidate? what?
        }
      });
    }
  }.start();
}

对于重绘/重新验证问题,通常调用revalidate() 然后repaint()。当然,这仅对您手动绘制的组件有效。对于您重复使用的组件,只需调用它们的值更改方法即可。

【讨论】:

  • 为什么不使用 SwingWorker 的“正确”方式呢?它提供了一个很好的、易于使用的界面来为您处理所有回调内容,并提供了一种在任务完成时更新 UI 的简单方法。
  • @berry,我认为“没有 SwingWorker,这是这样做的正确方法”应该被理解为“使用 Swing Worker 是正确的方法,但是如果你想不这样做使用它...”
  • 啊,我明白了——虽然有点模棱两可,但我认为它可以采取任何一种方式!
  • 谢尔盖是对的。抱歉,这里没有母语为英语的人;)
【解决方案2】:

我个人会为此使用 SwingWorker,尽管还有其他一些 cmets / 答案:

  • 尽管保持 UI 响应不是原始问题的一部分,但无论如何最好还是这样做(我想不出一个很好的理由来锁定 EDT 并进行冗长的处理。)
  • 它提供了一个done()可以实现的方法,当任务完成时默认在EDT上执行,省去了在invokeLater()中手动打包东西的需要
  • 它的可扩展性更强,提供的框架允许以后根据需要轻松添加进度等信息。

我最近看到了很多对 SwingWorker 的普遍厌恶,我不明白为什么。这是一个设计精美、可扩展的类,专门用于这样的目的,效果很好。是的,您可以将事物封装在线程中并启动它们,然后让它们将其他方法封装在 invokeLater() 中,但是当有更好的免费提供时,为什么要重新发明轮子呢?

【讨论】:

    【解决方案3】:

    将长时间运行的任务转移到另一个线程。将事件发送回 AWT 事件调度线程 (EDT) 以使用 java.awt.EventQueue.invokeLater 更新 GUI。

    【讨论】:

      【解决方案4】:

      您通常不需要做任何事情:如果您使用 swing 组件方法或其模型的方法,则会触发必要的事件并且 GUI 应该会自动更新自身。

      如果您定义自己的模型,则不会出现这种情况(忘记触发必要的事件,但这是您模型中的错误,应该在那里修复。

      【讨论】:

      • 所以如果我在 GUI 事件处理线程中调用 JSpinner.setValue() 方法,它应该自动更新 UI 吗?我记得它有时在我的一个应用程序中没有这样做。如果我移动了窗口或做了一些会使它无效的事情(比如暂时遮蔽其他窗口),那么它会更新。这是 JRE 中的错误吗?
      • 是的,如果您确保在 EDT 中调用该方法,ti 应该自动更新 GUI(一旦在事件调度线程 (EDT) 中没有其他事情可做)。无法说明为什么它不能在您的某个应用中运行,但应该可以。
      猜你喜欢
      • 2017-03-26
      • 2020-12-04
      • 1970-01-01
      • 2010-11-13
      • 2019-01-05
      • 1970-01-01
      • 2017-11-01
      • 1970-01-01
      • 2013-02-07
      相关资源
      最近更新 更多