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

I have a dashboard type app that launches other apps with buttons, like button A, button B, etc.. I use the system() function to launch the programs when a user clicks a button. How do I make it wait so that after a button is clicked and another Perl/Tk program is started, the user cannot start another copy of the program by clicking on the button in the dashboard until the previous program is closed? Right now, with system(), the user can start as many versions of the program as he wants just by clicking on the button in the dashboard a bunch of times.

Thanks...

  • Comment on Perl/Tk question about starting programs via a button

Replies are listed 'Best First'.
Re: Perl/Tk question about starting programs via a button
by jethro (Monsignor) on Feb 24, 2010 at 23:31 UTC

    One method would be to create an app-specific lockfile before starting an app and not start the app again until the lockfile was removed. The app has to delete the lockfile on finish. Disadvantage: If the app crashes without deleting the file the app is blocked

    A better method would remember the process id of the app and check if it still exists before starting it again.

    And if you want to be 100% sure you could use interprocess communication to ask the app if it still exists. But that would be overkill in most situations

Re: Perl/Tk question about starting programs via a button
by Khen1950fx (Canon) on Feb 24, 2010 at 23:44 UTC
    I borrowed this script from Term::ReadLine::Tk. You'll need to use tkwait():
    sub Tk_loop { Tk->tkwait('variable',\$giveup); $count_DoOne++, Tk::DoOneEvent(0) until $giveup; $count_loop++; $giveup = 0; }
Re: Perl/Tk question about starting programs via a button
by zentara (Cardinal) on Feb 25, 2010 at 13:47 UTC
    A simple way, that blocks the gui, but I show for educational purposes:
    sub button_callback{ $startbutton->configure(-state=>'disabled'); system( "your_program" ); $startbutton->configure(-state=>'normal'); }

    That way is bad programming, except for emergencies. :-)

    Another way, is to disable the Start button until the last run is completed. You can then fork your program off, with a pipe, so you don't have to worry about waiting for it to return. System will interefere with the event-loop of gui's.

    sub button_callback{ use Proc::ProcessTable; # prevent button from working on second click $start_button->configure(-state => 'disabled'); #run your program so it can get its pid , read perldoc perlipc my $pid = open(TH, "my_program |"); # start a timer to check for the $pid my $timer; #declare first so it can be cancelled in its own callback $timer = $mw->repeat(1000, sub{ # you can grep a shell and grep thru the output of ps, or + my $t = new Proc::ProcessTable; foreach my $p (@{$t->table}){ if( $p->pid == $pid){ print "still running\n"; }else{ #renable button $start_button->configure(-state => 'normal'); } #cancel the timer $timer->cancel; }); }
    There are some gotchas to watch out for, like making sure the $pid is not confused with the program's shell's pid.... you can also use threads. Which is better, depends on how your system program runs. You may even be able to read it's STDOUT or STDERR and watch a filehandle until you see it's closed.

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku
Re: Perl/Tk question about starting programs via a button
by doug (Pilgrim) on Feb 25, 2010 at 17:40 UTC

    When you launch a process, grey out all your buttons. Then install a signal handler to wait on SIGCHLD that ungreys your buttons.

    - doug