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

UPDATE: ++thundergnat for leading the way to the solution. By solving the test program with the raise method, he got me to RTFM for pack. Right at the very end, under Packing Order we see the following:

If the master for a slave is not its parent then you must make sure that the slave is higher in the stacking order than the master. Otherwise the master will obscure the slave and it will appear as if the slave hasn't been packed correctly. The easiest way to make sure the slave is higher than the master is to create the master window first: the most recently created window will be highest in the stacking order. Or, you can use the raise and lower methods to change the stacking order of either the master or the slave.

I didn't realize that master and parent are different. The green text window has the toplevel as its parent, but putting it into the blue frame makes that frame its master.

Folks-

I would like to create an unpacked Tk text window early on in my program, and pack it into a frame later on (then unpack it, then pack it, as the user interface requires).

I'm very confused by the behavior of the following test program.

As is, it works as I expect:
1.) Execute the program, resize the window to be very big.
2.) The green text box is nowhere to be seen (it's unpacked).
3.) Hitting the "Put text into frame" button will put the green text box into the blue frame.
4.) Hitting the "Take text out of frame" will put the green text box into the yellow toplevel.

Now comment out the "This works..." lines, and uncomment the "This doesn't work" lines, and rerun the program.

In this configuration, things don't work like I expect.
1.) Execute the program, resize the window to be very big.
2.) The blue frame is not yet created, and the green text box is nowhere to be seen (it's unpacked).
3.) Click on the "CreateFrame" listbox item to create the blue frame
4.) Hitting the "Put text into frame" button will fail to put the green text box into the blue frame (but the blue frame gets bigger - is the text box hidden somehow?)
5.) Hitting the "Take text out of frame" will put the green text box into the yellow toplevel.

What am I missing here?

Thanks

-Craig

use strict; use Tk; my $frame; my $text; # Create yellow toplevel window... my $top=MainWindow->new(); $top->configure(-background=>'yellow'); $top->Label(-text=>'Toplevel is yellow')->pack(-side=>'top'); # Create top level listbox... my $list = $top->Scrolled('Listbox', -selectmode=>'single')-> pack(-fill=>'both', -side=>'left'); # This works. Comment out 2 "frame" lines and comment in "bind" lines # to see the problem... $frame=$top->Frame(-background=>'blue')->pack(-fill=>'both'); $frame->Label(-text=>'The frame is blue')->pack(-side=>'top'); # This doesn't work... #$list->bind("<<ListboxSelect>>", sub { # $frame=$top->Frame(-background=>'blue')->pack(-fill=>'both'); # $frame->Label(-text=>'The frame is blue')->pack(-side=>'top'); #}); $top->Button(-text=>'Put text into frame', -command=>sub{ if(!$frame){return}; $text->packForget; $text->pack(-in=>$frame); })->pack; $top->Button(-text=>'Take text out of frame', -command=>sub{ $text->packForget; $text->pack(-in=>$top); })->pack; # Create unpacked text window... $text = $top->Scrolled('Text', -wrap=>'none', -background=>'green'); $text->insert('end', 'Green is the text box'); $list->insert( 'end', 'CreateFrame'); MainLoop;

Replies are listed 'Best First'.
Re: Strange Tk Frame Behavior
by zentara (Cardinal) on Feb 07, 2008 at 17:03 UTC
    You have a right to be confused, it should work. The frame widget is very primitive, and causes alot of hassles. It expands from the inside out, meaning if nothing is packed, it won't show up. You may need to completely packforget the frame from the top level, then repack it. There is also packPropagate to play with. You may need to tell $top to propagate the packing. It's very tricky, so someone else may find a simple fix for you, which I'm overlooking.

    Most people have learned to just use a Tk::Pane..... it works better. Try this. You may have to experiment with nesting the Pane into a Frame so the Label dosn't expand too much.

    #!/usr/bin/perl use strict; use Tk; require Tk::Pane; my $frame; my $text; my $pane; # Create yellow toplevel window... my $top=MainWindow->new(); $top->configure(-background=>'yellow'); $top->Label(-text=>'Toplevel is yellow')->pack(-side=>'top'); # Create top level listbox... my $list = $top->Scrolled('Listbox', -selectmode=>'single', )->pack(-fill=>'both', -side=>'left'); #create a Pane $pane=$top->Scrolled('Pane', -scrollbars=>'osoe', -background=>'blue'); $list->bind("<<ListboxSelect>>", sub { $pane->pack(-expand=>1, -fill=>'both'); $frame=$pane->Frame(-height=>1)->pack(-side=>'top',-pady=>0); $frame->Label(-text=>'The pane is blue', -height=>1)->pack(-side=>'top',-pady=>0); }); $top->Button(-text=>'Put text into pane', -command=>sub{ if(!$pane){return}; $text->packForget; $text->pack(-in=>$pane); })->pack; $top->Button(-text=>'Take text out of frame', -command=>sub{ $text->packForget; $text->pack(-in=>$top); })->pack; # Create unpacked text window... $text = $top->Scrolled('Text', -wrap=>'none', -background=>'green'); $text->insert('end', 'Green is the text box'); $list->insert( 'end', 'CreateFrame'); MainLoop;

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      ++zentara

      Thank you for sharing: my $pane

      OMG: I can't believe I just did that... Sorry all...

      Seriously though, thanks for almost always coming through on the Tk questions. Having you knocking about the monastery gives me great reassurance.

      -Craig

Re: Strange Tk Frame Behavior
by thundergnat (Deacon) on Feb 07, 2008 at 20:18 UTC

    Not to take anything away from zentaras answer, Pane very likely is a better way to go. However, it seems to me just adding a "raise" to your 'Put text in frame' button command will make it do what you (or I, at least,) would expect.

    $top->Button(-text=>'Put text into frame', -command=>sub{ if(!$frame){return}; $text->packForget; $text->pack(-in=>$frame); $text->raise; #<=== Add this line })->pack;