Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

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?

Replies are listed 'Best First'.
Re: PerlTk Busy vs. update
by Crian (Curate) on Jul 02, 2004 at 09:22 UTC
    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(); ...
      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.

        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.

Re: PerlTk Busy vs. update
by gaal (Parson) on Jul 02, 2004 at 06:38 UTC
    Isn't the option to cancel a long operation a feature? :)
      Excellent point. Except that the mixed messages of an hourglass cursor and an active button make my head reel.

        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
by keszler (Priest) on Jul 02, 2004 at 06:39 UTC
    $statuslabel->update should work.
      $statuslabel->update is the same as Tk->update, i.e. it would update all Tk widgets in the application, not only $statuslabel.
      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() ?

        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().
        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.)

        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.