in reply to Perl/Tk repeat method, callback doesn't work if...

I think I understand your question.

First, Tk::repeat is a quick shortcut for Tk::after, read "perldoc Tk::after". Look thru Tk::after's methods to see if there is something you can use. Second, you didn't show a complete code example, but with Tk timers, if you declare them BEFORE you create them, you can use their variable name within the callback, like:

#pseudocode my $timer; # code update line below, I forgot to define $timer $timer = $mw->repeat( 50, { #you can use $timer here if $whatever, $timer->cancel; } ); # declare outside the callback, otherwise a $timer cannot cancel itsel +f

If you really want to get into a select style usage, within Tk, it dosn't work well, because it will interfere with the eventloop. But there is a workaround. See Tk::Trace in Simple Tk Gauge


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

Replies are listed 'Best First'.
Re^2: Perl/Tk repeat method, callback doesn't work if...
by NewMonkMark (Initiate) on May 17, 2011 at 08:40 UTC
    Thank you zentara, about cancel/destroy the repeat object, I do that from the caller routine for a better "logistic" administration (yes, the missing code would show that). I know practically nothing about select function but after some tests I suspected the problems comes from it, so you reinforsed my suspects, I bookmarked your post "Simple Tk Gauge" and I'll study it later. After a first look to the after method, it seems there is nothing usable to solve that problem, I think I'll use the Tk::waitVariable method ( $widget->waitVariable(\$var); ) it should work. I'll post more on this thread if I'll discover more solutions. Thank you again!
      ...a doubt rised about the "waitVariable" method is that I suspect that if the timer of repeat is too small, the repeat could set the variable before the creation of waitVariable object and the program could block:
      sub xyz{ $wid->repeat(1, sub{ $var=1; } ); # after 1 millisecond $var==1 # 1 ms... 2ms... 3ms... } { &xyz; # 6 ms... 7ms... 8ms... $widget->waitVariable(\$var); # will this wait indefinitely because +the var was already changed??? # Continue... never will happen }
      It depends on how repeat works (I don't know); but because it returns before the first pause (see Tk::after documentation) should be possible to do a sufficient reliable use of waitVariables, even if this appears to me like a bad patch...
      Sorry it didn't work for you, but I noticed I didn't quite show the code correctly, neglecting to define $timer, after declaring it as a global. That's maybe why your script dosn't cancel. Also, there is a method DoOneEvent which is very useful to force Tk to update everything before proceeding.

      Here is a little something for you to play with, for waitVariable

      #!/usr/bin/perl use warnings; use strict; use Tk; $|=1; my $count = 0; my $loop = 0; my $mw = new MainWindow(); $mw->Label( -textvariable => \$count )->pack; $mw->Button( -text => 'Start', -command => \&long_job ) ->pack( -side => 'left' ); $mw->Button( -text => 'Stop', -command => sub { $loop = 0; print "$cou +nt\n"; } ) ->pack( -side => 'left' ); MainLoop(); sub long_job { my $var; my $timer = $mw->repeat(100, sub{$var++} ); $loop =1; while($loop){ $loop++; $mw->waitVariable(\$var); $count++; } DoOneEvent(); #must call or will block gui }

      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh
        There isn't a clear specific reason for posting the following text, but at least I want to thank you zentara for your useful posts and all readers;
        moreover, my small experience with Tk could benefits from any type of comment to this post and moreover... the discussion could be useful to others...
        So, Due to my No experience with Tk I don't know if there is a better way to accomplish my work, anyway my code is very confusing so I only briefly explain its scheme and I'll be pleased to receive any feedback on what the reader think about it and if he knows a simpler/better way:

        1. The program Starts and load threads module (one thread only for all "Worker" functions, Tk run in the main (not threaded))

        2. Define some shared vars used to manage Input from GUI, Output from "Worker thread" and state of "Worker thread"

        3. Launch the "Worker Thread" (when it starts, it loads some settings and enter an infinite loop timed by select, at each cycle it checks a shared variable which give the ID of function to launch}

        4. Open a Block { where loads Tk Module; whole Tk GUI resides here }

        5. Each Time the user Launch a function, FUNC_CTRL subroutine (placed in the GUI Block) run and create the List of smaller functions needed and defined in "Worker thread"; so manage that "Stack" and opening/closure of MsgBox, Dialog Box, Refresh of the right Tk fields

        6. Some shared variables filled by the "Worker" and reelaborated by different subroutines for each function to give out the right form of output in the right place (GUI Fields).

        The Timers problem I think to have fixed, comes from inside the FUNC_CTRL fuction that manages the $MW->repeat object for each MsgBox, refresh etc, from creation to destruction, so it needs to know when they are up and runnig before free the "Worker Function", I did that this way:
        my ($MSGBOX) = &MSG_WIN(); # Create the MsgBox Object and the repeat t +imer inside which $STATE_of_MSGBOX_TIMER is changed. Return the MsgBo +x object $MW->waitVariable(\$STATE_of_MSGBOX_TIMER); # This should wait until M +essage Box Timer is started


        I created one thread only because starting a new one each time for each function show me the grow of used memory, and "detach()" or "join()" the thread doesn't free the memory, so it accumulates.