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

I have no doc and I'm struggling to find how its done on any website. I just want to exit out of the a perl/tk menu that I create in a separate subroutine. The EXIT Action Button works to exit the menu and script but the SUBMIT Action button will not exit the menu and then continue running the script. I would like to exit the menu at the end of the get_input subroutine and continue processing the script. Here's the excerpt from the script:
my $main = MainWindow->new(); $Action_Submit = $main->Button(-text => 'Submit', -command => [\&g +et_input ])->place(-x => 700, -y => 45); $Action_Exit = $main->Button(-text => 'Exit', -command => [$main => + 'destroy'])->place(-x => 700, -y => 115); # This menu has several radio and action buttons. Once # filled out, I want to first pull all of the data input # into the menu and place them into variables....then exit. # However, + this does not Exit the menu as i would think it # should. Instead the menu stays active until we actually # exit the script. sub get_input { $ftp_loginid = $LoginID->get; $ftp_pw = $LoginPW->get; $ftp_localdir = $LocalDIR->get; $main => destroy; ...{below continue with the script] }
Is there a valid way of exiting the menu and continuing the script ? "$main => destroy;" fails to do so. Thanks. GrandFather, Yes...menu/ dialogbox...not sure of the difference. I attempted to incorporate your code but I could not get it to work. I just want to be able to Exit the Menu/ dialog when the Submit Action button is clicked. I have no idea why I cannot do this in a separate subroutine. Is the fact that I am not using the DialogBox the reason? I present a menu to the user waiting for specific text, radio buttons etc to be interfaced with, when completed, I want to gather that info and exit out of the dialog/ menu and then continue on the the script. I tried to add you code(subroutine in) and i thought I would get another menu(dialogbox) but for whatever reason my original menu just stays up after Submit is issued. I know I am just a rookie...seems like this should be simple but I am not getting it. thanks for any help/ guidance.

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

    You do not show a menu. It may be that you actually mean a dialog. Possibly the following will help:

    use strict; use warnings; use Tk; use Tk::DialogBox; my $main = MainWindow->new(); my $Action_Submit = $main->Button(-text => 'Submit', -command => [\&ge +t_input ])->place(-x => 700, -y => 45); my $Action_Exit = $main->Button(-text => 'Exit', -command => [$main => + 'destroy'])->place(-x => 700, -y => 115); $Action_Submit->pack (); $Action_Exit->pack (); MainLoop; # This menu has several radio and action buttons. Once # filled out, I want to first pull all of the data input # into the menu and place them into variables....then exit. However, t +his does # not Exit the menu as i would think it should. Instead the menu stays + active # until we actually exit the script. sub get_input { my $dlg = $main->DialogBox(-title => "Options", -buttons => ["OK", + "Cancel"]); my $name; my $nameEdit = $dlg->add ('Entry', -textvariable => \$name)->pack +(); return if $dlg->Show () ne 'OK'; print "Name is $name\n"; }

    DWIM is Perl's answer to Gödel
Re: How do you exit PERL TK menu without exiting the script too ?
by rcseege (Pilgrim) on Sep 20, 2006 at 00:46 UTC

    The main problem here is that just because the command option can accept [$main => 'destroy'] as a configuration for an internal Callback does not mean that the same syntax can be used standalone outside of that context. What you're looking for is: $main->destroy like the following stripped down example.

    use Tk; my $main = MainWindow->new; $main->Button( -text => 'Submit', -command => [\&Submit] )->pack; MainLoop; print "Script continues after mainloop terminated\n"; sub Submit { print "Submit called\n"; $main->destroy; }

    Destroying the MainWindow allows the Event Loop created by MainLoop to terminate, allowing the lines following MainLoop to execute.

    Rob
      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?

        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
        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