在后台运行另一个类的函数

时间:2015-02-12 10:29:01

标签: python multithreading tkinter

我有一个工人阶级

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 ... 启动线程时

1 个答案:

答案 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冻结的另一种方法,而不是修复现有算法的方法。