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

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!
  • Comment on Re^2: Perl/Tk repeat method, callback doesn't work if...

Replies are listed 'Best First'.
Re^3: Perl/Tk repeat method, callback doesn't work if...
by NewMonkMark (Initiate) on May 17, 2011 at 09:34 UTC
    ...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...
Re^3: Perl/Tk repeat method, callback doesn't work if...
by zentara (Cardinal) on May 17, 2011 at 16:50 UTC
    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.

        You are right to use your thread that way, with Tk. Your code is kind of complex from the description, so without REAL code examples, we can only hypothesize. :-)

        The key idea is the eventloop and how it allocates time to the various widgets. You might want to experiment with sprinkiling

        DoOneEvent(); # and or $mw->update;
        after variable updates which are needed elsewhere as signals.

        Also, with threads shared variables, the main thread is NOT automagically updated with the shared variable changes. The shared variable must be actively read, for it to cross the thread boundary.

        So if $STATE_of_MSGBOX_TIMER has changed in the thread, the main thread dosn't know about it, until it reads it once. If I understand your code idea, you are trying to use that in waitVariable, but it may not have been updated properly across the thread. So I don't know if a threads shared variable can be used across threads in waitVariable.

        A quick hack to tell if that's the case, is to make a timer in the main thread, that automatically updates all shared vars frequently, like

        $mw->repeat( 10 , { my $dummy_var = $STATE_of_MSGBOX_TIMER });
        that will force the main thread to read the shared var every 10 milliseconds.

        Good luck.


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