PerlTk Busy vs. update
Anonymous Monk
created: 2004-07-02 02:11:07
I would like to use a status label to inform the user what's going on while my application is churning away on a long computation. So I have a little subroutine that I call every so often during the computation that updates the -textvariable associated with the label and calls $main->update() to actually update what's being displayed on the label.

The problem I'm having is that calling this update() seems to defeat the $main->Busy() I'm using to prevent the user from being able to take any actions while the calculation is running, so that the user may inadvertently interrupt the calculation before it's finished.

Is there a way to update my status label without allowing any events that may come in during the update to sneak around the grab that the Busy is supposed to be doing? Or am I just confused?

Re: PerlTk Busy vs. update
created: 2004-07-02 02:38:31
Isn't the option to cancel a long operation a feature? :)
Re^2: PerlTk Busy vs. update
created: 2004-07-02 02:55:48
Excellent point. Except that the mixed messages of an hourglass cursor and an active button make my head reel.
Re^3: PerlTk Busy vs. update
created: 2004-07-02 03:03:09

The Tk faq mentions configuring the cursor. Very possibly your system has a "busy, but what do you want?" cursor like an hourglass *and* a pointer. Perhaps you could use that?

My own experience with GUIs was with GTK, so I haven't actually tried this. YMMV.

Re: PerlTk Busy vs. update
created: 2004-07-02 02:39:24
$statuslabel->update should work.
Re^2: PerlTk Busy vs. update
created: 2004-07-02 02:58:58
I thought so too, but I seem to be able to hit my Quit button despite the fact that I'm seeing the hourglass (universal sign for "you shouldn't be able to hit the Quit button now")

Any thoughts on the merits of idletasks() vs update() ?

Re^3: PerlTk Busy vs. update
created: 2004-07-02 03:43:30
If I've got this right, you're setting $main->Busy, calling $label->update, and seeing responses to events - like a buttonclick on another widget - occur when the child widget performs the update. Are you setting -recurse => 1 in the call to Busy?

(I always set that, except in exceptional circumstances, and so ass-u-me-d that $child->update would not affect $otherchild.)

Re^4: PerlTk Busy vs. update
created: 2004-07-02 10:51:49
You've got it right, and I am setting -recurse=>1 but as pointed out below, the update acts globally.

Does anyone know what the behavior of setting (un)Busy an already (un)Busy widget is "supposed" to be?

I think this might be my problem.

Re^5: PerlTk Busy vs. update
created: 2004-07-02 13:24:01
Is that with $top->update or $label->update?

Contrary to the assertion that any update is global, the 2nd run of my test script shows that with Busy(-recurse=>1) and $label->update, the $button event was discarded. (On the Win98 and W2K boxen here, anyway.)

Update: I'd changed two things at once while testing - the recurse option was solely responsible for causing the events to be discarded. Update is global.

Also, idletasks is slightly different between the Win* and Linux boxen I use. On the Linux boxen there are no "leftover" characters after idletasks causes the label change to display.

Re^6: PerlTk Busy vs. update
created: 2004-07-02 14:06:33
I was using $top->Busy(-recurse=>1) and $label->update() (on a Sun box). I've gone over to using $label->idletasks() and this seems to work.
Re^6: PerlTk Busy vs. update
created: 2004-07-02 14:12:25
update() is global. I would be happy if this wouldn't be the case. There's no difference between $mw->update and $label->update.
Re^3: PerlTk Busy vs. update
created: 2004-07-02 04:41:06
The difference is that idletasks() only serves IDLE_EVENTS (for example those callbacks defined with the afterIdle method), while update() serves all events. When in doubt use update().
Re^3: PerlTk Busy vs. update
created: 2004-07-02 10:14:27
Idletasks will change a label, but not perform other needed tasks. For example:
#!perl

use strict;
use warnings;
use Tk;
my $top = MainWindow->new();
my $txt = $top->Text->pack;
for my $t ('a' .. 'z') {
	$txt->insert('end', $t x 40 . "\n");
}
my $lbltxt = "wowowowowowowowowowowowowowo";
my $label = $top->Label(-textvariable => \$lbltxt)->pack;
my $button = $top->Button(-text => "Die", -command => sub { exit; })->pack;
$top->update;
#$top->Busy(-recurse => 1); # use
$top->Busy; # drop
sleep 8;
$lbltxt = "updatedupdated";
#$label->update; # use
$label->idletasks; # drop
sleep 8;
$txt->delete('1.0','end');
$top->Unbusy;
Tk::MainLoop;
Run this, click on the "Die" button as soon as the window appears. After the first sleep, the label is changed, but since the new text is of shorter length several "wowo" characters remain on either side of "updated". After the 2nd sleep and the Unbusy, the "Die" event occurs and the program exits.

Comment out the "drop" lines and uncomment the "use" lines.

Run now, click "Die" before the label changes. This time there are no leftover characters, and the "Die" event is discarded. After the Unbusy the program continues.

Re^4: PerlTk Busy vs. update
created: 2004-07-02 14:24:03
I get different behavior than you describe (running on my Sun box). There are no "leftover characters" either way, but as noted the "Die" event is only discarded if -recurse=>1 is set. Perhaps this is a portability issue?
Re^5: PerlTk Busy vs. update
created: 2004-07-02 19:07:49
That seems to be the case - running it on a Linux box here leaves no leftovers either. With recurse, the "Die" event is discarded during the ->update, or after the Unbusy with idletasks.
Re^2: PerlTk Busy vs. update
created: 2004-07-02 04:37:05
$statuslabel->update is the same as Tk->update, i.e. it would update all Tk widgets in the application, not only $statuslabel.
Re: PerlTk Busy vs. update
created: 2004-07-02 05:22:39
I think you should switch of the 'busy state' for the update and switch back immediately after updating, so your code could look like this:

...
$mw->Unbusy();
$mw->update();
$mw->Busy();
...
Re^2: PerlTk Busy vs. update
created: 2004-07-02 11:03:43
This seems to produce the desired behavior, but has the unfortunate side effect of a rather twitchy cursor and significant slow down (at least when running across the network) when I'm doing many updates in rapid succession (e.g. "Your job is 37% done", "Your job is 38% done", etc.)

I think a combination of using idletasks()and making sure not to (Un)Busy an already (Un)Busy widget (by keeping a global indicator of the Busy state of the widget) seems to be working the way I had envisioned (although I'm still testing).

Thanks all.

Re^3: PerlTk Busy vs. update
created: 2004-07-02 14:14:47
If you may limit your application to Unix/X11, then you could make use of the Tk::InputO widget. This is basically a widget which takes input, but is invisible otherwise. You would put an InputO widget all over the application and put a cancel button on top of the InputO.

But, unfortunately, this is Unix-only.

perlmonks.org content © perlmonks.org and Anonymous Monk, Crian, eserte, gaal, keszler

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03