ZachR
ZachR

Reputation: 103

Tkinter code runs without mainloop, update, or after

I have been trying to use tkinter to make a gui to select some excel files and sheets from those files.

I have a lot of experience in python, but I'd probably say a novice at tkinter.

The code I have written to select the files is shown below (typos are likely because I cannot access the internet on the machine these files are on, so I am typing it up here).

My question is about mainloop(), the update functions, and after(). I had mainloop() at the end of my code, but my program wouldn't terminate (i.e. the terminal would remain) after it did what it does. So I removed the mainloop() and now it functions perfectly without any mainloop(), update(), or after() calls.

I don't really understand this and would really like to. I get that mainloop() stops the code from progressing until the root closes, but I thought nothing would show up without mainloop(), and this code does wait for the user to close the windows before continuing.

I was also wondering if I do not have mainloop (or the like), the code still closes fine whether or not I have root.destroy() at the end of the App class (commented in the code). I don't get that either.

This information would help me make better and correct code in the future and hopefully improve this one. FYI, I have searched for the answer to this everywhere and could not find one, at least one I could understand. Thanks a bunch.

This is as minimal as I can think of for this code.

Code (Edited from original post):

import tkinter as tk
from tkinter import ttk

class App:
    def __init__(self, parent):
        self.root = parent
        self.root.withdraw()

        tl = tk.Toplevel(parent)
        b = ttk.Button(tl, text="Test widget")
        b.grid()
        tl.wait_window()

        # This line does not change how the code functions at all
        #self.root.destroy()

    def run(self):
        # Whether or not this is a function in the class or called globally doesn't matter.
        self.root.mainloop()


if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)

    # This is the mainloop() call. If I include it, the program does not close after
    # running the code in App.__init__. Without it, it runs perfectly.
    # app.run()

Upvotes: 0

Views: 8359

Answers (1)

progmatico
progmatico

Reputation: 4964

mainloop enters an event listening loop for your tk.Tk() application.

You should create only one object with Tk() in every tkinter application.

Now this loop will "globally" listen for GUI events and will call your registered callbacks (event handlers). Code before the mainloop call will run but nothing will be shown or updated in the screen until you call it. No event (user input, mouse movement, keyboard and others) will be queued and responded to before that. But the widgets are created and configured, just not shown yet. If you call root.update() without ever entering the mainloop you will eventually see the window flash and disappear because everything is running, and you force window refresh, but then suddenly the program ends.

So configure your GUI and in the end always run root.mainloop()

Now when you call wait_window, you are creating a local event loop (and blocking the mainloop if it was running). For a perfect explanation of wait_window by Brian see here

What happened to you is that your app is happily running with your local event loop, but without mainloop. That would be a strange thing to do. Even if you are making as Brian explains, a modal window, you want to "return" to the mainloop after the window closes.

As for the after method it just registers a callback function to run after your choosen time, or after the mainloop becames idle, with after_idle (nothing more to refresh, no events in the queue..., also think as soon as possible). And if you want to re-run that function again in the same way it should re-register with after or after_idle before returning.

So always use your mainloop() ending call - or should I say event loop starting call :)

Edit:

Also, don't do things in your code that are slow, or that may block the loops, such as calling sleep or any other blocking function. That will freeze the GUI, until the block ends.

Upvotes: 1

Related Questions