Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swing, how to properly update the UI

What is the right way to update the UI after doing some operations on Swing?

For example, after clicking a button, a method is called that may be almost instant or take some seconds. In fact, all the applicaton logic is done remotely through a web service, so it's normal to wait a little bit for the application to respond.

My eventhandler for a button may look like these:

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

My current implementation calls the updateUI method which internally call validate() and repaint() to the parent component that holds the UI. This works, but sometimes I can see the screen flickering. Am I doing it wrong? Is there a better way to do it?

like image 778
Hectoret Avatar asked Feb 07 '11 11:02

Hectoret


2 Answers

The right way would be to use SwingWorker, but if you want to do it manually you'll have to implement the following pattern:

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

For the repaint/revalidate question, normally call revalidate() then repaint(). this is, of course, only valid for component that you manually draw. For components that you reuse, just call their value change methods.

like image 127
Olivier Grégoire Avatar answered Sep 28 '22 08:09

Olivier Grégoire


I'd personally use SwingWorker for this, despite some of the other comments / answers:

  • Despite the fact keeping the UI responsive isn't part of the original question, it's good practice to do this anyway (I can't think of a single good reason to lock up the EDT with lengthy processing.)
  • It provides a done() method that can be implemented which will be executed on the EDT by default when the task is complete, saving the need for manually wrapping up things in invokeLater()
  • It's more extensible, providing the framework to allow information like progress to be added easily later if it's so desired.

I've seen a lot of SwingWorker hate in general recently, and I don't understand why. It's a nicely designed, extensible class specifically for purposes such as this that works well. Yes, you could wrap things up in threads and launch them and have them wrap other methods up in invokeLater(), but why reinvent the wheel when there's a better one available for free?

like image 35
Michael Berry Avatar answered Sep 28 '22 07:09

Michael Berry