in reply to Confused by variable scope in Tk::Wizard

See sub PM899927
#!/usr/bin/perl -- use strict; use warnings; use Tk; use Tk::Wizard; Main(@ARGV); exit(0); sub Main { @_ ? T160() : PM899927(); } #~ http://perlmonks.org/?node_id=899927 #~ Confused by variable scope in Tk::Wizard sub PM899927 { my $wiz = new Tk::Wizard( -title => "Kickstart Wizard" ); my $oschoice = 'test'; $wiz->addSingleChoicePage( -text => 'Choose OS', -variable => \$oschoice, -choices => [ { -title => 'Linux', -value => 'Lin' }, { -title => 'Windows', -value => 'Win', -selected => 1, }, ], -preNextButtonAction => sub { warn "\$oschoice $oschoice "; } +, ); $wiz->addPage( sub { #~ shift->_text_frame( $wiz->_text_frame( { -title => 'Partitioning', -boxedtext => \"/mirror/inifiles/partition.$oschoi +ce", } ); }, ); $wiz->Show; $wiz->focus; MainLoop; } ## end sub PM899927
#~ http://cpansearch.perl.org/src/LGODDARD/Tk-Wizard-2.151/t/160_textb +ox.t sub T160 { local $ENV{TEST_INTERACTIVE} = 1; my $wizard = Tk::Wizard->new; $wizard->addSplashPage( -wait => $ENV{TEST_INTERACTIVE} ? 0 : 1, ) +; $wizard->addTextFramePage( -wait => $ENV{TEST_INTERACTIVE} ? 0 : 1, -title => "1: Text from literal", -boxedtext => \"This is in a box", # " ); $wizard->addTextFramePage( -wait => $ENV{TEST_INTERACTIVE} ? 0 : 1, -subtitle => sprintf( "2: Text from filename (%s)", __FILE__ +), -boxedtext => __FILE__, ); $wizard->Show; MainLoop; } ## end sub T160 __END__
http://cpansearch.perl.org/src/LGODDARD/Tk-Wizard-2.151/lib/Tk/Wizard. +pm sub addTextFramePage { my ($self, $args) = (shift, {@_}); DEBUG "addTextFramePage args are ", Dumper($args); return $self->addPage( sub { $self->_text_frame($args) } ); } sub _text_frame { my $self = shift; my $args = shift; DEBUG "Enter _text_frame with ", Dumper($args); my $text; my $frame = $self->blank_frame(%$args); if ( $args->{-boxedtext} ) { if ( ref $args->{-boxedtext} eq 'SCALAR' ) { $text = $args->{-boxedtext}; } elsif ( not ref $args->{-boxedtext} ) { open my $in, $args->{-boxedtext} or Carp::croak "Could not read file: $args->{-boxedtex +t}; $!"; read $in, $$text, -s $in; close $in; WARN "Boxedtext file $args->{-boxedtext} is empty." if not + length $text; } } $$text = "" if not defined $text; my $t = $frame->Scrolled( "ROText", -background => ( $args->{ -background } || 'white' ), -relief => "sunken", -borderwidth => "1", -font => $self->{defaultFont}, -scrollbars => "osoe", -wrap => "word", )->pack(qw/-expand 1 -fill both -padx 10 -pady 10/); $t->configure( -background => 'green' ) if DEBUG_FRAME; $t->insert( '0.0', $$text ); $t->configure( -state => "disabled" ); return $frame; }

Replies are listed 'Best First'.
Re^2: Confused by variable scope in Tk::Wizard
by rgcosma (Beadle) on Apr 18, 2011 at 15:30 UTC
    Thank you very much, the example does work. I do have to admit though that I don't understand why.. the syntax around this segment gives me a headache:
    $wiz->addPage ( sub { $wiz->_text_frame( { -title => 'Partitioning', -boxedtext => "/mirror/inifiles/partition.$oschoice", } ); } );
      Here is the exact same thing only written more verbosely
      { my $Aspirin = sub { return $wiz->_text_frame( { -title => 'Partitioning', -boxedtext => "/mirror/inifiles/partition.$oschoice", } ); }; $wiz->addPage($Aspirin); }
      I suspect you're having trouble with closures

      In my original program, this unnamed subroutine, this anonymous subroutine, whose reference is now stored in $Aspirin, refers to two variables outside its scope. Namely $oschoice and $wiz, which are not declared (my) within $Aspirin. This makes $Aspirin a closure.

      Each time you call this subroutine, $Aspirin->(); it calls _text_frame with the current value of $oschoice

      So if $oschoice="Lin" then $Aspirin->() returns a frame with /mirror/inifiles/partition.Lin

      Next you change $oschoice="Win" and then $Aspirin->() returns a frame with /mirror/inifiles/partition.Win

      The first step in the wizard edits $oschoice, then when you click next, the wizard invokes $Aspirin , which returns a new frame using the current value of $oschoice

      If you click the back button and select a different OS, and click next again, the wizard will call $Aspirin again

      More on closures, hopefully easier to understand :) oh and no wizards or witches :)