8

I'm using Swing for the first time to create a simple GUI. It consists of a JFrame upon which I have placed a single JButton which, when clicked, calls some other code which takes approx. 3 seconds to return.

Just before the call to this code, in actionPerformed(), I want to update the text on the button to inform the user that processing is occuring. My problem is that the text on the button does not update until after the 3-second call has returned. I want the updated text to be present during the call, then I'll change it back afterwards.

Calling repaint() on the JButton doesn't do anything and calling it on the JFrame results in "Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException" being thrown when I click the button.

jjnguy
  • 136,852
  • 53
  • 295
  • 323
William
  • 13,332
  • 13
  • 60
  • 73

2 Answers2

15

What's happening is that the 3-second code is executing in the GUI thread, so the button doesn't have a chance to update until it's done.

To solve this, start a SwingWorker to do the long-running operation; then you'll still be free to do things in the GUI while you're waiting for it.

Here are a couple of tutorials on the subject, and the SwingWorker Javadocs referenced above have some code also.

Sample code

public void actionPerformed(ActionEvent e) {
    SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
        @Override
        public Void doInBackground() {
            // Call complicated code here
            return null;
            // If you want to return something other than null, change
            // the generic type to something other than Void.
            // This method's return value will be available via get() once the
            // operation has completed.
        }

        @Override
        protected void done() {
            // get() would be available here if you want to use it
            myButton.setText("Done working");
        }
    };
    myButton.setText("Working...");
    worker.execute();
}
Community
  • 1
  • 1
Michael Myers
  • 188,989
  • 46
  • 291
  • 292
  • Cheers to posting the same answer! We tend to do that a lot. (a couple of times) – jjnguy Jun 10 '09 at 19:57
  • Added sample code because otherwise your 54-second advantage is insurmountable. :P – Michael Myers Jun 10 '09 at 20:04
  • My sample code is a link away. You have to travel to the other answer I posted. – jjnguy Jun 10 '09 at 20:23
  • P.S. It is usually not my way to upvote a 'competing' answer, but I feel you have posted a better answer. – jjnguy Jun 10 '09 at 20:25
  • But my sample code is actually tailored to this specific question! That makes it better in ways that I can't quite think of! (I'm upvoting your answer too, but it looks like you've maxed out for the day anyway.) – Michael Myers Jun 10 '09 at 20:30
  • How can you tell how much rep I've gotten in a day? I know I can check my 'envelope' – jjnguy Jun 10 '09 at 20:31
  • Okay, *now* I can think of the ways it's better. :P (I'm now at +205 for the day, so you can have the rest of the Swing questions if you want.) – Michael Myers Jun 10 '09 at 20:32
  • Ha, I'm no where close to catching you in the swing votes total, and I'm at 200 for the day. Looks like there will be some swing questions up for grabs. – jjnguy Jun 10 '09 at 20:34
  • I saw you get three upvotes without your rep changing. Or maybe I hacked into your account. Whichever you prefer. – Michael Myers Jun 10 '09 at 20:34
  • You've got a higher average in Swing questions than I do, though. (And here's a -1 and +1 to compensate for the downvote you just got elsewhere.) – Michael Myers Jun 10 '09 at 20:38
  • Hey, no fair. Somebody took away a vote and then re-added it, for a net of -5 points. :( – Michael Myers Jun 10 '09 at 20:48
  • That was my bad... I was trying to see if adding and removing votes affected the total count at all. (it doesn't) – jjnguy Jun 10 '09 at 20:53
  • "worker" needs a semi-colon at the end of the line, and I had to add "return null;" in "doInBackground()" to get it to properly compile. – Zach May 03 '12 at 19:29
  • @Zach: I knew the return statement was necessary, but somehow I'd never noticed the missing semicolon. Thanks for pointing it out. – Michael Myers May 03 '12 at 19:43
10

The problem here is that your long running task is blocking the thread that would normally paint the GUI.

The usual way around this is to throw the longer running task off into another thread.

This can be done fairly easily using a SwingWorker.

This question may provide some helpful information as well.

Community
  • 1
  • 1
jjnguy
  • 136,852
  • 53
  • 295
  • 323