The gui1
script is a
trivial example, but it illustrates steps common to most Tkinter
programs. This Python code does the following:
The mainloop
method called
last puts the label on the screen and enters a Tkinter wait state,
which watches for user-generated GUI events. Within the mainloop
function, Tkinter internally
monitors things such as the keyboard and mouse to detect
user-generated events. In fact, the Tkinter mainloop
function is similar in spirit to
the following pseudo-Python code:
def mainloop( ): while the main window has not been closed: if an event has occurred: run the associated event handler function
Because of this model, the mainloop
call in Example 8-1 never returns to our
script while the GUI is displayed on-screen.[*] When we write larger scripts, the only way we can get
anything done after calling mainloop
is to register callback handlers to
respond to events.
This is called event-driven programming, and it is perhaps one of the most unusual aspects of GUIs. GUI programs take the form of a set of event handlers that share saved information rather than of a single main control flow. We’ll see how this looks in terms of real code in later examples.
Note that in a script, you really need steps 3 and 4 in the
preceding list to open this script’s GUI. To display a GUI’s window at
all, you need to call mainloop
; to
display widgets within the window, they must be packed (or otherwise
arranged) so that the Tkinter geometry manager knows about them. In
fact, if you call either mainloop
or pack
without calling the other,
your window won’t show up as expected: a mainloop
without a pack
shows an empty window, and a pack
without a mainloop
in a script shows nothing since the
script never enters an event wait state (try it).
Since the concepts illustrated by this simple script are at the core of most Tkinter programs, let’s take a deeper look at some of them before moving on.
When widgets are constructed in Tkinter, we can
specify how they should be configured. The gui1
script passes two arguments to the
Label
class constructor:
The first is a parent-widget object, which we want the new
label to be attached to. Here, None
means “attach the new Label
to the default top-level window
of this program.” Later, we’ll pass real widgets in this
position to attach our labels to other container objects.
The second is a configuration option for the Label
, passed as a keyword argument:
the text
option specifies a
text string to appear as the label’s message. Most widget
constructors accept multiple keyword arguments for specifying a
variety of options (color, size, callback handlers, and so on).
Most widget configuration options have reasonable defaults per
platform, though, and this accounts for much of Tkinter’s
simplicity. You need to set most options only if you wish to do
something custom.
As we’ll see, the parent-widget argument is the hook we use to
build up complex GUIs as widget trees. Tkinter works on a
“what-you-build-is-what-you-get” principle: we construct widget
object trees as models of what we want to see on the screen, and
then ask the tree to display itself by calling mainloop
.
The pack
widget method called by the gui1
script invokes the packer geometry
manager, one of three ways to control how widgets are arranged
in a window. Tkinter geometry managers simply arrange one or more
widgets within a container (sometimes called a parent or master).
Both top-level windows and frames (a special kind of widget we’ll
meet later) can serve as containers, and containers may be nested
inside other containers to build hierarchical displays.
The packer geometry manager uses constraint option settings to
automatically position widgets in a window. Scripts supply
higher-level instructions (e.g., “attach this widget to the top of
its container, and stretch it to fill its space vertically”), not
absolute pixel coordinates. Because such constraints are so
abstract, the packer provides a powerful and easy-to-use layout
system. In fact, you don’t even have to specify constraints. If you
don’t pass any arguments to pack
,
you get default packing, which attaches the widget to the top side
of its container.
We’ll visit the packer repeatedly in this chapter and use it
in many of the examples in this book. In Chapter 10, we will also meet an
alternative grid
geometry manager
and layout system that arranges widgets within a container in
tabular form (i.e., by rows and columns). A third alternative,
called the placer geometry manager system, is
described in Tk documentation but not in this book; it’s less
popular than the pack
and
grid
managers and can be
difficult to use for larger GUIs.
Like all Python code, the module in Example 8-1 can be started in a number of ways: by running it as a top-level program file:
C:...PP3EGuiIntro>python gui1.py
by importing it from a Python session or another module file:
>>>import gui1
by running it as a Unix executable if we add the special
#!
line at the top:
%gui1.py &
and in any other way Python programs can be launched on your
platform. For instance, the script can also be run by clicking on
the file’s name in a Windows file explorer, and its code can be
typed interactively at the >>>
prompt.[*] It can even be run from a C program by calling the
appropriate embedding API function (see Chapter 23 for details).
In other words, there are really no special rules to follow when running GUI Python code. The Tkinter interface (and Tk itself) is linked into the Python interpreter. When a Python program calls GUI functions, they’re simply passed to the embedded GUI system behind the scenes. That makes it easy to write command-line tools that pop up windows; they are run the same way as the purely text-based scripts we studied in the prior part of this book.
Earlier in this book we learned that if a program’s name ends in a .pyw extension rather than a .py extension, the Windows Python port does not pop up a DOS console box to serve as its standard streams when the file is launched by clicking its filename icon. Now that we’ve finally started making windows of our own, that filename trick will start to become even more useful.
If you just want to see the windows that your script makes no matter how it is launched, be sure to name your GUI scripts with a .pyw if they might be run on Windows. For instance, clicking on the file in Example 8-2 in a Windows explorer creates just the window in Figure 8-1.
You can also avoid the DOS pop up on Windows by running the
program with the pythonw.exe executable, not
python.exe (in fact,
.pyw files are simply registered to be opened
by pythonw
). On Linux, the
.pyw doesn’t hurt, but it isn’t necessary;
there is no notion of a streams pop up on Unix-like machines. On
the other hand, if your GUI scripts might run on Windows in the
future, adding an extra “w” at the end of their names now might
save porting effort later. In this book, .py
filenames are still sometimes used to pop up console windows for
viewing printed messages on Windows.
[*] Technically, the mainloop
call returns to your script only after the Tkinter event loop
exits. This normally happens when the GUI’s main window is closed,
but it may also occur in response to explicit quit
method calls that terminate nested
event loops but leave open the GUI at large. You’ll see why this
matters in Chapter 9.
[*] Tip: when typing Tkinter GUI code
interactively, you may or may not need to
call mainloop
to display
widgets. This is required in the current IDLE interface, but not
from a simple interactive session running in a system console
window. In either case, control will return to the interactive
prompt when you kill the window you created. Note that if you
create an explicit main-window widget by calling Tk( )
and attach widgets to it
(described later), you must call this again after killing the
window; otherwise, the application window will not exist.
3.145.35.247