Version 26 of Geometry Managers

Updated 2004-12-22 14:35:33

* What are geometry managers - when do you use one?

  • What geometry managers come with Tk? place - pack - grid - also, the text and canvas widgets 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.
  • How do you decide to use one over another? RS: grid for tabular layouts, mostly pack; hardly ever place or have a look at Comparing Geometry Managers.
  • What other geometry managers are available?
  • BLT has a table geometry manager
  • layout is a Tk front-end that calls the standard geometry managers with a different interface
  • Tix has a form geometry manager
  • TkVSform does geometry management (along with other things) for its forms
  • GRIDPLUS is a screen layout package built on the Tk grid manager

Stacking Order is an aspect of Geometry Management


QUESTION - 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
  2. 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

Many widgets have -width and -height options, but those do not usually give useful results when read (for the purposes of geometry management.) The [winfo width] and [winfo height] commands 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 the [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 [L1 ].

DKF


KBK: You also need to include update idletasks in the case where another geometry manager is managing the reqwidth or 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.


Kevin explains widget geometry using adult language in a comp.lang.tcl thread [L2 ].

KBK By "adult language", I think that the original poster means that I don't talk down to the reader, but call a spade a shovel. I grepped for @#$%! in the page, and didn't find it, so I don't think he meant "adult language" in the sense that movie rating boards use it!


Introspection on geometry managers is possible; that is, one can command

    winfo manager $widget

Notice that

    winfo manager $toplevel

returns the special value "wm".


QUESTION - Michael 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.


QUESTION - 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 1 Jul 2003 - Apparently not. Darn.



QUESTION - []

Can you point me to a link/site with EXAMPLES about the usage of pack/grid/place ? This would be extremely useful.

Lars H: Not a link, but here is an example. The main structure uses grid, but the "toolbar" frame on the top uses pack internally. Widgets named something ending in _c are canvases, ending in _h horizontal scrollbars, 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

Category GUI