Recipe 15.16 Responding to Tk Resize Events
15.16.1 Problem
You've written a Tk program, but your
widget layout goes awry when the user resizes their window.
15.16.2 Solution
You can prevent the user from resizing the window by intercepting the
Configure event:
use Tk;
$main = MainWindow->new( );
$main->bind('<Configure>' => sub {
$xe = $main->XEvent;
$main->maxsize($xe->w, $xe->h);
$main->minsize($xe->w, $xe->h);
});
Or you can use pack to control how each widget
resizes and expands when the user resizes its container:
$widget->pack( -fill => "both", -expand => 1 );
$widget->pack( -fill => "x", -expand => 1 );
15.16.3 Discussion
By default, packed widgets resize if their container changes
size—they don't scale themselves or their contents to the new
size. This can lead to empty space between widgets, or cropped or
cramped widgets if the user resizes the window.
One solution is to prevent resizing. We bind to
the Configure event, which is sent when a widget's
size or position changes, registering a callback to reset the
window's size. This is how you'd ensure a pop-up error-message box
couldn't be resized.
You often want to let the user resize the application's windows. You
must then define how each widget will react. Do this through the
arguments to the pack method:
-fill controls the dimensions the widget will
resize in, and -expand controls whether the
widget's size will change to match available space. The
-expand option takes a Boolean value, true or
false. The -fill option takes a string indicating
the dimensions the widget can claim space in: "x",
"y", "both", or
"none".
The solution requires both options. Without -fill,
-expand won't claim space to grow into. Without
-expand, -fill will claim empty
space but won't expand in it.
Different parts of your application will behave differently. The main
area of a web browser, for example, should probably change size in
both dimensions when the window is resized. You'd pack the widget
like this:
$mainarea->pack( -fill => "both", -expand => 1 );
The menubar above the main area, though, should expand horizontally
but not vertically. You'd pack the widget thus:
$menubar->pack( -fill => "x", -expand => 1 );
Associated with resizing is the need to anchor a widget to part of
its container. Here's how you'd anchor the menubar to the top-left
corner of its container when you call pack:
$menubar->pack (-fill => "x",
-expand => 1,
-anchor => "nw" );
Now when you resize it, the menubar stays at the top of the window
where it belongs, instead of being centered in wide open space.
15.16.4 See Also
The pack(n), XEvent(3), and
XConfigureEvent(3) manpages (if you have them);
Tcl and the Tk Toolkit, by John Ousterhout
(Addison-Wesley); Mastering Perl/Tk
|