This week's book giveaway is in the OCPJP forum.
We're giving away four copies of OCA/OCP Java SE 7 Programmer I & II Study Guide and have Kathy Sierra & Bert Bates on-line!
See this thread for details.
The moose likes Swing / AWT / SWT and the fly likes invokeLater - what's the skinny? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of OCA/OCP Java SE 7 Programmer I & II Study Guide this week in the OCPJP forum!
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "invokeLater - what Watch "invokeLater - what New topic
Author

invokeLater - what's the skinny?

clio katz
Ranch Hand

Joined: Apr 30, 2004
Posts: 101
Anyone out there who really knows the "Do's and Don't's" of javax.swing.SwingUtilities.invokeLater?

I have used, and *attempted* to use, invokeLater in cases where the GUI and GUI event Q could get (or were getting) hairy. In my experience, it hurt as often as helped. In some cases, I began to experience freeze-ups or exceptions in previously smooth-running code.

I have read too much about this without getting any clear sense of rules-of-thumb on how and when to use this construct. What I would really appreciate is if someone who looovvves invokeLater (or SwingWorker, or whatever gets you through this), could give me some 'in-a-nutshell' advice

For example, in a case when I put invokeLater around the repaint code of a Main panel, I then experienced freeze-ups in new JPanels I displayed (with invokeLater) by button click. {BTW, 'repaint' is supposedly always safe according to Sun}

Is there some special secret chart/mojo I should be using to find out 'safe' vs. 'unsafe' calls when I write code? My biz req's typically involve 10's to 100's of gui objs... help!

The Sun doc makes it seems like this is a harmless panacea to gui diplay probs, but I don't think so. If a programmer is supposed to thread-out the UI, understand which methods directly impact the UI, which get stuck in the Q, which do a bitshift, check which components are AWT vs. Swing, etc. -- then using invokeLater "properly" may be a real nuisance.

