Tkinter GUIs always have a root window, whether you get
it by default or create it explicitly by calling the Tk
object constructor. This main root window
is the one that opens when your program runs, and it is where you
generally pack your most important widgets. In addition, Tkinter
scripts can create any number of independent windows, generated and
popped up on demand, by creating Toplevel
widget objects.
Each Toplevel
object created
produces a new window on the display and automatically adds it to the
program’s GUI event-loop processing stream (you don’t need to call the
mainloop
method of new windows to
activate them). Example 9-3
builds a root and two pop-up windows.
Example 9-3. PP3EGuiTour oplevel0.py
import sys from Tkinter import Toplevel, Button, Label win1 = Toplevel( ) # two independent windows win2 = Toplevel( ) # but part of same process Button(win1, text='Spam', command=sys.exit).pack( ) Button(win2, text='SPAM', command=sys.exit).pack( ) Label(text='Popups').pack() # on default Tk( ) root window win1.mainloop( )
The toplevel0
script gets a
root window by default (that’s what the Label
is attached to, since it doesn’t
specify a real parent), but it also creates two standalone Toplevel
windows that appear and function
independently of the root window, as seen in Figure 9-3.
The two Toplevel
windows on
the right are full-fledged windows; they can be independently
iconified, maximized, and so on. Toplevel
s are typically used to implement
multiple-window displays and pop-up modal and nonmodal dialogs (more
on dialogs in the next section). They stay up until they are
explicitly destroyed or until the application that created them
exits.
It’s important to know that although Toplevel
s are independently active windows,
they are not separate processes; if your program exits, all of its
windows are erased, including all Toplevel
windows it may have created. We’ll
learn how to work around this rule later by launching independent GUI
programs.
A Toplevel
is roughly like
a Frame
that is split off into
its own window, and has additional methods that allow you to deal
with top-level window properties. The Tk
widget is roughly like a Toplevel
, but it is used to represent the
application root window. We got one for free in Example 9-3 because the Label
had a default parent; in other
scripts, we’ve made the Tk
root
more explicit by creating it directly, like this:
root = Tk( ) Label(root, text='Popups').pack() # on explicit Tk( ) root window root.mainloop( )
In fact, because Tkinter GUIs are built as a hierarchy, you
always get a root window by default, whether it is named explicitly,
as here, or not. You should generally use the root to display
top-level information of some sort; if you don’t attach widgets to
the root, it shows up as an odd empty window when you run your
script. Technically, you can suppress the default root creation
logic and make multiple root windows with the Tk
widget, as in Example 9-4.
Example 9-4. PP3EGuiTour oplevel1.py
import Tkinter from Tkinter import Tk, Button Tkinter.NoDefaultRoot( ) win1 = Tk( ) # two independent root windows win2 = Tk( ) Button(win1, text='Spam', command=win1.destroy).pack( ) Button(win2, text='SPAM', command=win2.destroy).pack( ) win1.mainloop( )
When run, this script displays the two pop-up windows of the
screenshot in Figure 9-3
only (there is no third root window). But it’s more common to use
the Tk
root as a main window and
create Toplevel
widgets for an
application’s pop-up windows.
Both Tk
and
Toplevel
widgets export extra
methods and features tailored for their top-level role, as
illustrated in Example
9-5.
Example 9-5. PP3EGuiTour oplevel2.py
############################################################################# # pop up three new windows, with style # destroy() kills one window, quit( ) kills all windows and app; top-level # windows have title, icon, iconify/deiconify and protocol for wm events; # there always is an app root window, whether by default or created as an # explicit Tk( ) object; all top-level windows are containers, but never # packed/gridded; Toplevel is like frame, but new window, and can have menu; ############################################################################# from Tkinter import * root = Tk( ) # explicit root trees = [('The Larch!', 'light blue'), ('The Pine!', 'light green'), ('The Giant Redwood!', 'red')] for (tree, color) in trees: win = Toplevel(root) # new window win.title('Sing...') # set border win.protocol('WM_DELETE_WINDOW', lambda:0) # ignore close win.iconbitmap('py-blue-trans-out.ico') # not red Tk msg = Button(win, text=tree, command=win.destroy) # kills one win msg.pack(expand=YES, fill=BOTH) msg.config(padx=10, pady=10, bd=10, relief=RAISED) msg.config(bg='black', fg=color, font=('times', 30, 'bold italic')) root.title('Lumberjack demo') Label(root, text='Main window', width=30).pack( ) Button(root, text='Quit All', command=root.quit).pack( ) # kills all app root.mainloop( )
This program adds widgets to the Tk
root window, immediately pops up three
Toplevel
windows with attached
buttons, and uses special top-level protocols. When run, it
generates the scene captured in living black-and-white in Figure 9-4 (the buttons’ text
shows up blue, green, and red on a color display).
There are a few operational details worth noticing here, all of which are more obvious if you run this script on your machine:
protocol
Because the window manager close event has been
intercepted by this script using the top-level widget protocol
method, pressing the X in
the top-right corner doesn’t do anything in the three Toplevel
pop ups. The name string
WM_DELETE_WINDOW
identifies
the close operation. You can use this interface to disallow
closes apart from the widgets your script creates. The
function created by this script’s lambda:0
does nothing but return
zero.
destroy
Pressing the big black buttons in any one of the three
pop ups only kills that pop up, because the pop up runs the
widget destroy
method. The
other windows live on, much as you would expect of a pop-up
dialog window.
quit
To kill all the windows at once and end the GUI
application (really, its active mainloop
call), the root window’s
button runs the quit
method
instead. Pressing the root window’s button ends the
application.
title
As introduced in Chapter
8, top-level window widgets (Tk
and Toplevel
) have a title
method that lets you change
the text displayed on the top border. Here, the window title
text is set to the string 'Sing...'
to override the default
'tk'
.
iconbitmap
The iconbitmap
method
changes a top-level window’s icon. It accepts an icon or
bitmap file and uses it for the window’s icon graphic when it
is both minimized and open. On Windows, pass in the name of a
.ico file (this example uses one in the
current directory); it will replace the normal red “Tk” icon
that normally appears in the upper-lefthand corner of the
window as well as in the Windows taskbar.
Top-level windows are containers for other widgets, much
like a standalone Frame
.
Unlike frames, though, top-level window widgets are never
themselves packed (or gridded, or placed). To embed widgets,
this script passes its windows as parent arguments to label
and button constructors. It is also possible to fetch the
maximum window size (the physical screen display size, as a
[width, height] tuple) with the maxsize( )
method, as well as set
the initial size of a window with the top-level geometry("
widthh
x
height
+
x
+
y
")
method. It is generally
easier and more user-friendly to let Tkinter (or your users)
work out window size for you, but display size may be used for
tasks such as scaling images (see the discussion on PyPhoto in
Chapter 12 for an
example).
In addition, top-level window widgets support other kinds of protocols that we will utilize later on in this tour:
The iconify
and
withdraw
top-level window
object methods allow scripts to hide and erase a window on the
fly; deiconify
redraws a
hidden or erased window. The state
method queries or changes a window’s state;
valid states passed in or returned include iconic
, withdrawn
, zoomed
(full screen on Windows; use
geometry
elsewhere), and
normal
(large enough for
window content). The methods lift
and lower
raise and lower a window with
respect to its siblings (lift
is the Tk raise
command). See the alarm
scripts near the end of Chapter
10 for usage.
Each top-level window can have its own window
menus too; both the Tk
and the Toplevel
widgets have a menu
option used to associate a
horizontal menu bar of pull-down option lists. This menu bar
looks as it should on each platform on which your scripts are
run. We’ll explore menus early in Chapter 10.
Most top-level window-manager-related methods can also be
named with a “wm_” at the front; for instance, state
and protocol
can also be called wm_state
and wm_protocol
.
Notice that the script in Example 9-3 passes its Toplevel
constructor calls an explicit
parent widget—the Tk
root window
(that is, Toplevel(root)
).
Toplevel
s can be associated with
a parent just as other widgets can, even though they are not
visually embedded in their parents. I coded the script this way to
avoid what seems like an odd feature; if coded instead like
this:
win = Toplevel( ) # new window
and if no Tk
root yet
exists, this call actually generates a default Tk
root window to serve as the Toplevel
’s parent, just like any other
widget call without a parent argument. The problem is that this
makes the position of the following line crucial:
root = Tk( ) # explicit root
If this line shows up above the Toplevel
calls, it creates the single root
window as expected. But if you move this line below the Toplevel
calls, Tkinter creates a default
Tk
root window that is different
from the one created by the script’s explicit Tk
call. You wind up with two Tk
roots just as in Example 9-5. Move the Tk
call below the Toplevel
calls and rerun it to see what I
mean. You’ll get a fourth window that is completely empty! As a rule
of thumb, to avoid such oddities, make your Tk
root windows early on and make them
explicit.
All of the top-level protocol interfaces are available only on
top-level window widgets, but you can often access them by going
through other widgets’ master
attributes—links to the widget parents. For example, to set the
title of a window in which a frame is contained, say something like
this:
theframe.master.title('Spam demo') # master is the container window
Naturally, you should do so only if you’re sure that the frame will be used in only one kind of window. General-purpose attachable components coded as classes, for instance, should leave window property settings to their client applications.
Top-level widgets have additional tools, some of which we may
not meet in this book. For instance, under Unix window managers, you
can also set the name used on the window’s icon (iconname
). Because some icon options may
be useful when scripts run on Unix only, see other Tk and Tkinter
resources for more details on this topic. For now, the next
scheduled stop on this tour explores one of the more common uses of
top-level windows.
3.16.217.187