jagdish.eashwar has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
I want to display the program status in a perl tk label widget, but am unable to. The widget is displaying the status only at the end of the script.I am submitting a short piece of code for your perusal.
use warnings; use strict; use Tk; my ($no,$upper_no,$mw); $mw = MainWindow->new; $mw->geometry("300x100"); $mw->title("PerlTk Test"); $mw->Label(-text => "Enter a 5 digit number") ->place(-relx => 0.0,-rely => 0.05); $mw->Entry(-takefocus => 1, -textvariable => \$upper_no, -width => 12) ->place(-relx => 0.50, -rely => 0.05); $mw->Button(-text => "Click to count upto that number and display them + below as you count", -wraplength => 250, -command => \&count) ->place(-relx => 0.5, -anchor => "center", -rely =>0.50); $mw->Label(-textvariable => \$no, -relief => 'sunken', -anchor => 'center') ->place(-relx =>0.0, -rely => 0.80, -relwidth => 1.0, -relheight = +> 0.2); MainLoop; sub count { if ($upper_no > 0) { $no = 0; while ($no < $upper_no) { $no++; } } }
Where am I going wrong?
Jagdish

Replies are listed 'Best First'.
Re: displaying program status in perl tk
by jethro (Monsignor) on Feb 04, 2009 at 15:27 UTC

    GUI programs work in a different fashion than normal code. The Mainloop is the one updating the screen and if you don't return to it, nothing gets updated. So your while loop was poison for the GUI

    #!/usr/bin/perl use warnings; use strict; use Tk; my ($no,$upper_no,$mw,$realend); $no=0; $upper_no=''; $mw = MainWindow->new; $mw->geometry("300x100"); $mw->title("PerlTk Test"); $mw->Label(-text => "Enter a 5 digit number") ->place(-relx => 0.0,-rely => 0.05); $mw->Entry(-takefocus => 1, -textvariable => \$upper_no, -width => 12) ->place(-relx => 0.50, -rely => 0.05); $mw->Button(-text => "Click to count upto that number and display them + below as you count", -wraplength => 250, -command => \&count) ->place(-relx => 0.5, -anchor => "center", -rely =>0.50); $mw->Label(-textvariable => \$no, -relief => 'sunken', -anchor => 'center') ->place(-relx =>0.0, -rely => 0.80, -relwidth => 1.0, -relheight = +> 0.2); MainLoop; sub count { if ($upper_no=~/^\d+$/ and $upper_no > 0) { if ($no < $upper_no) { $no++; } } }
      Hi jethro,
      Thanks for the quick response. With the modified code, I have to click the button each time to make the status message change. Isn't there some way of making the script update the mainloop from within a while loop as and when the status message changes?
        You can keep a reference to the label and update it directly. This is generally how you have to handle any progress/meter type stuff that needs to be updated in a loop. (This is untested but should be pretty close)
        my $counter_label = $mw->Label(-text => $no, -relief => 'sunken', -anchor => 'center') ->place(-relx =>0.0, -rely => 0.80, -relwidth => 1.0, -relheight = +> 0.2); ... sub count { if ($upper_no > 0) { $no = 0; while ($no < $upper_no) { $no++; $counter_label->configure(-text => $no); } } }
        Putting this code in your loop should do the trick. I haven't tested it.
        while(1) { last unless DoOneEvent($TK_DONT_WAIT); }
        DoOneEvent is the routine called from MainLoop.

        When passed the exported variable $TK_DONT_WAIT it returns true if there was an event to process, and false if otherwise. So DoOneEvent will continue to be called until there are no more events pending (and the only event pending would be the updating of your status bar). Then your program would continue on where it left off.

        Read more about the main loop here.
Re: displaying program status in perl tk
by zentara (Cardinal) on Feb 04, 2009 at 16:34 UTC
    Whenever you want something done automatically on a schedule, use a timer
    sub count { print "$upper_no\n"; my $timer; # declare first so you # can cancel it in it's own callback $timer = $mw->repeat(1000,sub{ $no++; if ($no >= $upper_no){ $timer->cancel } }); }

    I'm not really a human, but I play one on earth Remember How Lucky You Are
      Hi,
      Thank you every one for your responses. I tried all that was suggested to the best of my understanding, but couldn't get the display of the program status in real time. I hope I'm not speaking too soon, but I think I've finally found an answer in the 'Perl Tk and the Web' chapter of 'Mastering Perl Tk'. I have to use '$mw->idletasks;' in my while loop.
        If you need idletasks in your loop, and the timer I showed you dosn't work right to show your updates, then I must presume you are not showing us the real code. You might try putting $mw->update; in your loop too, that may help, but it's a bad design.

        If you would show us your real code, we probably could show you a better way.


        I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: displaying program status in perl tk
by balakrishnan (Monk) on Feb 06, 2009 at 07:52 UTC
    I seen that $mw->idletasks; takes the effect. In this case, You getting the status once you pressed the button. There are sometimes or in some places, we require the status to be updated once we pressed the enter key. For this, the following would help,
    my $input = $mw->Entry(-takefocus => 1, -textvariable => \$upper_no, -width => 12) ->place(-relx => 0.50, -rely => 0.05); my $counter_label = $mw->Label(-textvariable => \$no, -relief => 'sunken', -anchor => 'center') ->place(-relx =>0.0, -rely => 0.80, -relwidth => 1.0, -relheight = +> 0.2); # When <enter> is pressed, this taken into the action. $input->bind('<KeyPress-Return>', sub { count(); $counter_label->configure(-textvariable => \$no); } );
    This might helps for you.