Python: Tkinter: Why is it root.mainloop() and not app.mainloop() Python: Tkinter: Why is it root.mainloop() and not app.mainloop() tkinter tkinter

Python: Tkinter: Why is it root.mainloop() and not app.mainloop()


I'm not sure if you'll find this answer satisfying, but you call root.mainloop() because root is the object that has the mainloop method. In the code you've given, App has no mainloop function.

In simpler terms, this is just how tkinter works -- you always end your script by calling the mainloop method of the root window. When that method returns, your program will exit.

Let's start at the beginning. The simplest, non-OO Tkinter program is going to look like the following example. Note that this is a python 2.x example, and I do not use a global import since I think global imports are bad.

import Tkinter as tkroot = tk.Tk()<your widgets go here>root.mainloop()

Many people find that a pure procedural style is not an effective way to write code, so they might choose to write this in an object-oriented style. It's natural to think of "the app" as a singleton object. There are many ways to do this -- the one in your question is, unfortunately, not one of the clearer ways to do it.

A slightly better way, IMO, would be to structure the code like this:

class App(tk.Tk):    def __init__(self, *args, **kwargs):        tk.Tk.__init__(self, *args, **kwargs)        <your widgets go here>app = App()app.mainloop()

In this case, mainloop is still being called, though now it's a method of App since App inherits from Tk. It is conceptually the same as root.mainloop() since in this case, app is the root window even though it goes by a different name.

So, in both cases, mainloop is a method that belongs to the root window. And in both cases, it must be called for the GUI to function properly.

There is a third variation which is what the code you picked is using. And with this variation, there are several ways to implement it. The variation is your question uses a class to define the GUI, but does not inherit from Tk. This is perfectly fine, but you still must call mainloop at some point. Since you don't create (or inherit) a mainloop function in your class, you must call the one associated with the root window. The variations I speak of are how and where the instance of App is added to the root window, and how mainloop is ultimately called.

Personally I prefer that App inherits from Frame, and that you pack the app outside the definition of the app. The template I use looks like this:

class App(tk.Frame):    def __init__(self, *args, **kwargs):        tk.Frame.__init__(self, *args, **kwargs)        <your widgets go here>if __name__ == "__main__":    root = tk.Tk()    app = App(root)    app.pack(fill="both", expand=True)    root.mainloop()

In this final example, app and root are two completely different objects. app represents a frame that exists inside the root window. Frames are commonly used this way, as a container for groups of other widgets.

So, in all cases, mainloop must be called. where it is called, and how, depends a bit on your coding style. Some people prefer to inherit from the root window, some don't. In either case, you must call the mainloop function of the root window.


I tested both like you see:

One is written with "app." + ".pack()" and one calls "mainframe." + ".grid()"

 #-*- coding: utf-8 -*-#THIS IS THE "MAINFRAME." - PARTfrom Tkinter import *import ttkdef show():    p = password.get() #get password from entry    print(p)root = Tk()root.title("Ingos first program")mainframe = ttk.Frame(root, padding="30 30 60 12")mainframe.grid(column=0, row=0, sticky=(N, W, E, S))mainframe.columnconfigure(0, weight=1)mainframe.rowconfigure(0, weight=1)password = StringVar() #Password variablepassEntry = Entry(mainframe, textvariable=password, show='*').grid(column=3, row=3, sticky=S)submit = Button(mainframe, text='Show Console',command=show).grid(column=3, row=4, sticky=S)root.mainloop()def show():    p = password.get() #get password from entry    print(p)#THIS IS THE "APP."-PART. BOTH WORKS FINE.app = Tk()app.title("Ingos first program")password = StringVar() #Password variablepassEntry = Entry(app, textvariable=password, show='#').pack()submit = Button(app, text='Show Console',command=show).pack()app.mainloop()

This instance works fine with python 2.7. In that test even app. can handle "mainloop()"That script opens 2 windows, one after another (if you close the first one) and the first programm is formatted, didn't tryed to write the colum=3... stuff in the pack() clamps.

I still started the Tkinter so don't fight me, just trying.. Hope I could help to answer your question.All the best, Ingo


The App object is just your app code, and the reason you call App(root) is to make an instance with your class, which then has access to your root window.

It receives this reference in the __init__ method:

def __init__(self, master):    # master refers to the root window now    ...

You can see the entire definition of the App object (given by the block beginning with class App:), and it doesn't even have a mainloop method, so to start the main Tkinter loop, you have to call it on the root window.

In the example in the Python2 documentation, they do call it as you suspected should be done, but note that their example class subclasses the Tk object Frame. In your example code, App is an old-style class that doesn't inherit anything.