How do you run your own code alongside Tkinter's event loop? How do you run your own code alongside Tkinter's event loop? tkinter tkinter

How do you run your own code alongside Tkinter's event loop?


Use the after method on the Tk object:

from tkinter import *root = Tk()def task():    print("hello")    root.after(2000, task)  # reschedule event in 2 secondsroot.after(2000, task)root.mainloop()

Here's the declaration and documentation for the after method:

def after(self, ms, func=None, *args):    """Call function once after given time.    MS specifies the time in milliseconds. FUNC gives the    function which shall be called. Additional parameters    are given as parameters to the function call.  Return    identifier to cancel scheduling with after_cancel."""


The solution posted by Bjorn results in a "RuntimeError: Calling Tcl from different appartment" message on my computer (RedHat Enterprise 5, python 2.6.1). Bjorn might not have gotten this message, since, according to one place I checked, mishandling threading with Tkinter is unpredictable and platform-dependent.

The problem seems to be that app.start() counts as a reference to Tk, since app contains Tk elements. I fixed this by replacing app.start() with a self.start() inside __init__. I also made it so that all Tk references are either inside the function that calls mainloop() or are inside functions that are called by the function that calls mainloop() (this is apparently critical to avoid the "different apartment" error).

Finally, I added a protocol handler with a callback, since without this the program exits with an error when the Tk window is closed by the user.

The revised code is as follows:

# Run tkinter code in another threadimport tkinter as tkimport threadingclass App(threading.Thread):    def __init__(self):        threading.Thread.__init__(self)        self.start()    def callback(self):        self.root.quit()    def run(self):        self.root = tk.Tk()        self.root.protocol("WM_DELETE_WINDOW", self.callback)        label = tk.Label(self.root, text="Hello World")        label.pack()        self.root.mainloop()app = App()print('Now we can continue running code while mainloop runs!')for i in range(100000):    print(i)


When writing your own loop, as in the simulation (I assume), you need to call the update function which does what the mainloop does: updates the window with your changes, but you do it in your loop.

def task():   # do something   root.update()while 1:   task()