The default anchor is CENTER, so widgets show up in the middle of their space (the cavity
side they were given) unless they are positioned with anchor or stretched with fill. To
demonstrate, change gui4 to use this sort of code:
Button(win, text='Hello', command=greeting).pack(side=LEFT, anchor=N)
Label(win, text='Hello container world').pack(side=TOP)
Button(win, text='Quit', command=win.quit).pack(side=RIGHT)
The only thing new here is that the Hello button is anchored to the north side of its
space allocation. Because this button was packed first, it got the entire left side of the
parent frame. This is more space than is needed to show the button, so it shows up in
the middle of that side by default, as in Figure 7-15 (i.e., anchored to the center). Setting
the anchor to N moves it to the top of its side, as shown in Figure 7-18.
Figure 7-18. Anchoring a button to the north
Keep in mind that fill and anchor are applied after a widget has been allocated cavity
side space by its side, packing order, and expand extra space request. By playing with
packing orders, sides, fills, and anchors, you can generate lots of layout and clipping
effects, and you should take a few moments to experiment with alternatives if you
haven’t already. In the original version of this example, for instance, the label spans the
entire top side just because it is the first packed.
As we’ll see later, frames can be nested in other frames, too, in order to make more
complex layouts. In fact, because each parent container is a distinct space cavity, this
provides a sort of escape mechanism for the packer cavity algorithm: to better control
where a set of widgets show up, simply pack them within a nested subframe and attach
the frame as a package to a larger container. A row of push buttons, for example, might
be easier laid out in a frame of its own than if mixed with other widgets in the display
directly.
Finally, also keep in mind that the widget tree created by these examples is really an
implicit one; tkinter internally records the relationships implied by passed parent
widget arguments. In OOP terms, this is a composition relationship—the Frame contains
a Label and Buttons. Let’s look at inheritance relationships next.
Customizing Widgets with Classes
You don’t have to use OOP in tkinter scripts, but it can definitely help. As we just saw,
tkinter GUIs are built up as class-instance object trees. Here’s another way Python’s
400 | Chapter 7: Graphical User Interfaces