Example 8-19 uses the prior example’s makeform and fetch functions to generate a form
and prints its contents, much as before. Here, though, the input fields are attached to
a new Toplevel pop-up window created on demand, and an OK button is added to the
new window to trigger a window destroy event that erases the pop up. As we learned
earlier, the wait_window call pauses until the destroy happens.
Example 8-19. PP4E\Gui\Tour\entry2-modal.py
make form dialog modal; must fetch before destroy with entries
from tkinter import *
from entry2 import makeform, fetch, fields
def show(entries, popup):
fetch(entries) # must fetch before window destroyed!
popup.destroy() # fails with msgs if stmt order is reversed
def ask():
popup = Toplevel() # show form in modal dialog window
ents = makeform(popup, fields)
Button(popup, text='OK', command=(lambda: show(ents, popup))).pack()
popup.grab_set()
popup.focus_set()
popup.wait_window() # wait for destroy here
root = Tk()
Button(root, text='Dialog', command=ask).pack()
root.mainloop()
When you run this code, pressing the button in this program’s main window creates
the blocking form input dialog in Figure 8-25, as expected.
But a subtle danger is lurking in this modal dialog code: because it fetches user inputs
from Entry widgets embedded in the popped-up display, it must fetch those inputs
before destroying the pop-up window in the OK press callback handler. It turns out
that a destroy call really does destroy all the child widgets of the window destroyed;
trying to fetch values from a destroyed Entry not only doesn’t work, but also generates
a traceback with error messages in the console window. Try reversing the statement
order in the show function to see for yourself.
Figure 8-24. entry2 (and entry3) expansion at work
Message and Entry | 453