void OnMnuDoLengthyOp()
{
menuframe.UpdateWindow(); // All outstanding UI events will be
processed here.
LengthyOp(); // NOW I can call this.
}
(where 'menuframe' is the frame window to which the menu is attached) to
achieve this.
Any chance? It's no biggie to do the Runnable thing, I just would like to
investigate other possibilities.
--
--
Jason Teagle
ja...@teagster.co.uk
-----------------------------------------------------------
A list of programming resources I use:
ML: www.windev.org, www.codecipher.com, www.beginthread.com
MB: www.codeguru.com, www.codeproject.com
NG: comp.lang.java.*
OI: www.php.net
-----------------------------------------------------------
> I know I can use invokeLater() to allow the event dispatching thread to
> finish up, and then the code runs; but it requires a Runnable, and it
seems
Curious... why does this not work:
public void actionPerformed(ActionEvent e)
{
EventQueue.invokeLater(new Thread()
{
public void run()
{
// Do lengthy op...
}
}
);
}
? It compiles and runs and performs the lengthy op... it just doesn't allow
the (Swing) menu to hide before calling the lengthy op!
I also tried outside the handler (from a physical code position point of
view), in the routine called -by- the handler - no change.
Am I missing something?
>
>"Jason Teagle" <ja...@teagster.co.uk> wrote in message
>news:TD9B9.1265$ic7....@newsfep1-gui.server.ntli.net...
>
>> I know I can use invokeLater() to allow the event dispatching thread to
>> finish up, and then the code runs; but it requires a Runnable, and it
>seems
>
>Curious... why does this not work:
>
>public void actionPerformed(ActionEvent e)
>{
> EventQueue.invokeLater(new Thread()
> {
> public void run()
> {
> // Do lengthy op...
> }
> }
> );
>}
>
>? It compiles and runs and performs the lengthy op... it just doesn't allow
>the (Swing) menu to hide before calling the lengthy op!
>
>I also tried outside the handler (from a physical code position point of
>view), in the routine called -by- the handler - no change.
>
>Am I missing something?
First of all, call SwingUtilities.invokeLater rather than
EventQueue.invokeLater. Admittedly, all SwingUtilities does is call
EventQueue, but the docs always say to use SU, indicating that's the
Right Thing to Do. You never know when a future JDK will implement
SU.iL() to do something different.
Secondly, why create a Thread, when you can create a simple Runnable?
Maybe the effort of creating a Thread object is causing the behavior
you're seeing? (You'd still get the same end effect, and no extra
thread is actually started, since nothing ever calls start() on that
Thread object...)
Paul Brinkley
la...@starpower.net
> >Curious... why does this not work:
> >
> First of all, call SwingUtilities.invokeLater rather than
> EventQueue.invokeLater. Admittedly, all SwingUtilities does is call
> EventQueue, but the docs always say to use SU, indicating that's the
> Right Thing to Do. You never know when a future JDK will implement
> SU.iL() to do something different.
OK, noted.
>
> Secondly, why create a Thread, when you can create a simple Runnable?
> Maybe the effort of creating a Thread object is causing the behavior
> you're seeing? (You'd still get the same end effect, and no extra
> thread is actually started, since nothing ever calls start() on that
> Thread object...)
I didn't realise I could create an instance of an interface? I thought I had
to create an instanceof a class that implemented the interface!
But surely even with a Thread it should still wait until AWT had emptied its
queue before doing it?
You do. But you can do it on the fly:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//do stuff here
}
});
Jim S.
>
>"Paul Brinkley" <la...@starpower.net> wrote in message
>news:5cgatug2aar90m9mc...@4ax.com...
>
>> Secondly, why create a Thread, when you can create a simple Runnable?
>> Maybe the effort of creating a Thread object is causing the behavior
>> you're seeing? (You'd still get the same end effect, and no extra
>> thread is actually started, since nothing ever calls start() on that
>> Thread object...)
>
>But surely even with a Thread it should still wait until AWT had emptied its
>queue before doing it?
It should. That's kinda what I was trying to say; that Thread object
will be treated by the AWT event queue exactly as any other Runnable,
even though it's slightly more weighty than your typical
garden-variety Runnable.
Paul Brinkley
la...@starpower.net
invokeLater() will not execute the code in a separate thread. It will still
run inside the event dispatching thread. If you want to kick off a new thread
to do lengthy work, you need to do that on your own, or you could use
SwingWorker.java which can be downloaded from the Sun site
To create a new Thread and start it right away, you can use a similar
construct:
new Thread(new Runnable()
{
public void run()
{
// call lengthty procedure here
}
}).start();
Cheers
Thomas
> invokeLater() will not execute the code in a separate thread. It will
still
> run inside the event dispatching thread. If you want to kick off a new
thread
> to do lengthy work, you need to do that on your own, or you could use
> SwingWorker.java which can be downloaded from the Sun site
Well, I'm not really concerned about whether it will start a separate thread
or not; I'm concerned that it doesn't appear to do what the docs claim:
"If invokeLater is called from the event dispatching thread -- for example,
from a JButton's ActionListener -- the doRun.run() will still be deferred
until all pending events have been processed"
The only thing I can think of that would support what I'm seeing is if,
somehow, the code for hiding a menu item that has been selected is not
issued right away, and so the AWT considers its event queue empty and goes
ahead with the lengthy code, and only later does the event to hide the menu
get issued. But logic would dictate that as part of the overall handler for
the menu (of which the call to actionPerformed() is part), the menu would be
hidden - thus generating AWT events that should be cleared up before the
lengthy code gets run.
In fact, invokeLater() seems to be useless.
I'm not going to lose any sleep over this, but I would like to know if I've
done something wrong, or if there is a problem in the JVM here...
If the hiding of the menu occurs after the code run by invokeLater, it
indicates that the hiding of the menu is likely being done by an event
handler. That is, a hiding event is added to the event queue after all
the actionListeners for the menu event have returned. If an
actionListener invokes invokeLater, the invokeLater Runnable is processed
before the hiding event (because the invokeLater Runnable is in the event
queue ahead of the hiding event).
OK, I feel stupid. It didn't occur to me until today what you were
doing wrong in your original code:
public void actionPerformed(ActionEvent e)
{
EventQueue.invokeLater(new Thread()
{
public void run()
{
// Do lengthy op...
}
}
);
}
What you should do is more like this:
public void actionPerformed(ActionEvent e)
{
new Thread() {
public void run()
{
// Do lengthy op...
}
}.start();
}
And yes, invokeLater doesn't make an appearance, so yes, invokeLater
is useless, but only in this case. invokeLater is useful if your
lengthy operation involves invoking any methods on any realized GUI
components. For example:
public void actionPerformed(ActionEvent e)
{
new Thread() {
public void run()
{
// Do lengthy op...
SwingUtilities.invokeLater(new Runnable() {
statusBar.setText ("Done.");
});
}
}.start();
}
invokeLater isn't typically called from the AWT thread. It's
typically called from some other thread. It can also be safely called
from the AWT thread, and occasionally there's reason to.
The AWT event queue ideally is a pipeline of things to process. Each
thing should be doable virtually instantaneously (no massive image
processing, blocking on network I/O, etc.). There are three types of
things that can go in that queue:
1. GUI events (ActionEvent, MouseEvent, etc.)
2. repaint requests
3. Runnables (from invokeAndWait or invokeLater)
All invokeLater does is stick a Runnable in the pipe and move on.
invokeAndWait will stick a Runnable in the pipe and then block the
current thread until the AWT is done with that Runnable. That's why
you can't run invokeAndWait in the AWT thread; it would lock forever.
invokeLater's main purpose is to ensure thread safety. You could call
JLabel.setText("foo") from anywhere, but you really shouldn't, since
it can lead to kooky drawing behavior in the GUI.
Paul Brinkley
la...@starpower.net
> OK, I feel stupid. It didn't occur to me until today what you were
> doing wrong in your original code:
No no - you weren't wrong... I didn't -want- to use another thread
specifically.
I wanted to allow all pending AWT events (which I assumed would include
hiding the menu) to be completed before my length op started - I'm quite
happy for the lengthy op to pause the code while it works, it makes sense to
in a way in my project - I just didn't want it to stop the menu hiding
before it started.
> The AWT event queue ideally is a pipeline of things to process. Each
> thing should be doable virtually instantaneously (no massive image
> processing, blocking on network I/O, etc.). There are three types of
> things that can go in that queue:
>
> 1. GUI events (ActionEvent, MouseEvent, etc.)
> 2. repaint requests
> 3. Runnables (from invokeAndWait or invokeLater)
Yes, I understood this pipe (queue) concept (but thankyou). I had assumed
that hiding the menu would already be such an AWT event waiting in the
queue, and thus I could encourage AWT to clear its queue before starting on
my work... but it seems that assumption was wrong, the hiding doesn't occur
until after the action handler returns, which is useless to me...
>
>"Paul Brinkley" <la...@starpower.net> wrote in message
>news:nt5itu4qhl2lmc4a1...@4ax.com...
>
>> OK, I feel stupid. It didn't occur to me until today what you were
>> doing wrong in your original code:
>
>No no - you weren't wrong... I didn't -want- to use another thread
>specifically.
>
>I wanted to allow all pending AWT events (which I assumed would include
>hiding the menu) to be completed before my length op started - I'm quite
>happy for the lengthy op to pause the code while it works, it makes sense to
>in a way in my project - I just didn't want it to stop the menu hiding
>before it started.
>
>I had assumed
>that hiding the menu would already be such an AWT event waiting in the
>queue, and thus I could encourage AWT to clear its queue before starting on
>my work... but it seems that assumption was wrong, the hiding doesn't occur
>until after the action handler returns, which is useless to me...
The "right thing" for you to do is to run that lengthy op in a
separate thread anyway. In the meantime, I have a theory as to what
may be going on.
When the menu item is clicked (or the user presses Enter or whatever),
an ActionEvent is put on the AWT queue. (There's also 1-3 MouseEvents
or a KeyEvent or two, but they get processed without incident.) That
ActionEvent causes your actionPerformed() to be run in the AWT thread.
Your code, again:
public void actionPerformed(ActionEvent e)
{
EventQueue.invokeLater(new Thread()
{
public void run()
{ /* Do lengthy op... */ }
});
}
So, your code pops another task on the AWT queue, then ends
immediately.
Your actionPerformed() might not be the only actionPerformed(), of
course. There may be other ActionListeners, and as you probably know,
they may be invoked in any order. It's possible that the code that
causes the menu to hide is triggered by an ActionEvent on its
MenuItems, and that it's getting called after your actionPerformed().
Now, so far as you know, this is okay, since all actionPerformed()
methods will be invoked in the AWT thread before it's able to get to
that Runnable (Thread) you put in the queue.
However, it may be that that actionPerformed() hides the menu by
putting yet another repaint event on the queue. If so, that repaint
wouldn't happen until after your lengthy op is finished.
In general, while your lengthy op is running in the AWT thread, the
GUI will cease any and all repaints. This is easy to see by dragging
the GUI window partially offscreen, or hiding bits of it with windows
from other processes.
You said this apparent stasis of the GUI makes sense in a way for your
project. Maybe so. But given all the weirdness that happens as a
natural result of running lengthy tasks in the AWT thread, it might
make more sense for you to run the task in a side thread anyway, and
disable the GUI using a modal, non-dismissable "Please wait..."
dialog.
Paul Brinkley
la...@starpower.net
Actually if the "lengthy" task takes anything more than say 2 to 3
seconds, it is always better to use a thread. If you don't want to
handle any user events till the task is complete, it would be better to
use some other technique to block user events (like a modal dialog,
glasspane etc).
The difference between the two is that if you block the EDT itself,
paint operations are also blocked for that duration. So if the user
drags another window across yours during this time, remnants of that
window will show up within your Window, thus giving an appearance to the
user that your app has crashed.
> Yes, I understood this pipe (queue) concept (but thankyou). I had assumed
> that hiding the menu would already be such an AWT event waiting in the
> queue, and thus I could encourage AWT to clear its queue before starting on
> my work... but it seems that assumption was wrong, the hiding doesn't occur
> until after the action handler returns, which is useless to me...
If you must do this absolutely, you could do it in two ways. One is to
use a Timer to start your task after a small delay - another one (more
of a hack) is to jave an invokeLater runnable invoke another
invokeLater runnable that starts the task. This should delay the
processing by 2 EDT cycles which may be sufficient ?
BK
> Actually if the "lengthy" task takes anything more than say 2 to 3
> seconds, it is always better to use a thread. If you don't want to
> handle any user events till the task is complete, it would be better to
> use some other technique to block user events (like a modal dialog,
> glasspane etc).
OK, you're both right, I should use another thread anyway. It certainly
won't do any harm, and if the user does decide to try and do something
during that time (about 5 seconds maximum), it will be noticeably sluggish /
frozen, so it won't look any better than a sticky menu item.
> If you must do this absolutely, you could do it in two ways. One is to
> use a Timer to start your task after a small delay - another one (more
> of a hack) is to jave an invokeLater runnable invoke another
> invokeLater runnable that starts the task. This should delay the
> processing by 2 EDT cycles which may be sufficient ?
I believe (haven't tried yet) that I can add a ComponentListener to the
container that houses the menu items, and that way I can use the
componentHidden() handler to know when the menu has gone. I will try this
technique.
Does that seem less of a hack?
Not quite. "Lengthy" is actually anything that might possibly take more
than 1/10th of a second. That's a well known metric in the UI design world.
Really? I had heard 1/5 seconds. Not that I wouldn't be surprised.
This wouldn't be the first time I got conflicting bits of UI
guideline.
Just where -do- all the human factors experts hang out? It sure
doesn't seem to be comp.human-factors. Or Jakob Neilsen's site. Or
WebWord.
Paul Brinkley
la...@starpower.net
Just put the long task in a side Thread, and everything else should
take care of itself.
Paul Brinkley
la...@starpower.net
The figures I see quoted around the place (perhaps they are just quoting
one another) say 1/10th of a second for a delay to be noticeable, 1/3rd
of a second until something seems to have gone wrong.
Of course that's the whole round-trip time. You still have to deliver
the event beforehand and redraw aftwerwards. GC may also kick in. And if
there is a wait for mouse up instead of mouse down, then you've probably
thrown the 1/10th away before you started.
> Just where -do- all the human factors experts hang out? It sure
> doesn't seem to be comp.human-factors. Or Jakob Neilsen's site. Or
> WebWord.
Probably with like *real* humans. :) Or hung up on something like this:
http://projects.interaction-ivrea.it/endofyear/en/research/faraway.asp
Tackline
--
http://www.tackline.demon.co.uk/
Unemployed Java Developer of Central London.
To throw in another figure, I have seen research papers indicating that
the smallest actual detectable delay for a human being is about 50
milliseconds, or 1/20th of a second. I've also seen papers on
implementing real-time garbage collection for interactive applications
which use that 50 ms number as a guideline.
The "right" number probably depends on what's happening. If the user is
doing something where they expect a big change, then longer delays are
probably fine. The strictest number, 50 ms, is probably not a practical
guide except in situations where the user isn't expecting a major change
(eg, it was used as a guide for randomly initiated GC delays as I
mentioned above). The 100 ms number that Jon gave is perhaps more
practical for "things are happening" sorts of operations, and your 200
ms number perhaps for opening new windows or the like, where there's
clearly something big going on.
--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
This was an interesting discussion - I learned quit a bit! I do have
another question for you though.
What is the best way to "wait" for for a pending I/O receive
operation? Here'e what's happening.
* Right after showing a modal dialog box, the code sends
somehting to a host. This takes almost no time.
* It then needs to "wait" for the response. This may take
anywhere from, say, 0.2 to 3 seconds.
During the wait, I want the GUI to update itself (so that the JFrames
below the modal dialog gets repainted). I also want keyboard events to
be buffered. If this is not possible, I guess discarding them all
would be OK too.
I think that the "right thing to do" here would be to write a thread
that somehow disables input, then does the receive operation, then
enables input again. The problem is that I'm automatically converting
lagacy code into Java... so there is code right after the receive call
that needs to be called once the receive is done. Any ideas??
Thanks,
Micke
Chris Smith <cds...@twu.net> wrote in message news:<MPG.1844805a7...@news.altopia.com>...
It is not clear whether the modal dialog that you mention is one that
indicates something like a Status display. That is one of the typical
ways to block events from the underlying frame. (You start the thread
and immediately pop-up a status dialog. When the thread completes, the
dialog is disposed off - and the program flow continues at the statement
immediately after the modalDialog.show()).
Another alternative often used is to block events by using a GlassPane
which can prevent events from going through to the underlying
Frame/Dialog.
BK
The dialog is a "normal" dialog - it is run when the user selects a
menu item and he/she is supposed to fill it with data and then OK it.
But actually, the dialog was just an example of a situation where it's
important that the GUI repaints itself quickly (otherwise the dialog
won't hide properly).
But you're absolutely right - what I'm trying to achieve is almost
exactly what a modal dialog box does. In the show() method of
java.awt.Dialog, the code checks whether the calling thread is the
event dispatch thread. If it's not, it just blocks, since the events
will continue pumping anyway. If it is the EDT calling show(), like in
my case, then it must start pumping events _itself_ by calling
waitEvent and dispatchEvent in a loop. I tried yesterday to mimic what
it does in there, but I couldn't get it to work. It even says in the
class comment for Dialog how to do it, but you don't get to call any
of the methods in there directly.
Has anyone managed to do this, or is it impossible in Java?
I also tried your suggestion with actually showing a modal dialog box
while the worker thread is running and it works like a charm - if
nothing else works, I'll do that.
Thanks again,
Micke
Babu Kalakrishnan <ka...@sankya.com> wrote in message news:<slrnatn6s...@ganga.sankya.com>...
If you want event processing to occur normally, all that is necessary
is to do your long task in a separate Thread. It is only when you want
to block InputEvents, but want to process other stuff such as paint /
resize etc that you need to resort to things such as a modal dialog /
glasspane.
If your only requirement is that the rest of your code (after starting
the thread) has to execute only after the thread has completed, you
could move such code to a method that is called at the end of the
run method in the thread (Or into a runnable that is invoked with
invokeLater at the end of the run method if the code has to run in the
EDT).
Manually invoking the EventDispatchThread methods is unlikely to be
succesful because it is a package private class in the java.awt
package.
BK
> Manually invoking the EventDispatchThread methods is unlikely to be
> succesful because it is a package private class in the java.awt
> package.
Yepp, looks like it. In the Windows world this is pretty common, so I
was just wondering. Also, even though EventDispatchThread itself is
not avalable, some of the functions that it calls are - in EventQueue
and Component for example. Anyways, I'll stick with the "please wait"
dialog. It's working fine.
Thanks,
Micke