Although the solution(s) in the comments may work, I've found that in the past, threading has really disagreed with tkinter, which has its own virtual event manager. I wrote this so that if what you have tried doesn't work, you should be able to implement it this way.
import tkinter
import tkinter.ttk
import threading
import queue
import time
def long(steps):
time.sleep(1)
for i in range(20):
steps.put(5)
time.sleep(0.2)
class Window:
def __init__(self):
self.steps = queue.Queue()
self.root = tkinter.Tk()
self.root.title("Loading")
self.progressbar = tkinter.ttk.Progressbar(self.root)
self.progressbar.pack(fill="both", padx=10, pady=10)
def update(self):
if self.progressbar["value"] == 100:
self.root.quit()
self.root.destroy()
elif not self.steps.empty():
step = self.steps.get()
self.progressbar["value"] += step # Not progressbar.step because it loops
self.root.after(100, self.update)
def main(self):
self.update()
self.root.mainloop()
window = Window()
t = threading.Thread(target=long, args=(window.steps,))
t.start()
window.main()
It works better, when trying to have threaded objects interact with tkinter objects, to use some sort of mutable medium that can be used by both. Since the number of steps to increase the loading bar by can change, I used a Queue (It's also thread safe). The functions puts steps in the Queue every time something happens and the tkinter app has its own loop that checks to see if there are any new steps, effectively moderating the interaction between the thread and tkinter.
This is simply another way to prevent the GUI from freezing, not a way to fix the existing algorithm.
p.longTask
instead ofp.longTask()
– Hans Then