Would appreciate any tips - especially from anyone who likes/routinely uses invokeLater (i know you're out there:-)

thanks


[please feel free to move this question to another forum if this is not the appropriate one - thanks]
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

I am very interested in this topic as well. I conducted a test and I can't get SwingUtilities.invokeLater to work like the docs say it's suppose to.

Everything I read says: The invokeLater method returns immediately, without waiting for the event-dispatching thread to execute the code. Here's an example of using invokeLater

So I did code like:



Basically, what I think should happen is when I click the button, it should immediatly show as unpressed again but the thread should still sleep and the data should be printed on the console. However, what happens is the Button stays pressed until the doWork() method is complete.



GenRocket - Experts at Building Test Data
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Now interestingly enough, this works as I would expect and I didn't even use SwingUtilities...



Weird.
[ May 14, 2004: Message edited by: Gregg Bolinger ]
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

And here is a variation doing some painting on the JButton without using SwingUtilities...


[ May 14, 2004: Message edited by: Gregg Bolinger ]
clio katz
Ranch Hand

Joined: Apr 30, 2004
Posts: 101
Thanks for your responses, Greg.

I'm glad I'm not the only one who's perplexed by invokeLater! I thought it was basically a non-blocking call to give some thread/Q management hints to Swing about the runnable target.

But since I'm so murky on the guidelines at the moment, I only use it (sparingly!) for example when I'm instantiating a new GUI panel from a listener, or can't be sure that everthing in the current executing thread has gone quiet.

My ratio of time spent reading about invokeLater and SwingWorker to actually employing these tools effectively is probably 500:1! it works out to a pretty low signal:noise ratio

I'm leaning more towards your approach, Greg - to do the initial gui design keeping in mind how I need to thread-out the GUI tasks - because as an application get more complex, it gets harder and harder to anticipate GUI state. The alternative seems to be to write tons of classes to do strict MVC, which is nice in theory, until the performance hit of so many classes becomes unbearable:-(

So until I get a handle on the secret life of Swing, I am having to restrict the use cases ... which is not terrible, just frustrating. So much code to write, so little time to read about SwingWorker!

Thank you for your examples. I'm going to study them and hopefully learn a few things - it's time!
Don Kiddick
Ranch Hand

Joined: Dec 12, 2002
Posts: 580
Gregg/Clio,

In your example, I think what you are missing is that your buttons action listener code gets executed on the swing thread (you can check this using SwingUtilities.isEventDispatchThread()). This is true of all events dispatched by swing components.

Therefore you are executing on the swing thread when you make the request to execute something else on the same thread. This is why the call is synchronous - you are on the same thread ! Does that make sense ?

In response to when you should use invokeLater or invokeNow, it is whenever you are accessing swing components (e.g. getting, setting, any other operation) and are not on the swing thread already. Realise a lot of the time, you are in the swing thread. Probably more often than you realise, as stated before, event listeners are executed on the swing thread. Therefore gui interaction is normally already handled for you.
Most gui's - once the main method has created the gui, all other action is initiated by gui code and thus on the swing thread. The places you do want to look out for is if you have other non-gui inputs into the system (e.g. you have a thread listening to a server sending updates to your system.) - you will want to get the action onto the swing thread at some point.

does that help ?
D.
clio katz
Ranch Hand

Joined: Apr 30, 2004
Posts: 101
Don - thanks, that helps alot!

That's why I thought Gregg's examples and results were helpful. In the first example you can see that the _invokeLater is called in the executing GUI thread, thus the button stays depressed when he clicks it.

When he removes the _invokeLater - as you say - Swing handles the GUI.

My results have been similar, but your comment about _isEventDispatchThread is a really helpful hint. I had kind of discounted relying on this method because of some equivocal discussions I had seen in Sun forums.

The other sense that you gave - about getters, setters, background threads etc - is a really helpful way for me to think about the usage too.

If I could ask a quick question: I am still fixated on the right approach to one puzzling scenario:

What sort of high-level design considerations would I need if I had potentially long-running task(s) [with or without a GUI visual cue like a progressMonitor], that I might need to interrupt (*visually*, but not at task-level) due to severe error(s) generated external to the thread?

At the moment, I'm allowing the task to complete before I provide any visual cue about other errors. I do provide app-viewable logs, but I am considering using a status area as well.

Ultimately I'm working around the problem of not being able to reliably _showMessageDialog from any executing thread that may not be immediately "dispatch"able. On the other hand, it may just be poor design (i.e. undesirable) to popup error messages when background tasks fail.

I'm wondering if you (or Gregg, or others) have encountered this kind of problem, and what design approach you use to handle a like scenario.

In any case - thanks Don & Gregg - your feedback has been very helpful!
Don Kiddick
Ranch Hand

Joined: Dec 12, 2002
Posts: 580
Originally posted by clio katz:
What sort of high-level design considerations would I need if I had potentially long-running task(s) [with or without a GUI visual cue like a progressMonitor], that I might need to interrupt (*visually*, but not at task-level) due to severe error(s) generated external to the thread?

At the moment, I'm allowing the task to complete before I provide any visual cue about other errors. I do provide app-viewable logs, but I am considering using a status area as well.

Ultimately I'm working around the problem of not being able to reliably _showMessageDialog from any executing thread that may not be immediately "dispatch"able. On the other hand, it may just be poor design (i.e. undesirable) to popup error messages when background tasks fail.


I don't really understand the question. From what I understand :
You have a task that runs in a thread.
Something can go wrong external to that thread and when it does, you want the thread to be stopped and a message to be displayed to the user.

I don't think that is correct as it doesn't seem to relate to what we're talking about.

Ultimately I'm working around the problem of not being able to reliably _showMessageDialog from any executing thread that may not be immediately "dispatch"able.

I don't understand this. In what situations would you not be able to call showMessageDialog ? If you want it to be exectuted synchronously call SwingUtilities.invokeAndWait().


Please can you rephrase your question(s) ?

thanks, D.
Eddie Vanda
Ranch Hand

Joined: Mar 18, 2003
Posts: 281
Hi Guys,

Maybe my problem relates to yours. I have a GUI client application which sets up around 10 panels on a tabbed pane. After accepting a login, it takes over 20 seconds to fetch data from the server and then to show the gui. When the gui does show, it takes about 1 second to show all the tabs. I have pacified the users by fiddling with the cursor while they are waiting, but I feel I should be able to use another thread to fetch the data and show at least the first frame while the others are being set up. The login screen shows until the gui shows in its place. My gui has code that should show some statements on a status screen on the login screen but that does not work.

What I need is a pattern to follow. The examples of invokelater that I have seen so far are too simple. My app has almost a 100 classes so I need a model app which splits all the components into different classes.

I guess I'll get there if I keep on hacking but there must be a model somewhere that I can follow.

Ed


The nice thing about Standards is that there are so many to choose from!
Don Kiddick
Ranch Hand

Joined: Dec 12, 2002
Posts: 580
Eddie,
so it takes 20 seconds to get the data from the server and 1 second to display the gui. You could you use 2 threads to do this but the quickest it'll ever take is 20 seconds. I think your time but would be better off spent trying to optimise how you get data from the server (or the server itself).

D.
Eddie Vanda
Ranch Hand

Joined: Mar 18, 2003
Posts: 281
Hi Don,

There are ten screens on a tabbed pane and the user would be quite interested in the first one. It is a booking/notes system and the other screens show further information, so it really only takes about two seconds to get the info for the first screen.

I guess that I need a thread to fetch the information screen by screen and then progressively do invokeLater on each screen's gui to keep the user busy with the first few screens while the later screens are loading.

The system has been operational with about 30 users since the start of this year so I can take a bit longer to get this right. I have solved most of the major problems this year so now I am trying to make it nice without disturbing the code already working.

Ed
[ May 17, 2004: Message edited by: Eddie Vanda ]
Don Kiddick
Ranch Hand

Joined: Dec 12, 2002
Posts: 580
Originally posted by Eddie Vanda:
Hi Don,

There are ten screens on a tabbed pane and the user would be quite interested in the first one. It is a booking/notes system and the other screens show further information, so it really only takes about two seconds to get the info for the first screen.

I guess that I need a thread to fetch the information screen by screen and then progressively do invokeLater on each screen's gui to keep the user busy with the first few screens while the later screens are loading.

The system has been operational with about 30 users since the start of this year so I can take a bit longer to get this right. I have solved most of the major problems this year so now I am trying to make it nice without disturbing the code already working.

Ed

[ May 17, 2004: Message edited by: Eddie Vanda ]


Lazy loading is the simple solution. This would be where you load each tab's data on the first time the user clicks on that tab. So the user would see a 2 second pause the 1st time they click on each tab, so the app would seem more responsive.
You could preemptive load some of the data, which would make it even quicker.

does that make sense ?
D.
clio katz
Ranch Hand

Joined: Apr 30, 2004
Posts: 101
Eddie/Don -

I think I understand the problem that Eddie is having (and I face the potential of having that prob too, if the database grows large enough).

As far as approaches, I like the approach that they use in SwingSet2 for loading the demo-apps and toolbar buttons. It's a form of lazy loading that is not "on-demand" loading, but "as-able" loading (i.e. threaded).

They first create a small diversion with the splash screen, then load non-toolbar-dependent resources like menuBar and preload the first demo app, then drop the splash and lazy-load the remaining demos and corresponding toolbar icons.

I studied their design and - quite honestly - the details were "too deep" for me! but the general approach seems very useful. if i have to re-factor down the road, i will try a similar approach.

I think that Eddie is already onto this approach (re: loading first tab, making that app accessible (with dep restrictions), then lazy-loading remaining tabs).
clio katz
Ranch Hand

Joined: Apr 30, 2004
Posts: 101
Originally posted by Don Kiddick:

I don't understand this. In what situations would you not be able to call showMessageDialog ? If you want it to be exectuted synchronously call SwingUtilities.invokeAndWait().


Please can you rephrase your question(s) ?

thanks, D.


My question really kind of harkens back to one of the scenarios that you mention (background thread listening to server, etc). I can give an use case:
  • The application is in 'ready' state
  • a background task has been initiated to monitor changes to network service configuration
  • user opens a panel to execute a long-running task
  • long running task begins, displaying progressMonitor
  • background thread dies due to lost connection


  • Assume "long-running task" is *not* directly dependent upon background task. However, per biz reqs, user should be notified of any FATAL background-task event when it occurs.

    In this case, when I try to display a JOptionPane message dialog, nothing happens. Although it's clear to me (esp. now:-) that this is occurring because I'm not on the Swing event thread, I need to adopt some kind of design/policy for handling cases like this.

    At the moment I'm just "designing around it" with widgets like a Status panel in the main window.

    Other issue is that I hope to never have to code InvokeAndWait, except in very restrictive (i.e. uncomplicated) scenarios, when I am sure that there is no potential for deadlock.

    The other use case (described by Eddie) is vulnerable to the same sorts of issues, whether using 'on-demand' or 'as-able' loading... The heart of the design problem, if I can oversimplify a little, is how to deal with "insertions" or "overrides" of a single-threaded GUI Q like Swing.

    It's undoubtedly possible (for some gifted people!), but I'm trying to get an idea of whether the challenges are mainly design (i.e. a pattern-approach like Eddie mentioned), or generally code-till-it-works.

    Thanks for your replies - I think I'm on a much better footing with this now. Mainly I realize that I'm going to have to

    .assess the tools available for managing GUI threads (such as isEventDispatchThread),
    .think-through and settle on a design policy,
    .take-the-leap into working with the Swing architecture to get the right bits on the screen at the right time!

    Thanks again - comments and feedback are always welcomed.
    Don Kiddick
    Ranch Hand

    Joined: Dec 12, 2002
    Posts: 580
    Sorry my friend, I still don't see any problem with what you're trying to do...in my eyes the design could be a simple as below :



    D.
    clio katz
    Ranch Hand

    Joined: Apr 30, 2004
    Posts: 101
    Thanks, Don.

    I understand your point from the code fragment - that I can get the dialogs to display asynchronously ... eventually. The fact that mine has chosen not to display at all - and this discussion - has given me time to re-think the design. I'm beginning to think that I've talked myself out of plopping dialogs on top of dialogs, so just as well that I haven't managed to do it with Swing. (And I do now realize how wicked I was to think I could/should do it in the first place!)

    I finally thought of how RedHat blinks that little "Code Red" Icon in the corner of your window when you need to upgrade. What a nuisance it would be if they popped-up a dialog in the middle of my work instead! [On the other hand, the only *nix machines that I have ever had compromised were RH, so I know there is *also* such a thing as too much subtlety in presenting UI error messages)

    But I do feel better prepared for when I face with this problem next time. there *will* be a next-time ... sadly maybe a few hours away:-()

    Thanks! Again!
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: invokeLater - what's the skinny?