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

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

Im not sure if youll find this answer satisfying, but you call root.mainloop() because root is the object that has the mainloop method. In the code youve 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.

Lets 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 tk
root = 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. Its 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 its 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 dont 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 dont. 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. - PART
from Tkinter import *
import ttk

def 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 variable
passEntry = 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 variable
passEntry = 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, didnt tryed to write the colum=3… stuff in the pack() clamps.

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

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

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 doesnt 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 doesnt inherit anything.

Leave a Reply

Your email address will not be published. Required fields are marked *