This chapter is a continuation of our look at GUI programming in
Python. The previous chapter used simple widgets—buttons, labels, and the
like—to demonstrate the fundamentals of Python/tkinter coding. That was
simple by design: it’s easier to grasp the big GUI picture if widget
interface details don’t get in the way. But now that we’ve seen the
basics, this chapter and the next move on to present a tour of more
advanced widget objects and tools available in the tkinter library.
As we’ll find, this is where GUI scripting starts getting both
practical and fun. In these two chapters, we’ll meet classes that build
the interface devices you expect to see in real programs—e.g., sliders,
check buttons, menus, scrolled lists, dialogs, graphics, and so on. After
these chapters, the last GUI chapter moves on to present larger GUIs that
utilize the coding techniques and the interfaces shown in all prior GUI
chapters. In these two chapters, though, examples are small and
self-contained so that we can focus on widget details.
Technically, we’ve already used a handful of simple widgets in
Chapter 7
. So far we’ve metLabel
,Button
,Frame
, andTk
, and studiedpack
geometry management concepts along the
way. Although all of these are basic, they represent tkinter interfaces
in general and can be workhorses in typical GUIs.Frame
containers, for instance, are the basis
of hierarchical display layout.
In this and the following chapter, we’ll explore additional
options for widgets we’ve already seen and move beyond the basics to
cover the rest of the tkinter widget set. Here are some of the widgets
and topics we’ll explore in this chapter:
Toplevel
andTk
widgets
Message
andEntry
widgets
Checkbutton
,Radiobutton
, andScale
widgets
Images:PhotoImage
andBitmapImage
objects
Widget and window configuration options
Dialogs, both standard and custom
Low-level event binding
tkinter linked variable objects
Using the Python Imaging Library (PIL) extension for other
image types and
operations
After this chapter,
Chapter 9
concludes the two-part tour by presenting the remainder of the tkinter
library’s tool set: menus, text, canvases, animation, and more.
To make this tour interesting, I’ll also introduce a few notions
of component reuse along the way. For instance, some later examples will
be built using components written for prior examples. Although these two
tour chapters introduce widget interfaces, this book is also about
Python programming in general; as we’ll see, tkinter programming in
Python can be much more than simply drawing circles and arrows.
So far, all the buttons
and labels in examples have been rendered with a default
look-and-feel that is standard for the underlying platform. With my
machine’s color scheme, that usually means that they’re gray on Windows.
tkinter widgets can be made to look arbitrarily different, though, using a
handful of widget and packer options.
Because I generally can’t resist the temptation to customize widgets
in examples, I want to cover this topic early on the tour.
Example 8-1
introduces some of the
configuration options available in tkinter.
Example 8-1. PP4E\Gui\Tour\config-label.py
from tkinter import *
root = Tk()
labelfont = ('times', 20, 'bold') # family, size, style
widget = Label(root, text='Hello config world')
widget.config(bg='black', fg='yellow') # yellow text on black label
widget.config(font=labelfont) # use a larger font
widget.config(height=3, width=20) # initial size: lines,chars
widget.pack(expand=YES, fill=BOTH)
root.mainloop()
Remember, we can call a widget’sconfig
method
to reset its options at any time, instead of passing all of
them to the object’s constructor. Here, we use it to set options that
produce the window in
Figure 8-1
.
Figure 8-1. A custom label appearance
This may not be completely obvious unless you run this script on a
real computer (alas, I can’t show it in color here), but the label’s text
shows up in yellow on a black
background
, and with a font that’s very
different from what we’ve seen so far. In fact, this script
customizes the label in a number of ways:
By setting thebg
option of
the label widget here, its background is displayed in
black; thefg
option
similarly changes the foreground (text) color of the
widget to yellow. These color options work on most tkinter widgets
and accept either a simple color name (e.g.,'blue'
) or a hexadecimal string. Most of
the color names you are familiar with are supported (unless you
happen to work for Crayola). You can also pass a hexadecimal color
identifier string to these options to be more specific; they start
with a#
and name a color by its
red, green, and blue saturations, with an equal number of bits in
the string for each. For instance,'#ff0000'
specifies eight bits per color
and defines pure red; “f” means four “1” bits in hexadecimal. We’ll
come back to this hex form when we meet the color selection dialog
later in this chapter.
The label is
given a preset size in lines high and characters wide
by setting itsheight
andwidth
attributes. You can use
this setting to make the widget larger than the tkinter geometry
manager would by default.
This script specifies a
custom font for the label’s text by setting the
label’sfont
attribute to a
three-item tuple giving the font family, size, and style (here:
Times, 20-point, and bold). Font style can benormal
,bold
,roman
,italic
,underline
,overstrike
, or combinations of these
(e.g., “bold italic”). tkinter guarantees thatTimes
,Courier
, andHelvetica
font family names exist on all
platforms, but others may work, too (e.g.,system
gives the system font on Windows).
Font settings like this work on all widgets with text, such as
labels, buttons, entry fields, listboxes, andText
(the latter of which can even display
more than one font at once with “tags”). Thefont
option still accepts older
X-Windows-style font indicators—long strings with dashes and
stars—but the newer tuple font indicator form is more platform
independent.
Finally, the label is
made generally expandable and stretched by setting thepack expand
andfill
options we met in the last chapter;
the label grows as the window does. If you maximize this window, its
black background fills the whole screen and the yellow message is
centered in the middle; try it.
In this script, the net effect of all these settings is that this
label looks radically different from the ones we’ve been making so far. It
no longer follows the Windows standard look-and-feel, but such conformance
isn’t always important. For reference, tkinter provides additional ways to
customize appearance that are not used by this script, but which may
appear in others:
Abd=
N
widget option
can be used to set border width, and arelief=
S
option can specify a border style;S
can
beFLAT
,SUNKEN
,RAISED
,GROOVE
,SOLID
, orRIDGE
—all constants exported by the
tkinter module.
Acursor
option can be
given to
change the appearance of the mouse pointer when it
moves over the widget. For instance,cursor='gumby'
changes the pointer to a
Gumby figure (the green kind). Other common cursor names used in
this book includewatch
,pencil
,cross
, andhand2
.
Some widgets also
support the notion of a state, which impacts their
appearance. For example, astate=DISABLED
option will generally
stipple (gray out) a widget on screen and make it unresponsive;NORMAL
does not. Some widgets
support aREADONLY
state as well,
which displays normally but is unresponsive to changes.
Extra space can be
added around many widgets (e.g., buttons, labels, and
text) with thepadx=
N
andpady=
N
options. Interestingly, you can set these options both inpack
calls (where it adds empty space
around the widget in general) and in a widget object itself (where
it makes the widget larger).
To illustrate some of these extra settings,
Example 8-2
configures the custom
button captured in
Figure 8-2
and changes
the mouse pointer when it is positioned above it.
Figure 8-2. Config button at work
Example 8-2. PP4E\Gui\Tour\config-button.py
from tkinter import *
widget = Button(text='Spam', padx=10, pady=10)
widget.pack(padx=20, pady=20)
widget.config(cursor='gumby')
widget.config(bd=8, relief=RAISED)
widget.config(bg='dark green', fg='white')
widget.config(font=('helvetica', 20, 'underline italic'))
mainloop()
To see the effects generated by these two scripts’ settings, try out
a few changes on your computer. Most widgets can be given a custom
appearance in the same way, and we’ll see such options used repeatedly in
this text. We’ll also meet operational configurations, such asfocus
(for focusing input) and others. In fact,
widgets can have dozens of options; most have reasonable defaults that
produce a native look-and-feel on each windowing platform, and this is one
reason for tkinter’s simplicity. But tkinter lets you build more custom
displays when you
want to.
For more on ways to apply configuration options to provide common
look-and-feel for your widgets, refer back to
Customizing Widgets with Classes
, especially itsThemedButton
examples. Now that you know more
about configuration, its examples’ source code should more readily show
how configurations applied in widget subclasses are automatically
inherited by all instances and subclasses. The new
ttk
extension described in
Chapter 7
also provides additional ways to
configure widgets with its notion of themes; see the preceding chapter
for more details and resources on ttk.