Is it necessary to call Tk() when writing a GUI app with Tkinter?

Rick Johnson rantingrickjohnson at gmail.com
Thu Mar 1 21:35:44 EST 2012


On Feb 29, 10:41 pm, John Salerno <johnj... at gmail.com> wrote:
> I'm not sure I understand which method you are advocating. It
> sounded like you said calling Tk() explicitly is a bug.

I am saying just the opposite: Allowing the module "Tkinter" to
implicitly create a root window IF the programmer was too lazy to
create a root window himself is ridiculous, confusing, and
inconsistent; therefor it's a BUG! Observe:

INCORRECT:
 import Tkinter as tk
 b = tk.Button(master=None, text='Sloppy Coder')
 b.pack()
 b.mainloop()

CORRECT:
 import Tkinter as tk
 root = tk.Tk()
 b = tk.Button(root, text='Smart Coder')
 b.pack()
 root.mainloop()

IMO, only the widget "Tkinter.Tk" should have the method mainloop! If
you call w.mainloop() and "w" is NOT an instance of Tkinter.Tk, then
an error should be raised; I decided to raise a LazyCoderError in MY
version of the Tkinter module just to drive the point home.

> I certainly would never create widgets without first creating a
> master frame,

You really have no choice otherwise. Each and every widget requires a
parent argument (or parent=None, which will then create and use the
Tkinter._default_root; BUG!). The fact that Tkinter "magically"
creates the root window for you does not negate the fact that every
widget requires a parent. This is why i think the official version of
Tkinter is flawed. And the fix is very simple actually.

> but is creating a Frame object enough, or should I create a Tk
> object and *then* a Frame object?

No matter what, you MUST create an instance of Tkinter.Tk to be the
"root" window of your GUI application. After that, you can nest as
many frames, toplevels, and blah widgets under that root window as you
so desire. Actually you don't even need a "frame", you can pack
widgets directly into a Toplevel or Tk widget.

EXAMPLE 1: (this works, but is flawed!)
 root = tk.Tk()
 b = tk.Button(master=None, text='Sloppy Coder')
 b.pack()
 root.mainloop()

EXAMPLE 2: (This is how to write code!)
 root = tk.Tk()
 widgetframe = tk.Frame(root)
 b = tk.Button(master=None, text='Sloppy Coder')
 b.pack()
 root.mainloop()

EXAMPLE 3: (OOP style)
 class App(tk.Tk):
     def __init__(self):
         tk.Tk.__init__(self)
         # something should happen here to justify using OOP
     # or here

 class AppFrame(tk.Frame):
     def __init__(self, master, **kw):
         tk.Frame.__init__(self, master, **kw)
         self.createWidgets()

     def createWidgets(self):
         b = tk.Button(master=None, text='Push Me')
         b.pack()

 if __name__ == '__main__':
     app = App()
     frame = AppFrame(app)
     frame.pack()
     app.mainloop()


> Also, at what point do you include the destroy method in your
> program, assuming you do not have a widget that will close the
> window? If you only want the Windows "X" button to close the window,
> then is it okay to leave out any call to destroy()?

Yes. GUI destruction should (almost always) be controlled by the user.
In certain circumstances you will want to force destruction, or
intercept a users request for destruction so you can do something
first (cleanup, sanity checks, etc...).

> Or should always explicitly destroy it just as I explicitly created
> a Tk instance?

NO, you should create the root and then allow the user to decide when
to destroy the GUI. Always remember the phrase: "User Driven Events"
when coding a GUI!

> If the latter, then where in the code do you put the call to destroy
> so it won't conflict with the user closing the window with the X
> button?

In the "very special" cases where you need to destory the GUI, make
sure no code can run AFTER you destroy the root window. Whoever wrote
that example was obviously too lazy to run the code and check for
errors or subtle bugs.






More information about the Python-list mailing list