I'm using Tkinter to make an interactive Data Science App. I'm kinda new using Tkinter, so sorry if I don't use the correct technical language. There's a process where there´s heavy image processing. I also need a window which shows a progress bar of how the image processing is going. In particular, the image processing makes N things, and the window should show the progress bar, and text with n/N, percentage, and time passed. The process starts with a start button. It works at first, until some point where it just freezes. This is how my GUI class looks:
class progress_bar:
def __init__(self, parent, queue):
self.queue = queue
self.parent = parent
self.parent.geometry("300x100")
self.frame = tk.Frame(parent)
self.frame.pack()
self.progress = ttk.Progressbar(self.frame, orient = tk.HORIZONTAL,
length = 250, mode = 'determinate')
self.startButton = tk.Button(self.frame, text="Start", command=self.update_bar)
self.label = tk.Label(self.frame, text="")
self.progress.pack(pady=15)
self.label.pack(pady=0)
self.startButton.pack(pady=5)
self.parent.eval('tk::PlaceWindow . center')
self.startButton.focus()
def update_bar(self):
self.queue.put(True)
time.sleep(4)
while True:
if not self.queue.empty():
returns = self.queue.get()
self.progress['value'] = int(100*(returns[0]/returns[1]))
self.label.config(text = f"{returns[0]}/{returns[1]} ({int(100*(returns[0]/returns[1]))}%)"+" Time: "+
str(int(returns[2]/3600))+" hrs "+ str(int(int(returns[2]/60)%60))+" min "+str(int(returns[2]%60))+" s")
self.frame.update_idletasks()
if returns[0] == returns[1]:
break
time.sleep(0.8)
self.parent.destroy()
Because of the heavy image processing, I create a new proccess with multiprocessing.Process and the stats of that process are brought back for the GUI through a Queue. In fact, that Queue is given to the progress_bar object when created and brought from the child process (image processing) to update the progress bar window. To run the code I have something like this:
if __name__ == '__main__':
... some stuff ...
progress_queue = Queue()
process = Process(target=image_processing_function, args=its_args)
process.start()
root = tk.Tk()
window = progress_bar(root, progress_queue)
root.mainloop()
It works fine at first, but reaching 2% of progress, it freezes. The image processing running on the other core keeps running perfectly, it's just tkinter that freezes.
The image processing function is actually on another python script called "mark_finder.py", so I just import it in the main script with "import mark_finder.py as mf" and then just use the function (called "create_path_df") in the multiprocessing.Process like "Process(target=mf.create_path_df, args=its_args). This function is recursive and does the following:
event_cnt = 0
exe_time = 0
first_call = True
def create_path_df(source_path, df_paths, progress_queue, verbose_events):
global first_call
while first_call and progress_queue.empty():
pass
if first_call and progress_queue.get():
first_call =False
global event_cnt
global exe_time
.... stuff...
# base case:
... stuff ...
progress_queue.put([event_cnt, verbose_events, exe_time])
... stuff...
# recursive case:
... stuff ...
somewhere here I make my recursive call
... more stuff ...
It works perfectly for a while, but then Tkinter just freezes, and the second process keeps running perfectly. Looking at the task manager, the tkinter script uses between 5% and 7% of the CPU and the image processing process uses between 10% and 15% of the CPU. My CPU is an AMD Ryzen 7 3700X 8-Core Processor.