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

I'm building an app with TK and need a way to dynamically change the contents of the main window. My approach is to place a frame in the window that takes up all of the space, then use subs to clear and fill the frame. When I try this, however, the sub isn't doing anything. here is my code:
use warnings; use strict; use Tk; ### Build Main Window # my $mainWindow = MainWindow->new; $mainWindow->title("BNS Cable Customer Managment"); $mainWindow->geometry("800x600"); ### Build Menu Bar my $mainMenu =$mainWindow -> Menu(); $mainWindow -> configure(-menu => $mainMenu); my $fileM = $mainMenu -> cascade(-label=>"File", -underline=>0, -tearo +ff => 0); my $optsM = $mainMenu -> cascade(-label=>"Options", -underline=>0, -te +aroff => 0); my $modeM = $mainMenu -> cascade(-label=>"Mode", -underline=>0, -tearo +ff => 0); ##File Menu $fileM -> command(-label => "New Property", -underline=>0 ); $fileM -> command(-label => "Logout", -underline=>0 ); $fileM -> separator(); $fileM -> command(-label =>"Exit", -underline => 1, -command => sub { exit } ); ##Options menu $optsM -> command(-label => "Preferences", -underline=>0 ); ##Mode Menu $modeM -> command(-label => "Property Centric", -underline=>0, -command => \&propCen); $modeM -> command(-label => "Task Centric", -underline=>0 ); #### Now the main Content my $content = $mainWindow->Frame; $content->pack(-fill => 'both', -expand => 1, -pady => 10, -padx => 10); MainLoop; sub propCen { $content->packForget; my $propList = $content->Scrolled("Listbox", -scrollbars=>"e", -exportselection => 0, -selectmode => "extended") ->pack( -anchor => 'w', -fill => 'y', -expand => 1); }
If I move the contents of the sub out and into the mainloop, it displays as I want it to.
nevermind..... I wasn't repacking the frame after I 'forgot' it. Saw that as soon as I posted.

While that did work, It's not working as expected.
With that code, the proper contents load correctly, but if I call the sub multiple times in a row, it starts nesting the widgets, instead of destroying and rebuilding.
Am I missing something or is there a better way to go about this?

Replies are listed 'Best First'.
Re: passing TK object into a sub
by zentara (Cardinal) on Jul 16, 2008 at 15:07 UTC
    I have trouble understanding your example, but here is how to do correct packForgetting. Notice, you reuse your widgets, NOT make new ones. While they are in a packForget state, you can reconfigure them, then repack them.
    #!/usr/bin/perl use warnings; use strict; use Tk; my $count = 0; my $top = new MainWindow; my $txt = $top->Scrolled("Text")->pack; $txt->insert('end',"Original stuff\n"); my $button1 = $top->Button(-text => "packForget", -command => sub{ my @w = $top->packSlaves; foreach (@w) { $_->packForget; } &rebuild; })->pack(); my $button = $top->Button(-text => "Exit", -command => sub {exit})->pack; MainLoop; sub rebuild{ $txt->delete('0.0','end'); $txt->insert('end',time."New stuff\n"); $txt->pack; $count++; $button1->configure(-text=>'packForget'.$count); $button1->pack; $button->pack; } __END__

    I'm not really a human, but I play one on earth CandyGram for Mongo
      Im my example I just have a window with a menubar at the top. Selecting a mode from the "mode" menu displays different content in the main window.

      So I built all of that and put a frame below the menu to house whatever content I need to load into it. Which is loaded by calling a specific sub.

      So by your example, I should build all of the widgets ahead of time and just pack/forgetPack them with the subs to change their visibility? Does that have an adverse effect on memory usage?
        You are correct. Build all of your widgets ahead of time, and control their visibility by packing/packForgetting them. Your memory usage will stay constant that way. If you are talking about many widgets, that may never get used, only build them as you need them, and store them in a hash or array for easy manipulation. So you can do something like this, where you can set the variable for the checkbox, to $num, and when you click the checkbox, the $num will be sent to the sub.
        my %entry; #global to store entries sub get_entry{ my $num = shift; if ( !Exists( $entry{$num}{'entry'} ) { $entry{$num}{'entry'} = $frame->Entry()->pack(); } else { #repack $entry{$num}{'entry'}->pack(); } }

        I'm not really a human, but I play one on earth CandyGram for Mongo