Swing,如何正确更新UI

时间:2011-02-07 11:54:48

标签: java swing user-interface

在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的父组件。这有效,但有时我可以看到屏幕闪烁。我做错了吗?有没有更好的方法呢?

4 个答案:

答案 0 :(得分:5)

正确的方法是使用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()。当然,这仅对您手动绘制的组件有效。对于您重复使用的组件,只需调用它们的值更改方法。

答案 1 :(得分:4)

我个人使用SwingWorker,尽管其他一些评论/答案:

  • 尽管保持UI响应不是原始问题的一部分,但最好还是这样做(我不能想到用冗长的处理来锁定EDT的一个好理由。)
  • 它提供了一个done()方法,可以在任务完成后默认在EDT上执行,省去了在invokeLater()中手动包装内容的需要
  • 它更具可扩展性,提供了一个框架,允许稍后在需要的时候轻松添加进度等信息。

我最近看到很多SwingWorker讨厌,我不明白为什么。它是一个设计精美,可扩展的类,专门用于这样的目的,效果很好。是的,你可以在线程中包装并启动它们并让它们在invokeLater()中包含其他方法,但是为什么在有更好的免费提供时重新发明轮子呢?

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

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