Home > Archive > PerlTk > June 2004 > MainWindow auto-resize issues
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
MainWindow auto-resize issues
|
|
| Chris Chiesa 2004-06-18, 8:56 pm |
| For the past six w s or so, I have been fighting on-and-off with
several issues surrounding MainWindow resizing. In my application I
want to build an initial, largely empty GUI, then populate it with
various widgets in response to user input at run time. Unfortunately,
unless I do things "just exactly right," the MainWindow fails to
resize (expand and contract) to match the comings-and-goings of child
widget hierarchies created/destroyed "dynamically" in the course of
operations. Sometimes the MainWindow doesn't resize at all, sometimes
it resizes "partway," and only rarely, after much trial-and-error,
have I gotten it to resize "just right..."
There seem to be three issues; two that I've solved, and one that is
still a mystery.
First, observe the following example program:
--------
#!/usr/local/bin/perl -w
use strict 'refs';
use Tk;
my $mw = MainWindow->new();
my $button = $mw->Button(-text => 'Click Me',
-command => sub { addButton(); } )
->pack;
MainLoop;
sub addButton
{
my $nooF = $mw->Frame; # Don't pack here, due to Problem #1
my $nooB = $nooF->Button(-text => "New"); # Don't pack() yet...
$nooB->configure(-command => sub { remButton( $nooB, $nooF ); } );
$nooF->pack; # ONE
$nooB->pack; # TWO
}
sub remButton
{
$_[0]->destroy; # Button
$_[1]->destroy; # Frame
}
This program initially displays a single button reading "Click Me."
When you click on it, nothing obvious happens -- but actually each
click is causing another new button, reading "New," to be created and
packed into the MainWindow. You can't see these "New" buttons,
though, because the MainWindow is not automatically expanding itself
to reveal the new buttons. You must "manually" drag the MainWindow
out to a larger size in order to see them.
One fix for this is to swap the two lines commented #ONE and #TWO --
that is, to pack each "New" button into its containing Frame _before_
packing that Frame into the MainWindow. This makes no sense to me --
I would think the resulting Widget-geometry hierarchy should be the
same in the end, either way -- but this is what I observe. I
tentatively deduce a general rule: "in order to obtain proper
MainWindow resizing behavior, you must pack() all of a Frame's
children _before_ pack()-ing the Frame itself into _its_ parent." In
other words, "you must pack() 'from the bottom up'" when constructing
a widget hierarchy. Although this solution "works," it bothers me
because it flies directly in the face of the "standard" paradigm of
doing e.g.
$fr = $mw->Frame->pack;
$btn = $fr->Button->pack;
| |
| $_@_.%_ 2004-06-19, 3:56 am |
|
cchiesa1@rochester.rr.com (Chris Chiesa) wrote in message-id:
<f201def1.0406181338.7f17bb6@posting.google.com>
>
>For the past six w s or so, I have been fighting on-and-off with
>several issues surrounding MainWindow resizing. In my application I
>want to build an initial, largely empty GUI, then populate it with
>various widgets in response to user input at run time. Unfortunately,
>unless I do things "just exactly right," the MainWindow fails to
>resize (expand and contract) to match the comings-and-goings of child
>widget hierarchies created/destroyed "dynamically" in the course of
>operations. Sometimes the MainWindow doesn't resize at all, sometimes
>it resizes "partway," and only rarely, after much trial-and-error,
>have I gotten it to resize "just right..."
>
>There seem to be three issues; two that I've solved, and one that is
>still a mystery.
>
>First, observe the following example program:
>
>--------
>#!/usr/local/bin/perl -w
>
>use strict 'refs';
>
>use Tk;
>
>my $mw = MainWindow->new();
>
>my $button = $mw->Button(-text => 'Click Me',
> -command => sub { addButton(); } )
> ->pack;
>
>MainLoop;
>
>sub addButton
>{
> my $nooF = $mw->Frame; # Don't pack here, due to Problem #1
>
> my $nooB = $nooF->Button(-text => "New"); # Don't pack() yet...
> $nooB->configure(-command => sub { remButton( $nooB, $nooF ); } );
>
> $nooF->pack; # ONE
> $nooB->pack; # TWO
>
>}
>
>sub remButton
>{
> $_[0]->destroy; # Button
> $_[1]->destroy; # Frame
>}
>
>This program initially displays a single button reading "Click Me."
>When you click on it, nothing obvious happens -- but actually each
>click is causing another new button, reading "New," to be created and
>packed into the MainWindow. You can't see these "New" buttons,
>though, because the MainWindow is not automatically expanding itself
>to reveal the new buttons. You must "manually" drag the MainWindow
>out to a larger size in order to see them.
>
>One fix for this is to swap the two lines commented #ONE and #TWO --
>that is, to pack each "New" button into its containing Frame _before_
>packing that Frame into the MainWindow. This makes no sense to me --
>I would think the resulting Widget-geometry hierarchy should be the
>same in the end, either way -- but this is what I observe. I
>tentatively deduce a general rule: "in order to obtain proper
>MainWindow resizing behavior, you must pack() all of a Frame's
>children _before_ pack()-ing the Frame itself into _its_ parent." In
>other words, "you must pack() 'from the bottom up'" when constructing
>a widget hierarchy. Although this solution "works," it bothers me
>because it flies directly in the face of the "standard" paradigm of
>doing e.g.
>
> $fr = $mw->Frame->pack;
> $btn = $fr->Button->pack;
> .
> . # construct-and-pack other contents of $fr, here...
> .
>
>Instead, my observation and the resulting rule forces me to code like
>THIS:
>
> $fr = $mw->Frame;
> $btn = $fr->Button;
> .
> . # construct other contents of $fr, here...
> .
> $btn->pack;
> .
> . # pack other contents of $fr, here...
> .
> $fr->pack; # Must be done LAST!
>
>-- which is a lot uglier, particularly when the Frame has a lot of
>children. I'm caught between "doing what works," and the strong
>suspicion that "that CAN'T be right, EVERYBODY programs it the FIRST
>way, and it seems to work..." What am I doing wrong here?
>
>The second issue arose when, after discovering the above, I
>painstakingly scoured-and-restructured my real application to
>eliminate all instances of the "wrong" packing-order, and my
>application's MainWindow STILL didn't auto-resize correctly. I
>tracked THAT down to an apparent requirement to "_construct_ ALL of a
>Frame's child widgets _before_ pack()-ing ANY of them." If I pack()ed
>a couple of the children before one of them was constructed, the
>MainWindow would resize only big enough for the contents that HAD been
>constructed as of the first (I think) pack() call. Again, there's no
>sense to this, but this is what I observe. This makes it even harder
>to construct a GUI in a "natural" order, because now you have all
>these secondary orderings to try to get right.
>
>Third and last, I have lately reorganized the GUI in my real
>application to take into account BOTH of these factors -- and AGAIN
>the MainWindow refuses to resize properly. I am trying to create, at
>run time, a Frame ($f1) containing children, and pack $f1 into a
>top-level Frame ($mF) that is the only child of the MainWindow. I
>construct and pack() several children into $f1, among them another
>Frame ($f2) that I want to use as a menubar. I find that if I EVER
>pack() $f2 into $f1 at ANY point in the code, the MainWindow resizes
>only big enough to allow for the height of $f2, 'ignoring' the rest of
>the children of $f1. If I DON'T pack() $f2 into $f1, the MainWindow
>resizes big enough for the full contents of $f1 (excepting the
>menubar, $f2, which I didn't pack()). This, again, is
>crazy-senseless, but this is what I am observing. I would _love_ to
>demonstrate this for you in a small example program, but I haven't
>been able to reproduce this effect (or that in the previous paragraph)
>in a small example. Small examples all work fine. :-b Oh, and grid()
>exhibits more-or-less analogous behaviors where I've said pack()
>throughout this message. :-b
>
>I've been scouring the Web, Usenet, Perl/Tk books, etc., for anything
>I can find on this subject, and have not found much. I've tried
>various combinations of packForget()-ing and re-pack()ing children,
>destroy()-ing and rebuilding the entire GUI, etc. etc. -- all things,
>I point out, that my co-workers have found to help with this same
>problem in some of _their_ Perl/Tk apps that have the same sort of
>problems! -- but these do not work. Just today I have gotten the
>vague idea that maybe "stacking order" comes into it somewhere, but I
>don't fully see how that's possible; nothing seems to be getting
>created "in front of" anything else -- my backgrounds are not hiding
>my buttons, or anything like that -- but I am otherwise completely
>stumped. I would be extremely grateful for any light anyone could
>shed on any of this!!!
>
>Thanks,
>
> Chris Chiesa
> Lead Programmer/Analyst, University of Rochester Laboratory for
>Laser Energetics
Might be able to use the 'geomtry method' thingy..
Not sure though ive never used 'pack' in one of my applications before.
#!
use strict;
use warnings;
use Tk;
#Main#
my $mw = MainWindow->new();
&a_gui(); &Tk::MainLoop();
#Subroutines#
sub a_gui #----------------------------------------------
{
my $b1 = $mw->Button(-text => 'Default Geometry',
-command => \&geometry1)->pack;
my $b2 = $mw->Button(-text => 'Big Geometry',
-command => \&geometry2)->pack;
#Callbacks
sub geometry1 #----------------------------------------------
{
$mw->geometry("");
}
sub geometry2 #----------------------------------------------
{
$mw->geometry("300x450+0+0");
}
}
| |
| zentara 2004-06-19, 3:56 pm |
| On 18 Jun 2004 14:38:11 -0700, cchiesa1@rochester.rr.com (Chris Chiesa)
wrote:
>For the past six w s or so, I have been fighting on-and-off with
>several issues surrounding MainWindow resizing. In my application I
>want to build an initial, largely empty GUI, then populate it with
>various widgets in response to user input at run time. Unfortunately,
>unless I do things "just exactly right," the MainWindow fails to
>resize (expand and contract) to match the comings-and-goings of child
>widget hierarchies created/destroyed "dynamically" in the course of
>operations. Sometimes the MainWindow doesn't resize at all, sometimes
>it resizes "partway," and only rarely, after much trial-and-error,
>have I gotten it to resize "just right..."
>
>There seem to be three issues; two that I've solved, and one that is
>still a mystery.
....program snipped.....
>This program initially displays a single button reading "Click Me."
>When you click on it, nothing obvious happens -- but actually each
>click is causing another new button, reading "New," to be created and
>packed into the MainWindow. You can't see these "New" buttons,
>though, because the MainWindow is not automatically expanding itself
>to reveal the new buttons.
I'm running Perl 5.8.3 and Tk 804.027 and your script works fine.
When I click on the ClickMe button, it creates a new button, and
the MainWindow is automatically enlarged to show it. When I click
on New, the button disappears and the MainWindow reduces in size.
Maybe if you are using an older Tk version, you might need to
do some manual repacking.
Look at this example I scavenged:
#!/usr/bin/perl
use Tk;
my $mw = MainWindow->new;
$mw->bind( "<Configure>" => sub { print "reconfigure
".ref($_[0])."\n" } );
my $topFr = $mw->Frame
->pack( -fill => "both", -expand => 1 );
$topFr->Button( -text => "bigger", -command => sub { changeSize(50) } )
->pack( -side => "bottom", -expand => 1 );
$topFr->Button( -text => "smaller", -command => sub { changeSize(-50) }
)
->pack( -side => "bottom", -expand => 1 );
my $interior = $topFr->Frame(
-label => "Hello world", -height => 100, -width => 100,
-background => "white", -relief => "groove" )
->pack( -side => "bottom", -fill => "both", -expand => 1 );
$interior->packPropagate(0);
MainLoop;
sub changeSize
{
my ($sizeDelta) = @_;
$interior->configure(
-width => $interior->width+$sizeDelta,
-height => $interior->height+$sizeDelta );
printf("interior %d x %d, topFr %d x %d\n",
$interior->width, $interior->height,
$topFr->width, $topFr->height );
}
__END__
########################################
################
and here is another snippet to help you detect a resize event.
#!/usr/bin/perl
use Tk;
my $mw = new MainWindow;
my $currentSize = $mw->reqwidth . "x" . $mw->reqheight;
$mw->bind('<Configure>', [\&OnResize, \$currentSize]);
MainLoop;
sub OnResize {
my ($mw, $oldSize) = @_;
my $newSize = $mw->width . "x" . $mw->height;
if ($$oldSize ne $newSize) {
## Resize has occurred do something:
printf("Resize happened - old size: %s, new size: %s\n",
$$oldSize, $newSize
);
## set the old size to the new size
$$oldSize = $newSize;
}
}
__END__
--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
| |
| Chris Chiesa 2004-06-25, 6:47 pm |
| $_@_.%_ wrote in message news:<RxLAc.3252$U.1953@nwrdny02.gnilink.net>...
> cchiesa1@rochester.rr.com (Chris Chiesa) wrote in message-id:
> <f201def1.0406181338.7f17bb6@posting.google.com>
>
> Might be able to use the 'geomtry method' thingy..
> Not sure though ive never used 'pack' in one of my applications before.
Alas, I tried the 'geometry method' thing and it didn't help.
One problem I find is that all the documentation, books, even Usenet
postings, discuss at great length the issue of how to get window
content to behave properly when the user "manually" resizes the
MainWindow -- i.e., the Pack Manager's behavior when propagating
container-size changes "down" to children -- but I've rarely/never
seen a discussion of size changes propagating the OTHER way -- i.e.
"up" from children to parent... to MainWindow... when the window
content changes. I can't believe nobody deals with this... how do you
all handle it?!?
Chris
| |
| $_@_.%_ 2004-06-25, 6:47 pm |
|
cchiesa1@rochester.rr.com (Chris Chiesa) wrote in message-id:
<f201def1.0406210451.5cd95e32@posting.google.com>
>
>$_@_.%_ wrote in message news:<RxLAc.3252$U.1953@nwrdny02.gnilink.net>...
>
>Alas, I tried the 'geometry method' thing and it didn't help.
>
>One problem I find is that all the documentation, books, even Usenet
>postings, discuss at great length the issue of how to get window
>content to behave properly when the user "manually" resizes the
>MainWindow -- i.e., the Pack Manager's behavior when propagating
>container-size changes "down" to children -- but I've rarely/never
>seen a discussion of size changes propagating the OTHER way -- i.e.
>"up" from children to parent... to MainWindow... when the window
>content changes. I can't believe nobody deals with this... how do you
>all handle it?!?
>
>Chris
Typically would use a paned window or scrollbars, but perhaps
assigning variables to the x and y coordinants when calling
mw->geometry(x,y,col,row)
If you used variables you might be be able to 'increment the variables'
each time a 'new widget is added', then re-issue the 'geometry' method
along with perhaps the 'update' method. Still there is the problem when
the mainwindow grows beyond display resolution.. eventually scrollbars
may need to come into play.
Just a thought, perhaps later on today I'll have a go at a test script,
but in the meantime, mabey you could try this; and good luck.
|
|
|
|
|