[Python编程(第4版)].(Programming.Python.4th.Edition).Mark.Lutz.文字版

(yzsuai) #1

Other ways to be modal


Modal dialogs are typically implemented by waiting for a newly created pop-up win-
dow’s destroy event, as in this example. But other schemes are viable too. For example,
it’s possible to create dialog windows ahead of time, and show and hide them as needed
with the top-level window’s deiconify and withdraw methods (see the alarm scripts
near the end of Chapter 9 for details). Given that window creation speed is generally
fast enough as to appear instantaneous today, this is much less common than making
and destroying a window from scratch on each interaction.


It’s also possible to implement a modal state by waiting for a tkinter variable to change
its value, instead of waiting for a window to be destroyed. See this chapter’s later dis-
cussion of tkinter variables (which are class objects, not normal Python variables) and
the wait_variable method discussed near the end of Chapter 9 for more details. This
scheme allows a long-lived dialog box’s callback handler to signal a state change to a
waiting main program, without having to destroy the dialog box.


Finally, if you call the mainloop method recursively, the call won’t return until the widget
quit method has been invoked. The quit method terminates a mainloop call, and so
normally ends a GUI program. But it will simply exit a recursive mainloop level if one
is active. Because of this, modal dialogs can also be written without wait method calls
if you are careful. For instance, Example 8-14 works the same way as the modal mode
of dlg-custom.


Example 8-14. PP4E\Gui\Tour\dlg-recursive.py


from tkinter import *


def dialog():
win = Toplevel() # make a new window
Label(win, text='Hard drive reformatted!').pack() # add a few widgets
Button(win, text='OK', command=win.quit).pack() # set quit callback
win.protocol('WM_DELETE_WINDOW', win.quit) # quit on wm close too!


win.focus_set() # take over input focus,
win.grab_set() # disable other windows while I'm open,
win.mainloop() # and start a nested event loop to wait
win.destroy()
print('dialog exit')


root = Tk()
Button(root, text='popup', command=dialog).pack()
root.mainloop()


If you go this route, be sure to call quit rather than destroy in dialog callback handlers
(destroy doesn’t terminate the mainloop level), and be sure to use protocol to make the
window border close button call quit too (or else it won’t end the recursive mainloop
level call and may generate odd error messages when your program finally exits). Be-
cause of this extra complexity, you’re probably better off using wait_window or
wait_variable, not recursive mainloop calls.


442 | Chapter 8: A tkinter Tour, Part 1

Free download pdf