The relative size and placement parameters of the place command can be used to create custom geometry managers. Example 25-5 shows a paned layout manager. Two frames, or panes, are placed inside another frame. A small third frame represents a grip that is used to adjust the boundary between the two panes:
The Pane_Create procedure is given two widgets to manage, and an optional set of parameters. The general syntax of Pane_Create is:
Pane_Create f1 f2 ?-orient xy? ?-percent p? ?-in master?
All the optional arguments are available in $args. Its attribute-value structure is used to initialize a temporary array t. Default values are set before the assignment from $args. The following code is compact but doesn't check errors in the optional arguments.
set t(-orient) vertical set t(-percent) 0.5 set t(-in) [winfo parent $f1] array set t $args
Global state about the layout is kept in an array whose name is based on the master frame. The name of the master frame isn't known until after arguments are parsed, which is why t is used. After the upvar the argument values are copied from the temporary array into the global state array:
set master $t(-in) upvar #0 Pane$master pane array set pane [array get t]
Example 25-5 sets several place parameters on the frames when they are created. These are remembered, and other parameters are adjusted later to dynamically adjust the boundary between the frames. All Tk geometry managers retain settings like this. The initial settings for the vertical layout is shown here:
place $pane(1) -in $parent -x 0 -rely 0.0 -anchor nw -relwidth 1.0 -height -1 place $pane(2) -in $parent -x 0 -rely 1.0 -anchor sw -relwidth 1.0 -height -1 place $pane(grip) -in $parent -anchor c -relx 0.8
The position of the upper and lower frames is specified with an absolute X and a relative Y position, and the anchor setting is chosen to keep the frame visible inside the main frame. For example, the lower frame is positioned at the bottom-left corner of the container with -x 0 and -rely 1.0. The -anchor sw attaches the lower-left corner of the frame to this position.
The size of the contained frames is also a combination of absolute and relative values. The width is set to the full width of the container with -relwidth 1.0. The height is set to minus one with -height -1. This value gets added to a relative height that is determined later. It will leave a little space between the two contained frames.
The resize grip is just a small frame positioned at the boundary. Initially it is just placed over toward one size with -relx 0.8. It gets positioned on the boundary with a -rely setting later. It has a different cursor to indicate it is active.
The example uses some event bindings that are described in more detail in Chapter 26. The <Configure> event occurs when the containing frame is resized by the user. When the user presses the mouse button over the grip and drags it, there is a <ButtonPress-1> event, one or more <B1-Motion> events, and finally a <ButtonRelease-1> event. Tcl commands are bound to these events:
bind $parent <Configure> [list PaneGeometry $parent] bind $pane(grip) <ButtonPress-1> [list PaneDrag $parent %$pane(D)] bind $pane(grip) <B1-Motion> [list PaneDrag $parent %$pane(D)] bind $pane(grip) <ButtonRelease-1> [list PaneStop $parent]
The code is set up to work with either horizontal or vertical layouts. The pane(D) variable is either X, for a horizontal layout, or Y, for a vertical layout. This value is used in the bindings to get %X or %Y, which are replaced with the X and Y screen positions of the mouse when the bindings fire. This value is passed to PaneDrag as the parameter D. The PaneDrag procedure remembers the previous position in pane(lastD) and uses that to update the percentage split between the two contained panes:
The PaneGeometry procedure adjusts the positions of the frames. It is called when the main window is resized, so it updates pane(size). It is also called as the user drags the grip. For a vertical layout, the grip is moved by setting its relative Y position. The size of the two contained frames is set with a relative height. Remember that this is combined with the fixed height of -1 to get some space between the two frames:
3.143.5.201