8.7. Adding Buttons and Callbacks
So far, we've learned how to display messages in labels, and we've met Tkinter core concepts along the way. Labels are nice for teaching the basics, but user interfaces usually need to do a bit more; like actually responding to users. The program in Example 8-10 creates the window in Figure 8-7.
Figure 8-7. A button on the top
Example 8-10. PP3E\Gui\Intro\gui2.py
Here, instead of making a label, we create an instance of the Tkinter Button class. It's attached to the default top level as before on the default TOP packing side. But the main thing to notice here is the button's configuration arguments: we set an option called command to the sys.exit function.
For buttons, the command option is the place where we specify a callback handler function to be run when the button is later pressed. In effect, we use command to register an action for Tkinter to call when a widget's event occurs. The callback handler used here isn't very interesting: as we learned in an earlier chapter, the built-in sys.exit function simply shuts down the calling program. Here, that means that pressing this button makes the window go away.
Just as for labels, there are other ways to code buttons. Example 8-11 is a version that packs the button in place without assigning it to a name, attaches it to the LEFT side of its parent window explicitly, and specifies root.quit as the callback handlera standard Tk object method that shuts down the GUI and so ends the program (really, it ends the current mainloop event loop call).
Example 8-11. PP3E\Gui\Intro\gui2b.py
This version produces the window in Figure 8-8. Because we didn't tell the button to expand into all available space, it does not do so.
Figure 8-8. A button on the left
In both of the last two examples, pressing the button makes the GUI program exit. In older Tkinter code, you may sometimes see the string exit assigned to the command option to make the GUI go away when pressed. This exploits a tool in the underlying Tk library and is less Pythonic than sys.exit or root.quit.
8.7.1. Widget Resizing Revisited: Expansion
Even with a GUI this simple, there are many ways to lay out its appearance with Tkinter's constraint-based pack geometry manager. For example, to center the button in its window, add an expand=YES option to the button's pack method call, and generate a window such as Figure 8-9. This makes the packer allocate all available space to the button but does not stretch the button to fill that space.
Figure 8-9. side=LEFT, expand=YES
If you want the button to be given all available space and to stretch to fill all of its assigned space horizontally, add expand=YES and fill=X keyword arguments to the pack call. This will create the scene in Figure 8-10.
Figure 8-10. side=LEFT, expand=YES, fill=X
This makes the button fill the whole window initially (its allocation is expanded, and it is stretched to fill that allocation). It also makes the button grow as the parent window is resized. As shown in Figure 8-11, the button in this window does expand when its parent expands, but only along the X horizontal axis.
Figure 8-11. Resizing with expand=YES, fill=X
To make the button grow in both directions, specify both expand=YES and fill=BOTH in the pack call; now resizing the window makes the button grow in general, as shown in Figure 8-12. In fact, for a good time, maximize this window to fill the entire screen; you'll get one very big Tkinter button indeed.
Figure 8-12. Resizing with expand=YES, fill=BOTH
In more complex displays, such a button will expand only if all of the widgets it is contained by are set to expand too. Here, the button's only parent is the Tk root window of the program, so parent expandability isn't yet an issue. We will revisit the packer geometry manager when we meet multiple-widget displays later in this tutorial and again when we study the alternative grid call in Chapter 10.