Inheriting from Frame or not in a Tkinter application
A Frame is usually used as a geometry master for other widgets.
Since an application usually has numerous widgets, you'll often want to contain them all in a Frame, or at least use the Frame to add some borderwidth
, padding, or other nicety.
Many example snippets you might find on the web do not use a Frame because they just want to demonstrate some feature in the shortest amount of code.
So, use a Frame if you need it, otherwise, do not.
Edit: I think the best way to organize a GUI is given in this Tkinter tutorial:
simpleApp.py:
import Tkinter as tk
class SimpleApp(object):
def __init__(self, master, **kwargs):
title=kwargs.pop('title')
frame=tk.Frame(master, **kwargs)
frame.pack()
self.label = tk.Label(frame, text=title)
self.label.pack(padx=10,pady=10)
if __name__=='__main__':
root = tk.Tk()
app = SimpleApp(root,title='Hello, world')
root.mainloop()
This is mainly like your first example in that SimpleApp
inherits from object
, not Frame
. I think this is better than subclassing Frame
since we are not overriding any Frame
methods. I prefer to think of SimpleApp
as having a Frame
rather than being a Frame
.
Having SimpleApp
subclass object
does have a significant advantage over subclassing tk.Tk
, however: it makes it easy to embed SimpleApp
in a larger app:
import simpleApp
import Tkinter as tk
class BigApp(object):
def __init__(self, master, **kwargs):
title=kwargs.pop('title')
frame=tk.Frame(master, **kwargs)
frame.pack()
self.simple = simpleApp.SimpleApp(frame,title=title)
frame.pack(padx=10, pady=10)
self.simple2 = simpleApp.SimpleApp(frame,title=title)
frame.pack()
if __name__=='__main__':
root = tk.Tk()
app = BigApp(root,title='Hello, world')
root.mainloop()
Thus, simpleApp.py can be a stand-alone script as well as an importable module.
If you try this with SimpleApp
inheriting from tk.Tk
, you end up with extra undesired windows.
The option I prefer* is to inherit from the class Tk. I think it is the more reasonable choice since the window is, in effect, your application. Inheriting from Frame
doesn't make any more sense to me then inheriting from Button
or Canvas
or Label
. Since you can only have a single root, it makes sense that that is what you inherit from.
I also think it makes the code more readable if you do the import as import Tkinter as tk
rather than from Tkinter import *
. All of your calls then explicitly mention the tk
module. I don't recommend this for all modules, but to me it makes sense with Tkinter.
For example:
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.label = tk.Label(text="Hello, world")
self.label.pack(padx=10, pady=10)
app = SampleApp()
app.mainloop()
* Note: since originally writing this answer I have changed my position. I now prefer to inherit from Frame
rather than Tk
. There's no real advantage one way or the other, it's more of a philosophical choice than anything else. Regardless, I believe that whether you inherit from Frame
or Tk
, I think either choice is better than the first example in the code that inherits from nothing.
The one slight advantage inheriting from Frame
has over Tk
is in the case where you want your application to support multiple identical windows. In that case, inheriting from Frame
lets you create the first window as a child of root, and additional windows as children of instances of Toplevel
. However, I've seen very few programs that ever have a need to do this.
For more information about how I think Tkinter programs should be structured, see my answer to the question Python Tkinter program structure.