On Feb 29, 6:17 pm, Terry Reedy <tjre...@udel.edu> wrote: > On 2/29/2012 9:24 AM, Rick Johnson wrote:
> > On Feb 28, 11:06 pm, John Salerno<johnj...@gmail.com> wrote: > >> However, in the Python documentation, I see this: > > >> root = Tk() > >> app = Application(master=root) > >> app.mainloop() > >> root.destroy() > >> I tried the above and I got the following error: > > >> Traceback (most recent call last): > >> File "C:\Users\John\Desktop\gui.py", line 12, in<module> > >> root.destroy() > >> File "C:\Python32\lib\tkinter\__init__.py", line 1714, in destroy > >> self.tk.call('destroy', self._w) > >> _tkinter.TclError: can't invoke "destroy" command: application has been > >> destroyed > > >> So apparently closing the window with the X button (on Windows) > > >> implicitly calls the destroy() method of the root frame. > >> If that's the case, why does the documentation explicitly call it? > > I do not know if tk has changed since the example was written or if it > was buggy from the beginning. I opened an issue to fix it. > > http://bugs.python.org/issue14163 "protocol" is ONLY a method of Tkinter.Tk and Tkinter.Toplevel. Actually Toplevel and Tk are exactly the same object but Tk has an TCL interpretor attached. Tkinter.Tk is meant to be the parent of ALL widgets within your Tkinter GUI. Tkinter.Frame is nothing more than a box to stuff widgets into. Tkinter.Frame IS NOT a window and therefor it DOES NOT have window methods. HOWEVER! Most people start falsely believing that a Tkinter.Frame AND Tkinter.Toplevel are the same thing; since Tkinter will "auto- magically" pack your frame into a default Tkinter.Tk window (psst: that's just a fancy Toplevel widget!) if you don't explicitly create the Tk instance yourself. >>>Slightly tangential meanderings This inconsistency also rears it's ugly head in the dialog modules: tkFileDialog and tkMessageBox. Both of which do not require a parent argument to their convenience functions. Instead they allow the parent to be OPTIONALLY passed. Inquisitive Ivan mused: """ What's wrong with that Rick, the dialog will still display whether a parent argument is passed or not. Heck, even if no viable parent exists, Tkinter will create one! Tkinter is a smart module!""" True Ivan. However, if you dig a little deeper you will see that the dialog created WITHOUT a parent does not function in a manner consistent to modal dialogs; that is, owning the focus and becoming a transient of another Toplevel window. Also, about your second point, noobs get confused when that default root window pops up. Then they come here and ask the same question over and over. Can't you see the design flaw that is directly in front of your face NOR smell the pungent odors that reeking from this module! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Some might argue that this implicit root window creation is beneficial for toy GUIs -- and i agree! HOWEVER, you will due enormous damage to a neophyte's learning process. I say just force the extra line of code and be consistent. Actually i believe SO strongly in "explicit root window creation" that i edited the source code of my Tkinter version to NOT allow ANY widget's master to be None. I had written a more exhaustive "expo-say" some time back but i cannot remember the title. > > Most applications will have both: user destroying, and program > > destroying. > > from tkMessageBox import askyesnocancel > > from tkinter.messagebox in 3.x Yes, Tkinter has changed a bit in Python>=3.0, thanks for pointing this out. > [...snip code...] > This works as adjusted for 3.x. I presume that a quit button or menu > entry should also call onDestroyWindow so the effect is the same as > clicking the outer [X] button. Yes, but i think the REAL problem is faulty code logic. Remove the last line "root.destroy()" and the problem is solved. Obviously the author does not have an in-depth knowledge of Tkinter. > I tried the same approach to fix the doc example, but unlike your class > App(Tk), class App(Frame) does not a .protocol attribute. See the > tracker issue for all my comments on the example. see above comments about Tkinter.Frame, Tkinter.Toplevel, and Tkinter.Tk ^^^ > I considered removing both the quit button and 'root.destroy' to get a > beginning example that works properly, but as you said, having both is > common so I would like both if the solution is not too esoteric. If you want to keep things simple, i would: 1. Create the root window explicitly! 2. Bind the command of the button to root.destroy (command=root.destroy) I would offer better advice if i could but i have no idea where this "book the OP is learning" is located? No one ever provided a link to the code in question? PS: I would highly suggest against using the "from Tkinter import *". Instead, use "import Tkinter as tk" and prefix all module contents with "tk.". Also, use "from Tkconstants import X, Y, X" -- http://mail.python.org/mailman/listinfo/python-list