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)