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

Hello Monks,

I'm searching fo guidance on add a feature to my recent Tk sparetime project. My probably naif understanding of the MainLoop is the mother of all errors. I'm seeking, if possible, explaination and examples.

Problem: I want to add an autoplay function to a secondary TopLevel window. In the below, semplified, example I display a sequence of chars A..Z A button on the primary window starts the autoplay function, and this works in the way I expected. But it turns out I'm not able to stop that autoplay. I imagined that checking a $toggle_autoplay variable was sufficient. I've bound the variable to the p key on the keyboard. It seems though that the variable remains unchanged (UPDATE: it seems the problem was an if?then:else related problem. the longer contruct below works...).

A)Is this the best way to implement an autoplay function? I tried to use Tk's repeat and timer with no big success. I read all tk callback material but if I understood it correctly a variable used in the callback it is evaluated when the callback is created NOT when it is invoked. How to change this behaviour?

B)why the ' ? : ' construct fails? Why it only works with an if(){}else{} one. Are not the same?

Background: the real application shows photos on the secondary window. I dont want to use modules like Tk::Slideshow or similar to accomplish the task. I want to do it on my own to understand better how MainLoop works.

The below code shows what i'm working on ()

#!/usr/bin/perl use warnings; use strict; use Tk; use Tk::Pane; use Tk qw(:eventtypes); my $mw = new MainWindow (-title=>" $0 MAIN"); my $phwin; my $display_label; my @to_show =('A'..'Z'); my $toggle_autoplay = 0; my $fr0 = $mw->Frame()->pack(); $fr0->Button( -text => "autoplay", -command => sub{$toggle_autoplay = 1; &autoplay}, #[\&autoplay, Ev $toggle_autoplay?$toggle_autoplay=0:$t +oggle_autoplay=1], )->pack(); # ok same behaviour of ->update #$mw->DoOneEvent(DONT_WAIT | ALL_EVENTS);# # the above without bitmask run but not at the right interval #also ok is: $mw->update; &secondary_win; MainLoop; ###################################################################### +########## sub autoplay { while($toggle_autoplay){ $display_label->configure(-text=> shift @to_show); $phwin->update; #$phwin->DoOneEvent; sleep 1; #last if $phwin->waitVariable(\$toggle_autoplay); } } ###################################################################### +########## sub secondary_win { # window does not exists if (! Exists($phwin)) { $phwin = $mw->Toplevel(); $phwin->title("SECONDARY"); $phwin->bind('<KeyRelease-p>' => sub { print "BEFORE: bind-p = $t +oggle_autoplay\n"; # THIS WORKS #if ($toggle_autoplay == 0 +){ # $toggle_autoplay = 1; #} #else{ # $toggle_autoplay = 0; #} # THE FOLLOWING DOES NOT W +ORKS! WHY? $toggle_autoplay == 0 ? $toggle_autoplay = 1 : $toggle_autoplay = 0 ; print "AFTER: bind-p = $to +ggle_autoplay\n"; }) } # window Exists else { $phwin->deiconify( ) if $phwin->state() eq 'iconic'; $phwin->raise( ) if $phwin->state() eq 'withdrawn'; } #my $scrolledframe = $phwin->Scrolled('Frame',-scrollbars => 'osoe +')->pack(); $display_label = $phwin->Label(-text=>'SECONDARY')->pack; }

Thanks in advance!

L*

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Replies are listed 'Best First'.
Re: Tk starting and stopping an autoplay loop using a keybinding
by Corion (Patriarch) on Oct 03, 2016 at 08:20 UTC

    The ternary operator ?: is not a statement but an expression. You should assign its result, not run two statements:

    $toggle_autoplay = ($toggle_autoplay == 0) ? 1 : 0;

    or, a bit shorter:

    $toggle_autoplay = !$toggle_autoplay;

      Or, a bit shorter:

      $toggle_autoplay ^= 1;

      Just to confuse things,

      $toggle_autoplay == 0 ? $toggle_autoplay = 1 : ($toggle_autoplay = 0);

      would have worked (because it fixes the precedence problem you were having).

      ..oops me bad! thanks

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Tk starting and stopping an autoplay loop using a keybinding
by Anonymous Monk on Oct 03, 2016 at 08:58 UTC
Re: Tk starting and stopping an autoplay loop using a keybinding
by tybalt89 (Monsignor) on Oct 03, 2016 at 18:39 UTC

    Here's a version using ->after() for the timing. (You should never sleep() in a Tk program.)

    Some things are different, for one, my windowmanager (RicksWM) does not have icons, so I left that part out and just destroyed the secondary window instead.

    #!/usr/bin/perl # http://perlmonks.org/?node_id=1173140 use strict; use warnings; use Tk; my @to_show = 'A'..'Z'; my $toggle_autoplay = 0; my $show = 'SECONDARY'; my $top; my $mw = new MainWindow; $mw->geometry('+400+0'); $mw->Button( -text => 'Autoplay', -command => \&click, -font => 'courierbold 100', )->pack; MainLoop; sub advance { if( $toggle_autoplay ) { $show = shift @to_show; push @to_show, $show; $mw->after(1000, \&advance); } } sub click { if( $toggle_autoplay ) { $toggle_autoplay = 0; $top->destroy; } else { $top = $mw->Toplevel; $top->title('SECONDARY'); $top->bind('<KeyRelease-p>' => \&click ); $toggle_autoplay = 1; $top->Label( -textvariable => \$show, -font => 'courierbold 200', -width => 2, )->pack; advance(); } }

    Your problem with ?: is actually explained in perlop.

      thanks tybalt89 for you working example: it turned out i was looking at the wrong part of Mastering Perl Tk book (chapter 13.22. Time Delays contains useful informations: i was on Anatomy of MainLoop).

      My problem with ?: was the worst Perl gaffe by me since years..

      You should never sleep() in a Tk program. I suspected this, and sounds like a good motto. It reminds me to an older one dormitare cogitantem de fuga vetat that translates more or less in: to sleep is forbidden to those plaining an escape

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.