in reply to Re: How do you exit PERL TK menu without exiting the script too ?
in thread How do you exit PERL TK menu without exiting the script too ?

Thanks Rob, Your stripped down sample is exactly what I do with 1 difference...I have a bunch of code after the $main-> destroy; and the menu does not exit out until this code completes. Try adding a "sleep 30;" statement after the "$main->destroy;" The exit will not occur until everything in the subroutine ends. It must be because the MainLoop subroutine callled the Submit subroutine. Any way around this?
  • Comment on Re^2: How do you exit PERL TK menu without exiting the script too ?

Replies are listed 'Best First'.
Re^3: How do you exit PERL TK menu without exiting the script too ?
by GrandFather (Saint) on Sep 20, 2006 at 01:14 UTC

    Have Submit set a "success" flag, destroy the main window, then return. Complete the processing in the main line following MainLoop if the success flag is set:

    ... my $ok = 0; MainLoop; print "Script continues after mainloop terminated\n"; print "Do ok stuff\n" if $ok; sub Submit { $ok = 1; $main->destroy; }

    Update: added code example


    DWIM is Perl's answer to Gödel
Re^3: How do you exit PERL TK menu without exiting the script too ?
by rcseege (Pilgrim) on Sep 20, 2006 at 03:06 UTC
    It must be because the MainLoop subroutine callled the Submit subroutine.

    This is true. Consider that Tk, like other GUI toolkits is event driven - you set up the GUI components, and then you start up the Event processor using the MainLoop function, which processes events until the MainWindow has been destroyed. All Events are processed serially, so even when you change the condition that will terminate the event loop the condition will not be reevaluated until the current event is processed.

    Any way around this?

    Well, sure -- move that code outside of the subroutine, and after the MainLoop. ;-) As for determining what caused MainLoop to terminate (Cancel or Submit) GrandFather already provided the solution using my example.

    The intent of that example was to try and make it clarify what was happening. Normally, when I'm doing something like this, I'm more likely to do something closer to what GrandFather showed in his first example. Here's an embellished version using DialogBox

    use strict; use Tk; use Tk::DialogBox; use Tk::LabFrame; if (authenticateUser()) { print "protected statement called\n"; } sub authenticateUser { my ($user, $passwd); my $mw = MainWindow->new; my $dialog = $mw->DialogBox( -title => "Login", -buttons => [qw/Login Cancel/] ); my $labFrame = $dialog->add('LabFrame', -labelside => "acrosstop", -label => "Login Form" )->pack; ## Internal Frame for padding with Labeled Frame my $iFrame = $labFrame->Frame-> pack(qw/-padx 10 -pady 10/); $iFrame->Label(-text => "User: ")->grid( $iFrame->Entry(-textvariable => \$user) ); $iFrame->Label(-text => "Password: ")->grid( $iFrame->Entry( -show => '*', -textvariable => \$passwd ), -pady => 5 ); if ($dialog->Show() eq "Login") { ## Authenticate user - assume check passed print "$user/$passwd authenticated!\n"; return 1; } return 0 }

    If you read through this example you'll notice that I don't call MainLoop anywhere. This is because DialogBox is handling it internally. It works using the waitVariable method documented in the widgets pod. waitVariable functions a lot like MainLoop except that it waits for a specified variable to be set before terminating the event loop. It's still the same basic idea, though. Here's the same script, but without the DialogBox. Note the use of waitVariable, which is crucial.

    use strict; use Tk; use Tk::LabFrame; if (authenticateUser()) { print "protected statement called\n"; } sub authenticateUser { my ($user, $passwd, $button); my $mw = MainWindow->new; my $labFrame = $mw->LabFrame( -labelside => "acrosstop", -label => "Login Form" )->pack(qw/-side top -padx 10/); ## Internal Frame for padding with Labeled Frame my $iFrame = $labFrame->Frame-> pack(qw/-padx 10 -pady 10/); $iFrame->Label(-text => "User: ")->grid( $iFrame->Entry(-textvariable => \$user) ); $iFrame->Label(-text => "Password: ")->grid( $iFrame->Entry( -show => '*', -textvariable => \$passwd ), -pady => 5 ); my $buttons = $mw->Frame-> pack(qw/-side bottom -pady 5/); $buttons->Button( -text => "Login", -command => sub { $button = "Login"; } )->pack(qw/-side left -padx 10/); $buttons->Button( -text => "Cancel", -command => sub { $button = "Cancel"; } )->pack(qw/-side left -padx 10/); ## Prevents the script from moving past this point ## until the $button variable has been set. $mw->waitVariable(\$button); if ($button eq "Login") { ## Authenticate user - assume check passed print "$user/$passwd authenticated!\n"; return 1; } return 0 }
    Rob