Recently, I got stuck with very new problem (for me) of updating GUI in Tkinter when long processes are needed to be run (like running a time-consuming loop, waiting for a process to complete and return or fetching something from URL). Actually, for processes requiring a long time to complete, the Tkinter blocks other GUI events. Because of it, updates to GUI element only happen when the process returns after completing execution.
I earlier didn’t know about the ‘thread safe’ property of python Tkinter. The main caveat here is that we can’t update GUI elements from multiple threads. Once main thread initiates the mainloop(), we can never use other thread to update the GUI. However, we can easily do background processes in other threads. But, here also we need to invoke a GUI function whenever the process in the background thread stops and returns the result. But, a GUI function can only be invoked through the thread executing mainloop().
Therefore, after reading some online resources on StackOverflow and other Python blogs, I came to know about one design pattern followed to solve this problem. Instead of invoking a GUI function, whenever the result is returned we need to maintain a shared queue. The contents of queue will be shared between the thread executing mainloop() and the thread running the background process. Whenever we need to return the result after the process ends in the background thread, we need to put the result in the queue. On the other side, the thread ( executing mainloop() ) needs to periodically check the contents of the shared queue. In my case, I couldn’t understand this concept of ‘shared queue’ just by reading about it. Therefore, let’s go through a small piece of code to understand it better.
After result is produced put it in queue
result = 0
for i in range(10000000):
#Do something with result
####### Do something ######
self.myframe = tk.Frame(self)
self.myframe.grid(row=0, column=0, sticky='nswe')
self.mylabel = tk.Label(self.myframe) # Element to be updated
self.mybutton = tk.Button(
Spawn a new thread for running long loops in background
self.thread_queue = queue.Queue()
self.new_thread = threading.Thread(
Check if there is something in the queue
self.res = self.thread_queue.get(0)
if __name__ == "__main__":
root = tk.Tk()
main_app = MainApp(root)
Here, we may need to disable the button, because it may happen that clicking mybutton may result in creating multiple new threads.