I am trying to implement Multithreading while using a GUI in tkinter. I came along this solution, but i am failing to implement it.
So basically i need to know:
How do i need to alter my Code to make the Progressbar interact nice and smoothly, i.e. not going in unresponsive mode when the GUI loses focus?
This is my code boiled down:
from tkinter import *
import queue
import threading
from tkinter.ttk import *
class ThreadedTask(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
# Gui class
class MyGui(Frame):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.queue = queue.Queue()
self.init_ui()
# define a button to fulfill long task
def init_ui(self):
self.frame = Frame(self, relief=RAISED, borderwidth=1)
self.frame.grid(row=0, column=0, columnspan=1, sticky='ns')
self.status_frame = Frame(self, relief=RAISED, borderwidth=1, height=20)
self.status_frame.grid(row=1, column=0, columnspan=3, sticky='nesw')
self.status_frame.grid_configure(padx=3, pady=3)
self.button = Button(self.frame, text='do Stuff', command=self.do_stuff)
self.button.grid(padx=3, pady=3)
self.progress = Progressbar(self.status_frame, orient="horizontal", length=80, mode="determinate")
self.progress.grid(row=1, column=0, pady=3, sticky='nesw')
self.grid()
# start ThreadedTask here
def do_stuff(self):
ThreadedTask(self.queue).start()
self.queue_process(DoStuffClass(ui=self))
def queue_process(self, process, retry_time=10):
self.master.after(retry_time, process)
def update_status(self):
self.parent.update_idletasks()
class DoStuffClass:
def __init__(self, ui=None):
self.ui = ui
self.long_task()
def long_task(self):
# do stuff here and update the progressbar from MyGui
self.ui.progress['maximum'] = 10000
# some lengthy task ...
for i in range(10000):
print(i)
self.ui.progress.step()
self.ui.parent.update_idletasks()
# main
root = Tk()
root.geometry("150x80+50+50")
MyGui(root)
root.mainloop()
root.quit()
I think right now my problem is the wrong implementation of queues and Threading, i.e. self.queue_process(DoStuffClass(ui=self))
... the behaviour is the same as if i wouldn't use a queue and Multithread at all. The progressbar works, as long as it stays "in focus", which means me not clicking anything else on the desktop. As soon as i'm clicking elsewhere on the desktop and the GUI loses focus, the GUI goes in "unresponsive" mode and the progress bar does not update anymore. Also, sometimes Tcl closes the wrong Thread, which makes the whole program crash.