我有一个工人阶级
class Parser: #(threading.Thread)
...
def longTask(self,...)
...
return
...
一个窗口的类,它使用tkinter
class Window:
...
def startProcess(self,...):
p = Parser()
t= threading.Thread(target=p.longTask())
t.start()
return
...
但即使longTask()在一个单独的线程中运行,我的GUI也会冻结 - 为什么?
我的目标是在 longTask()运行时更新 Window 中的进度条。 longTask()在内部更新一个数字,范围从0到100。
问题:如何在 longTask()运行时完成此操作并阻止GUI冻结?
注意:当我调用 t.start()时,显然线程没有启动,但当我通过 t = threading.Thread ... 启动线程时
答案 0 :(得分:0)
虽然评论中的解决方案可能有效,但我发现在过去,线程确实不同意tkinter,后者拥有自己的虚拟事件管理器。我写了这个,这样如果你尝试的东西不起作用,你应该能够以这种方式实现它。
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()
当尝试让线程对象与tkinter对象交互时,它可以更好地使用某种可由两者使用的可变介质。由于增加加载条的步骤数可以改变,我使用了一个队列(它也是线程安全的)。每次发生事件时,函数都会在队列中放入步骤,并且tkinter应用程序有自己的循环,检查是否有任何新步骤,有效地调节线程和tkinter之间的交互。
这只是阻止GUI冻结的另一种方法,而不是修复现有算法的方法。