views:

748

answers:

2

I have a UI built inside a JFrame. One of the buttons starts a long running call (still within the same java process), and during it's execution, the UI is frozen.

I figured, to make it clear that things are still running, I can display a progress bar, perhaps in a popup, so that the user can be kept up-to-date as to what the program is doing.

So I'm creating a new JDialog, adding a JProgressBar to it, and updating it as things happen. The problem is that that dialog's content isn't getting updated. Changes I make to it's title show up immediately, and anything I output to the console, but nothing in the UI itself.

Is there a command I can issue to force a repaint?

Here's the core of this section:

  killWindow = new JDialog();
  killWindow.setUndecorated(true);
  killWindow.setTitle("stopping tests - 0 of " + numActive);
  killProgress = new JProgressBar(0, numActive);
  killWindow.add(killProgress);
  killProgress.setStringPainted(true);
  killWindow.pack();
  killWindow.setLocationRelativeTo(frame);
  killWindow.setVisible(true);

Then, as we progress...:

  killProgress.setValue(++killedTests);                    // not seen!
  killProgress.setString("Killing test on " + nickname()); // not seen!
  log("Killed another test, " + killedTests + " so far");  // visible in real time
  killWindow.setTitle("stopping tests - " + killedTests +
                      " of " + killProgress.getMaximum()); // visible in real time

What am I missing? I tried googling and searching here on SO, and haven't really seen anything obvious?

+3  A: 

You have to perform your long running task in another thread.

There is this thread called "AWT Event Dispatch Thread" which is in charge of the update of UI components. If it is busy performing your long running task it won't update the UI ( nor refresh you dialog ).

You may consider using SwingUtilities or a SwingWorker.

From the SwingWorker documentation here's a sample

final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
   @Override
   public String doInBackground() {
       return findTheMeaningOfLife();
   }

   @Override
   protected void done() {
       try { 
           label.setText(get());
       } catch (Exception ignore) {
       }
   }
}

(new MeaningOfLifeFinder()).execute();

By running your long task in a different thread, you're allowing the AWT event dispatch thread to show a responsive UI.

You may take a look at this "Lesson from the Java tutorial" to understand better these concepts.

OscarRyz
+1  A: 

It sounds like you might be running your long running task on the Event Dispatch Thread (EDT). Take a look at SwingWorker. If you are using 1.6 it's built in:

http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html

If not, you can find more info at:

http://en.wikipedia.org/wiki/SwingWorker

Scott A Miller