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

Hi perl Monks,
I am trying to write a simple code which selects the names from a list box and creates a top level window for that name.
This toplevel window is having two buttons Save and close.
When i open multiple toplevel windows i am unable to store the context of all the windows. i.e when i click on the close button of last recent window it gets closed but when i click on the close button which is present on the rest of the toplevel windows they will not close.
Please help me getting the context of all the toplevel windows. This is the code that i have written:

#!/usr/local/bin/perl use Tk; use Tk::BrowseEntry; my $mw = new MainWindow; $mw->title("Main Window"); my $frame1 = $mw->Frame()->pack(-side => 'top' ); #List for Browse Entry my @List = ("First window","Second Window","Third Window", "Last Windo +w"); $browseentry = $frame1 ->BrowseEntry( -label => "Select Window:", -listheight=> 4, -variable => \$Win_value, -browsecmd => \&Create_Window) ->pack(-side =>'left', -ipady => 5, -pady=>15) +; $browseentry->insert('end', @List); $frame2 = $mw->Frame()->pack(-side => 'bottom'); my $lbl1 = $frame2->Button(-text => 'Close', -command =>sub {$mw->destroy()}) ->pack(-pady =>10); MainLoop; sub Create_Window { our %Window_Info; our $flg = 0; our $my_Win = @_; our $frm1 = join '', @_[1],"_frm1"; our $frm2 = join '', @_[1],"_frm2"; our $caption = join '', @_[1],"_Details"; while (($key, $val) = each(%Window_Info)) { if($key eq @_[1]){ $flg=1; $val ->deiconify( ); $val ->raise( ); } } if ($flg == 0){ $my_Win = $mw ->Toplevel(); $my_Win ->title("$caption"); $my_Win->minsize(qw(800 500)); $my_Win->focus(); #Storing the values in the Hash table $Window_Info{@_[1]}=$my_Win; $frm2 = $my_Win->Frame()->pack(-side => 'bottom' ); #opens the save file dialog wrt the selected toplevel. $frm2->Button(-text => 'Save', -command =>sub {SaveFile($my_Wi +n)})->pack(-side=>'left'); #closes the selected window $frm2->Button(-text => 'Close', -command =>sub {$my_Win->destr +oy()})->pack(-side=>'left'); } }

Replies are listed 'Best First'.
Re: Unable to delete a specified toplevel
by Erez (Priest) on Jun 11, 2008 at 10:56 UTC

    Add

    use strict; use warnings;

    To the top of your program and correct your errors accordingly.
    Also: don't manipulate the default list (@_) in a procedure. Assign its values to local (my, not our) variables and use those; and at any rate, referring to a specific variable in a list is done through $list[0], not @list[0]. As it is, there are so many ways why it *shouldn't* work, than suggestions how to make it work properly.

    Stop saying 'script'. Stop saying 'line-noise'.
    We have nothing to lose but our metaphors.

Re: Unable to delete a specified toplevel
by GrandFather (Saint) on Jun 11, 2008 at 11:28 UTC

    There are a slew of problems with your original script. Using strictures and not using our is part of the problem, but the issues go much deeper than that.

    The following sample derived from your original code fixes the main problems I found:

    #!/usr/local/bin/perl use strict; use Tk; use Tk::BrowseEntry; my $obj = bless {mw => new MainWindow}; $obj->{mw}->title("Main Window"); $obj->{frame1} = $obj->{mw}->Frame()->pack(-side => 'top' ); my $Win_value; #List for Browse Entry my @List = ("First window", "Second Window", "Third Window", "Last Win +dow"); my $browseentry = $obj->{frame1}->BrowseEntry ( -label => "Select Window:", -listheight=> 4, -variable => \$Win_value, -browsecmd => [\&Create_Window, $obj], ) ->pack(-side =>'left', -ipady => 5, -pady=>15); $browseentry->insert('end', @List); my $frame2 = $obj->{mw}->Frame()->pack (-side => 'bottom'); my $lbl1 = $frame2->Button (-text => 'Close', -command =>sub {$obj->{m +w}->destroy()}) ->pack (-pady =>10); MainLoop; sub Create_Window { my $self = shift; my $myId = $_[1]; my $caption = join '', $_[1],"_Details"; if (exists $self->{windows}{$myId} and Exists ($self->{windows}{$m +yId}{win})) { $self->{windows}{$myId}{win}->deiconify (); $self->{windows}{$myId}{win}->raise (); return; } my $info = $self->{windows}{$myId} = {}; $info->{win} = $self->{mw}->Toplevel(); $info->{win}->title("$caption"); $info->{win}->minsize(qw(800 500)); $info->{win}->focus(); $info->{frame} = $info->{win}->Frame()->pack(-side => 'bottom' ); #opens the save file dialog wrt the selected toplevel. $info->{frame}->Button( -text => 'Save', -command =>sub {SaveFile($info->{win})} )->pack(-side=>'left'); #closes the selected window $info->{frame}->Button ( -text => 'Close', -command => [\&closeChild, $self, $myId], )->pack(-side=>'left'); } sub closeChild { my ($self, $winId) = @_; $self->{windows}{$winId}{win}->destroy (); delete $self->{windows}{$winId}; }

    Note the use of very light weight object orientated programming techniques to avoid accessing global variables from within subs to get at state information.

    Also note the -command => [\&closeChild, $self, $myId] technique to pass parameters to a callback routine.

    The sample allows windows to be opened and closed in any order. It allows closed windows to be re-created and shifts focus from the main window to an existing created window (using the list box). The created windows may be closed using either the close button in the window or the close box in the window's title bar. Using the title bar close doesn't get the closeChild callback called however.


    Perl is environmentally friendly - it saves trees
Re: Unable to delete a specified toplevel
by Anonymous Monk on Jun 11, 2008 at 11:08 UTC
    Change all our for my s/our/my/;