Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Re: How do you exit PERL TK menu without exiting the script too ?

by rcseege (Pilgrim)
on Sep 20, 2006 at 00:46 UTC ( [id://573830]=note: print w/replies, xml ) Need Help??


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

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

Replies are listed 'Best First'.
Re^2: How do you exit PERL TK menu without exiting the script too ?
by ljsmith91 (Initiate) on Sep 20, 2006 at 00:52 UTC
    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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://573830]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (1)
As of 2024-04-19 00:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found