Geometry Managers

Difference between version 36 and 37 - Previous - Next
A '''geometry manager''' manages the placement and layout of the elements of a
[GUI].



** See Also **

   [Comparing Geometry Managers]:   

   [http://wiki.tcl.tk/38909%|%A Program In Tcl/Tk To Demonstrate The Three Geometry Managers : pack, grid and place]:   

   [Stacking Order]:   an aspect of geometry management



** Reading **

   [http://groups.google.com/d/msg/comp.lang.tcl/O890hopUMTE/y5Wpwr_UP_sJ%|%Windownamager geometry problem] , [comp.lang.tcl] ,2002-06-04:   [KBK] gives a good description of the requested versus the actual geometry of a widget




** [Tk] geometry managers **


   [place]:   precise placement of a widget in absolute coordinates, for when you want to roll your own geometry manager
   
   [pack]:   widgets flow around each other in the available space
   
   [grid]:   available space is devided into numbers sectors to which widgets are either manually or automatically assigned.  Somewhat more direct and intuitive than [pack].


The [text] and [canvas] widgets also have a limited capability to manage the
geometry of child widgets (without using place, pack or grid).  For example,
[BWidget] constructs a scrollable frame megawidget by creating a frame as an
embedded window of a canvas.



** Other Geometry Managers **

   [BLT]'s table geometry manager:   

   [layout]:   a Tk front-end that calls the standard geometry managers with a different interface

   [Tix]'s form geometry manager:   

   [TkVSform]:   does geometry management (along with other things) for its forms

   [GRIDPLUS2]:   is a screen layout package built on the Tk [grid] manager

   [making your own geometry manager]:   
   [Pave, sort of geometry manager]:   


** Description **

Choose [grid] for tabular layouts, and when there's no good reason to choose
something else.  Choose [pack] if you're used to the web browser box model, and
the flow makes sense to you.  Choose [place] when you want as little help as
possible managing the layout.



** Introspection **

Introspection on geometry managers is possible:

======
winfo manager $widget
======

Notice that

======
winfo manager $toplevel
======

returns the special value, `wm`.



** Horizontal Stretch of One Widget, But No Vertical Stretch of Either Widget **

[Harald Kirsch]:  Is it possible with place to position a widget .f.bot just
below another widget .f.top such that the following holds:
 
   1. If the container .f is resized vertically, both widgets keep their natural height and keep sticked to the top of .f
   1. If .f is resized horizontally, .f.top keeps it natural width and stays sticked to the left border of .f while .f.bot resizes itself to stretch over the whole width of .f.

Please note that 2 seems to make it impossible to use the sibling-trick mentioned in the place-manual.

I would probably get the above done with place, if I knew a way of
extracting the natural width and height of widgets which are
[[place]]d. Neither [[... cget -width]] nor [[winfo width ...]] deliver
anything useful - except if I call update before calling winfo.

'''ANSWER''' - DKF

You need to use [[winfo reqwidth]].  Code that satisfies your request
follows:

======
# Basic Setup
frame .f -bg red
label .f.top -text "I'm top" -bg yellow
label .f.bot -text "I'm bot" -bg white
pack .f -fill both -expand 1
# Geometry Manager Magic
set w1 [winfo reqwidth .f.top]
set w2 [winfo reqwidth .f.bot]
if {$w1<$w2} {set w1 $w2}
set h [expr {[winfo reqheight .f.top]+[winfo reqheight .f.bot]}]
.f configure -width $w1 -height $h
place .f.top -x 0 -y 0
place .f.bot -x 0 -y [winfo reqheight .f.top] -relwidth 1
======

Did you know that you can also achieve the same effect using `grid`?

======
# Basic Setup
frame .f -bg red
label .f.top -text "I'm top" -bg yellow
label .f.bot -text "I'm bot" -bg white
pack .f -fill both -expand 1
# Geometry Manager Magic
grid .f.top -sticky w
grid .f.bot -sticky ew
grid columnconfigure .f 0 -weight 1
grid rowconfigure .f 2 -weight 1 -minsize 0
======

And also `[pack]`?

======
# Basic Setup
frame .f -bg red
label .f.top -text "I'm top" -bg yellow
label .f.bot -text "I'm bot" -bg white
pack .f -fill both -expand 1
# Geometry Manager Magic
pack .f.top -side top -anchor w
pack .f.bot -side top -anchor nw -fill x -expand 1
======

----

[DKF]:

Many widgets have `'''-width'''` and `'''-height'''` options, but those do not
usually give useful results when read (for the purposes of geometry
management.)  `[winfo width]` and `[winfo height]` would be more useful you'd
think, but in fact they only ever report the ''current'' size of a widget,
which is initially zero as there hasn't been time to work it out yet (since
interaction with geometry managers is performed on idle updates.)  To get the
info you need for GM, you need `winfo reqheight` and `winfo reqwidth` commands,
which report what size widgets would prefer to be.

The other thing you need to watch out for if you are doing any fancy geometry
mangling (unlike the simple example above) is the `'''<Configure>'''` event.
This lets you find out when the enclosing widget changes in size due to
whatever GM is managing ''it''.  A sophisticated example that uses the
configure events is available at
[http://www.cs.man.ac.uk/~fellowsd/tcl/#scripts/notebook].


----

[KBK]: You also need to include `'''update idletasks'''` in the case where
another geometry manager is managing the `winfo reqwidth` or `winfo reqheight`
of the widget.  It is possible that the requested size is zero because a
subordinate geometry manager hasn't had the chance to work out the size.



** Using Text Widget As a Flowing Geometry Manager **

[Michail Richardson]: Is it possible with pack to position a series of widgets
in a frame such that if they all fit in the horizontal space, then they are
arranged that way.  Otherwise, they are folded like text. A sort of message
window for frames.  This is so that a series of radiobuttons that exceeds the
width of the user's screen can properly be displayed, in, e.g. tkGnats.  (The
list of buttons is determined at run-time)


[KBK]: Sure.  Window them in a text widget.  There's an example in the "Widget
Tour" that comes with Tk that does just what you're asking.

[escargo]: This sounds like the Java flow layout.



** Using `[pack]` and `[grid]` Together **

[Lars H]: In the following example, the main structure uses `[grid]`, but the
"toolbar" frame on the top uses `[pack]` internally.  Widgets named something
ending in `_c` are [canvas]es, ending in `_h` horizontal [scrollbar]s, and
those ending in _v are vertical scrollbars.

======
set t [toplevel .rulebrowser]
wm title $t "Rule browser"

# First create some things to manage
foreach c_ [list $t.left_ $t.right_] {
   scrollbar ${c_}h -orient horiz -command [list ${c_}c xview]
   scrollbar ${c_}v -command [list ${c_}c yview]
   canvas ${c_}c -width 200 -height 400 -relief solid -borderwidth 1\
     -xscrollcommand [list ${c_}h set] -yscrollcommand [list ${c_}v set]\
     -scrollregion {0 0 300 500}
}

# Then start managing
grid $t.left_c  -row 2 -column 0 -sticky nsew
grid $t.right_c -row 2 -column 3 -sticky nsew
grid $t.left_v  -row 2 -column 1 -sticky ns
grid $t.right_v -row 2 -column 4 -sticky ns
grid $t.left_h  -row 3 -column 0 -sticky ew
grid $t.right_h -row 3 -column 3 -sticky ew
grid rowconfigure $t 2 -weight 1
grid columnconfigure $t 0 -weight 1
grid columnconfigure $t 3 -weight 1

canvas $t.arrow_c -width 20 -height 20
$t.arrow_c create line {0 10 20 10} -arrow last -width 2
grid $t.arrow_c -row 2 -column 2

scrollbar $t.text_v -command [list $t.text_t yview]
text $t.text_t -height 5 -yscrollcommand [list $t.text_v set]
grid $t.text_t - - - -row 1 -column 0 -sticky nsew
grid $t.text_v -row 1 -column 4 -sticky ns

set bg grey90
frame $t.f -background $bg
grid $t.f - - - - -row 0 -column 0 -sticky ew
pack [button $t.f.prev -text "Prev" -highlightbackground $bg] -side left
pack [button $t.f.next -text "Next" -highlightbackground $bg] -side left
pack [button $t.f.go -text "Go" -highlightbackground $bg] -side right
pack [entry $t.f.go_e -width 4] -side right
pack [label $t.f.go_l -text "Rule" -background $bg] -side right
======



** Misc **

[escargo]:  Is there any way to tell which of the commands (or potentially
procedures) act as geometry managers?  (This is in some respects an
[Introspection] question as well.)

[escargo] 2003-07-01: Apparently not.  Darn.


<<categories>> GUI