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

Iam writing a massive Gui program and for part of it I need to unpack the widget. I get error saying that global $boom requires explicit package name, however $boom is a local variable which I use in another subroutine, please help.

sub die{ local $boom = MainWindow->new( -background=>'green'); my $label = $boom->Label(); my $yes = $boom->Button(); my $no = $boom->Button(); $label->configure(-text=>'DO you really want to quit?'); $yes->configure(-text=>'Yes',-command=>\&des); $no->configure(-text=>'NO', -command=>\&goback); $label->pack(); $yes->pack(); $no->pack(); } sub goback{ $boom->packForget(); } sub des{ $boom->packForget(); }

Edit: g0n - code tags

Replies are listed 'Best First'.
Re: help using packForget()
by akho (Hermit) on Apr 28, 2007 at 14:00 UTC
    local declaration does not create a new variable. It gives a new (lexically scoped) value to a package variable. Use my.

    The value you put in $boom will be gone after die exits even if you use local. If you want it to stay, declare it (as my) in a larger block.

    Properly formatted code after s/local/my/:

    my $boom; sub die { $boom = MainWindow->new( -background=>'green'); # this is where lo +cal was my $label = $boom->Label(); my $yes = $boom->Button(); my $no = $boom->Button(); $label->configure(-text=>'DO you really want to quit?'); $yes->configure(-text=>'Yes',-command=>\&des); $no->configure(-text=>'NO', -command=>\&goback); $label->pack(); $yes->pack(); $no->pack(); } sub goback { $boom->packForget(); } sub des { $boom->packForget(); }

    Upd It would be much better not to use global or semi-global variables. This code

    die; # creates window 1 die; # creates window 2

    will create two windows, but all buttons will control only one of those windows (and after it is closed, buttons will probably generate errors). And this probably happens if your user clicks the "Quit" button twice.

    That said, you will be much better off if you use Tk::Dialog for dialog boxes.

Re: help using packForget()
by f00li5h (Chaplain) on Apr 28, 2007 at 14:01 UTC

    These warnings are coming from strict

    the idea of local $boom is to give the global $boom a local value so when you speak of $boom, here, it's a package global.

    Also, If i recall, you can combine the calls to ->configure and ->new() when creating the widgets when using Tk to get a call somewhat like

    $boom->Button((-text=>'Yes',-command=>\&des)->pack()
    the trick there being to do it in the right order...

    Sun Apr 29 04:30:14 UTC 2007 jonadab, mentions that what I say in relation to local is q{ if not outright wrong, is at least misleading }, I'd rather go with "over simplified". I am happy to stand corrected and point out that Coping with Scoping does a far better job of explaining that I ever will.

    @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;
      the idea of local $boom is to give the global $boom a local value so when you speak of $boom, here, it's a package global.

      This description, if not outright wrong, is at least misleading. The idea of local is to give the global variable a dynamic value for the time being, but allow it to be automagically restored to its former value later (when the current block exits). The distinction is important, because the dynamic value is global in nature, not local in the traditional sense. (Yes, local is misnamed.) Any other code that gets called, even from other packages, will see the dynamic value. Therein lies its value. In fact, you would ordinarily not use local on your own variables. For those you would typically use my or our or place them in a package namespace. local is more useful for dynamically scoping the package variables used by other code that you are calling, in order to adjust its behavior in some way. (In Perl this is most often special variables belonging to built-in code that is part of perl itself, but in principle it could also be global (or package) variables belonging to a module, as is common e.g. in elisp.)

      -- 
      We're working on a six-year set of freely redistributable Vacation Bible School materials.
Re: help using packForget()
by zentara (Cardinal) on Apr 28, 2007 at 15:51 UTC
    As an afterthought, to what I said earlier, and the fact that you said this was for a gigantic gui, you might want to worry about memory gains from creating and packForgeting a $mw. PackForget will not destroy the widgets, and repeated use will cause a memory increase the way you have it now.

    Some options are to make the $boom a global, and when you call the my_die sub, use $boom over and over, by reconfiguring the buttons and labels. As a matter of fact, if you do it that way, you may not need packForget, just withdraw the $boom and reconfigure the widgets. You only need packForget if you want to repack the widgets in a different order. As an example of a non-leaking reusable popup......

    #!/usr/bin/perl use warnings; use strict; use Tk; my $tl; my $mw = MainWindow->new; $mw->title( "MainWindow" ); $mw->Button( -text => "Toplevel", -command => \&do_Toplevel )->pack(); MainLoop; sub do_Toplevel { if ( !Exists( $tl ) ) { $tl = $mw->Toplevel(); $tl->geometry('300x100+100+100'); $tl->title( "Toplevel" ); #put all your widgets here $tl->Button( -text => "Close", -command => sub { $tl->grabRelease; $tl->withdraw } )->pack; } else { $tl->deiconify(); $tl->raise(); $tl->grabGlobal; } } ##############################################################

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: help using packForget()
by zentara (Cardinal) on Apr 28, 2007 at 15:31 UTC
    Please use code tags around your code, so it is more readable.

    In addition to the technique of making $boom a global, you can also pass it to the subs, like this:

    sub my_die { my $boom = MainWindow->new( -background => 'green' ); my $label = $boom->Label(); my $yes = $boom->Button(); my $no = $boom->Button(); $label->configure( -text => 'DO you really want to quit?' ); $yes->configure( -text => 'Yes', -command => [\&des,$boom] ); $no->configure( -text => 'NO', -command => [\&goback,$boom] ); $label->pack(); $yes->pack(); $no->pack(); } sub goback { my $boom = shift; $boom->packForget(); } sub des { my $boom = shift; $boom->packForget(); }

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: help using packForget()
by akho (Hermit) on Apr 28, 2007 at 14:55 UTC
    And for the love of God, don't call your subs 'die'.