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

Hello... as title says, I would like to freeze a button while it is in the active mode. This is perhaps a simple question that you think I might get from web, but I just can't relate how to do that with my real code. I knew that a button can be set on it's state to 'normal', 'active' and 'disabled', but how do I apply it within my code bellow if each button below incurred some other subroutines? I just want to freeze the button "run all" until the job of invoking the job1, job2 & job3 button is done. Also, another side question on my flash button, why is it not flashing when the "run all" button is pressed? Thanks for your help.

my $run_all_btn=$mw->Button( -text => 'run all', -width => 20, -height => 2, -activebackground => 'red', -background => 'green', -command => sub { $run_job1->invoke(); $run_job2->invoke(); $run_job3->invoke(); #I want the button freeze until run compl +etion of all buttons job1, 2 and 3. })->pack(); $run_all_btn->flash(); #seem not working

Replies are listed 'Best First'.
Re: How to freeze a button while it is in active mode
by zentara (Cardinal) on Jul 17, 2014 at 14:51 UTC
    If $run_all_button->flash() dosn't work, you can make one manually with a timer. See second script below. I'm guessing it flashes once, and so fast you miss it. You may need to add a timer.

    As to your button states, look at this script.

    #!/usr/bin/perl use Tk; $mw = MainWindow->new(-title => "Testing Stop Button\n"); my $toolbar = $mw->Frame->pack(-side => 'left'); $button_run = $toolbar->Button(-text => "RUN", -command => sub{ $mw->Busy(-recurse => 1, -cursor => 'watch'); $button_run->configure(-state => 'disabled'); $button_stop->configure(-state => 'normal');}) ->pack(-side => 'left'); $button_stop = $toolbar->Button(-text => "STOP", -command => sub{ print "sub called, not Click_stop\n"; $stop_spyglass = 1; $button_stop->configure(-state => 'disabled');}, -state => 'disabled') ->pack(-side => 'left'); $button_stop->bind( '<Leave>', \&Leave_stop); $button_stop->bind('<Enter>', \&Enter_stop); $button_stop->bind('<Button-1>', \&Click_stop); sub Enter_stop { print "Enter_stop ", $button_stop->cget('-state'), "\n"; if ($button_stop->cget('-state') eq 'active' ){ $mw->Unbusy(); } } sub Leave_stop { print "Leave_stop ", $button_stop->cget('-state'), "\n"; if ($button_stop->cget('-state') eq 'normal'){ $mw->Busy(-recurse => -1, -cursor => 'watch'); } } sub Click_stop{ print "Click_stop ", $button_stop->cget('-state'), "\n"; if ($button_stop->cget('-state') eq ('active')){ $stop_spyglass = 1; $button_stop->configure(-state => 'disabled'); $button_run->configure(-state => 'normal'); } } MainLoop;
    and a button flasher
    #!/usr/bin/perl use Tk; use strict; my $mw = tkinit; my $button = $mw->Button(-text => 'Push Me')->pack; $button->configure(-command => [\&Invert, $button]); my $button1 = $mw->Button(-text => 'Flashy')->pack; my $timer = $mw->repeat(500,[\&Invert, $button1]); MainLoop; sub Invert { my($w) = @_; $w->configure(-bg => $w->cget('-fg'), -fg => $w->cget('-bg')); }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh

      Thanks Zentara, for again helping me with the sample code ans explanation.. which I really greatful to have your helping hands when I need. I finally manage to get my code done by doing the disabled/normal the button at my subroutine.

Re: How to freeze a button while it is in active mode
by Anonymous Monk on Jul 17, 2014 at 10:07 UTC

    ...

    The question isn't very clear

    Its hard to advise what to do without short a runnable program

    #!/usr/bin/perl -- ## ## ## perltidy -olq -csc -csci=3 -cscl="sub : BEGIN END if " -otr -opr - +ce -nibc -i=4 -pt=0 "-nsak=*" #!/usr/bin/perl -- use strict; use warnings; use Tk; use Time::HiRes qw/ usleep /; Main( @ARGV ); exit( 0 ); sub Main { GoTk( 4 ); GoTk( 8 ); } ## end sub Main sub GoTk { my( $many ) = @_; my $mw = tkinit; my @bbs; for my $one ( 1 .. $many ) { push @bbs, $mw->Button( -text, $one, -command, [ \&bbs_exclusive, ], )- +>pack; } $bbs[ rand @bbs ]->focus; $mw->$_ for qw/ withdraw deiconify raise focusForce update /; $mw->MainLoop; } ## end sub GoTk sub bbs_exclusive { my $ev = $Tk::event; my $bClicked = $Tk::widget; my @bbs = grep { $_->isa( 'Tk::Button' ) } $bClicked->parent- +>children; $_->configure( -state => 'disabled' ) for @bbs; for( 1 .. 10 ) { for my $bb ( @bbs ) { my $t = $bb->cget( -text ); $t .= ' #'; $bb->configure( -text, $t ); $bb->update; } usleep 100 * 1000; # sleep for 100*1 millisecond } for my $bb ( @bbs ) { my $t = $bb->cget( -text ); $t =~ s{(?:\Q #\E)*$}{}; $bb->configure( -text, $t ); $bb->configure( -state, 'normal' ); } } ## end sub bbs_exclusive __END__

      Thanks for your time and code. Though this is not really what I'm looking for but your sample code did help me learn something new. I might need it sometime in future. Thanks yea!

Re: How to freeze a button while it is in active mode
by locked_user sundialsvc4 (Abbot) on Jul 17, 2014 at 12:33 UTC

    It partly depends upon exactly what your graphic user-interface is set up to do (and how much support for, e.g., “button groups” you have at your disposal with any particular platform), but here is a general strategy for the handler for a button that will take a little while to complete.   (Entirely-abstract non-Perl pseudocode):

    disableButton(); try { doTheWork(); } finally { enableButton(); } }
    Translating that to “Perl or what-have-you” I leave as an exercise to the reader.   The try..finally construct that I refer to (which doesn’t automatically exist in Perl) is one that will always execute the finally portion even if an exception occurred.

    My point, in using it, is that you always have to anticipate and to handle exceptions that may occur in your button-handler, so that you always re-enable the button.

    Some GUIs provide for button-groups which simply means that the outer-level framework takes care of enabling and disabling the buttons.

    Likewise, some GUIs implement buttons as objects that automatically handle the disable/enable logic (and exception-trapping), calling an onClick method of some kind to doTheWork().

      Note that if you just run off and loop on a job, then the GUI will be frozen and windows will mark it "not responding". Be sure to sprinkle in some DoOneEvent() or equivalent calls so your GUI keeps rolling while you work.

      Also note that just because a button is disabled, doesn't mean it can't be click()ed again if the user is quick and/or tricky. (Eg: Win32-GuiTest) The enable state of the button itself makes a decent flag if the application isn't multithreaded.

      Thank you very much Sundialsvc4, for helping me to understand the logic. I finally manage to work on it as disable that before the function and enable it right afterward in my subroutine of button function. Appreciate!