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

I am trying to write a fron end to a daemon. (Yes, noone around here can be asked to start something on Windows from a command line) Here is some example code:

sub long_sub { print "1\n"; &long_sub(); } $main->button( -text => "Start Long-Sub", -command => \&long_sub)->pack;

My question is: How do I keep my GUI responsive while the sub is executing?? I know under TCL/TK you needed to update your UI inside the sub, but I do not see this functionality in Perl TK.

Ideally, I would like to just have this run in the background. Any help would be appreciated.

~Hammy

Replies are listed 'Best First'.
(tye)Re: Perl TK
by tye (Sage) on May 10, 2001 at 01:24 UTC

    You could try using the experimental (and very-easy-to-break, in my experience) pretend-fork of Win32 Perl.

    But I'd just do something like:

    if( @ARGV && $ARGV[0] eq "do_long_sub" ) { &long_sub(); exit( 0 ); } # ... $main->button( -text => "Start Long-Sub", -command => sub { system(1,$^X,$0,"do_long_sub") } )->pack;

            - tye (but my friends call me "Tye")

      At this point I'm almost thinking it's easier to just have two different scripts.... That's ungodly... And here I was learning Perl TK so I could stop having all of my logic in Perl and my UI in TCL\TK.....

      Sigh...

Re: Perl TK
by physi (Friar) on May 10, 2001 at 02:22 UTC
    In perl TK there is the $widget->update() function.
    But that will only help, if you call it often enough from in your sub. For example:
    #!/usr/bin/perl -w use strict; use Tk; my $mw = MainWindow->new(); my $b1 = $mw->Button()->pack; my $b2 = $mw->Button(-command => \&test )->pack; MainLoop; sub test { print "start"; $mw->update(); for my $i (0..10000) { if ($i % 20 == 0) { print "$i\n"; $mw->update(); } } print "thats it"; }
    This works. So you can push 'button1' until the sub is running. But remember, that you have to update your mainwindow very often.
    If you want to run your sub in background, you can use fork as explained above. But maybe you want to use the results of your sub for your Tk display. in that case You should use a kind of pipe for that. But I think the update function could help you.

    Also look for  afterIdle, DoWhenIdle, idletasks. Maybe they are needful to you

    ----------------------------------- --the good, the bad and the physi-- -----------------------------------
      Thanks, that is more like I'm used to in TCL/TK. Yes, it's a biggol' pain in the booty, but I'm used to it...
Re: Perl TK
by JojoLinkyBob (Scribe) on May 10, 2001 at 04:45 UTC
    Ah Yes, I had this problem before, here's a quick-and-dirty progress bar script that uses and example
    #progress bar that monitors a compile, #by counting .o's periodically use Tk; sub tick; $total_objects = 303; $progressbar_width = 2*$total_objects; $progressbar_height = 50; $timer_interval=10; #in seconds $MW = MainWindow->new; $MW->bind('<Control-c>' => \&exit); $MW->bind('<Control-q>' => \&exit); $canvas1 = $MW->Canvas( '-width' => $progressbar_width, -height => $progressbar_height, -background => 'black' ) -> pack; $newval = 10; $start = $MW->Button( -text => 'Start', -command => sub {tick}, ); $start->pack(-side => 'left', -fill => 'both', -expand => 'yes'); sub tick { # Update the counter every 5 seconds $MW->after($timer_interval * 1000, \&tick); $num_objs = @objects = glob("\\as900\\code\\build\\*.o"); print "\n$num_objs out of $total_objects built so far..."; $newval = ($num_objs / $total_objects)*$progressbar_width; $canvas1->create ('rectangle','0','0',$newval,$progressbar_height, +-fill=>'red'); } MainLoop;

    This gives you the capability of a timer callback.
    Desert coder

      Just making sure I have this right....

      A script that might look like this:

      use Tk; my_long_sub { print "You can't kill me!\n"; sleep 60; my_long_sub(); } $main = MainWindow->new; $main->Button( -text "Start Long Sub", -command \&my_long_sub)->pack;

      Could (and should?) be written thusly:

      use Tk; $seconds = 60; not_a_long_sub { print "You can't kill me!\n"; #sleep 60; <-Replacing this with an after #my_long_sub(); <-After handles the call } $main = MainWindow->new; $main->Button( -text "Start Long Sub", -command \&not_a_long_sub)->pac +k; $main->after($seconds * 1000, \&not_a_long_sub);

      This assumes the after counts in Milliseconds. (Like Tk)

      Sorry to work this out in public, but I wanted to get my brain around it quick.... If anyone gathers the notion that I havent grokked this fully, let me know.

        That looks efficient to me.
        Desert coder