views:

933

answers:

2

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.

+8  A: 

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.

jjnguy
+8  A: 

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.


Edit: Since jjnguy beat me to posting, I'll go ahead and whip up some sample code. This is based on one of the examples in the SwingWorker Javadocs:

public void actionPerformed(ActionEvent e) {
    SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
        @Override
        public Void doInBackground() {
            // Call complicated code here
            // If you want to return something, 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();
}
Michael Myers
Cheers to posting the same answer! We tend to do that a lot. (a couple of times)
jjnguy
Added sample code because otherwise your 54-second advantage is insurmountable. :P
Michael Myers
My sample code is a link away. You have to travel to the other answer I posted.
jjnguy
P.S. It is usually not my way to upvote a 'competing' answer, but I feel you have posted a better answer.
jjnguy
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
Noooooooooooooooooooo!!!!!!!!!!!
jjnguy
How can you tell how much rep I've gotten in a day? I know I can check my 'envelope'
jjnguy
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
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
I saw you get three upvotes without your rep changing. Or maybe I hacked into your account. Whichever you prefer.
Michael Myers
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
Hey, no fair. Somebody took away a vote and then re-added it, for a net of -5 points. :(
Michael Myers
That was my bad...I was trying to see if adding and removing votes affected the total count at all. (it doesn't)
jjnguy