在线程中销毁Toplevel会锁定root

时间:2014-01-15 21:03:14

标签: python multithreading tkinter python-3.3 python-multithreading

我有一个我一直在编写的程序,它起初是一个帮助函数,可以根据该报告中的某些信息在共享驱动器上找到某个报告。我决定给它一个GUI,这样我就可以将它分发给其他员工,并且在我第一次尝试实现tkinterthreading时遇到了一些错误。

我知道古老的格言“我有一个问题,然后我使用了线程,现在我有两个问题。”至少,线程确实解决了第一个问题 - 所以现在到了第二个问题......

我的淡化代码是:

class GetReport(threading.Thread):
    def __init__(self,root):
        threading.Thread.__init__(self)

        # this is just a hack to get the StringVar in the new thread, HELP!
        self.date = root.getvar('date')
        self.store = root.getvar('store')
        self.report = root.getvar('report')
        # this is just a hack to get the StringVar in the new thread, HELP!

        self.top = Toplevel(root)
        ttk.Label(self.top,text="Fooing the Bars into Bazes").pack()
        self.top.withdraw()
    def run(self):
        self.top.deiconify()
        # a function call that takes a long time
        self.top.destroy() #this crashes the program

def main():
    root = Tk()
    date,store,report = StringVar(),StringVar(),StringVar()

    #####
    ## labels and Entries go here that define and modify those StringVar
    #####

    def launchThread(rpt):
        report.set(rpt)

        # this is just a hack to get the StringVar in the new thread, HELP!
        root.setvar('date',date.get())
        root.setvar('store',store.get())
        root.setvar('report',report.get())
        # this is just a hack to get the StringVar in the new thread, HELP!

        reportgetter = GetReport(root)
        reportgetter.start()

    ttk.Button(root,text="Lottery Summary",
                command=lambda: launchThread('L')).grid(row=1,column=3)

    root.mainloop()

我的预期输出是root打开并填充标签,条目和按钮(其中一些在此示例中隐藏)。每个按钮都会从条目中提取数据并将它们发送到launchThread函数,这将创建一个新线程来执行填充我需要的文书工作所需的元素和条形码。

该线程将启动Toplevel基本上只是通知用户它正在处理它。完成后,Toplevel将关闭,我请求的文书工作将打开(我使用ShellExecute打开.pdf),同时线程退出(因为它退出其run函数)

实际上发生的是该线程将启动其Toplevel,文书工作将打开,然后Python将变得无响应并需要“结束处理”。

2 个答案:

答案 0 :(得分:0)

据我所知,你不能使用线程来改变任何GUI元素。比如摧毁Toplevel窗口。

任何Tkinter代码都需要在程序的主循环中完成。

答案 1 :(得分:-1)

Tkinter无法接受来自主线程以外的线程的任何命令,因此在线程中启动TopLevel将失败,因为它无法访问其他线程中的Tk。要解决此问题,请使用.is_alive线程方法。

def GetReport(threading.Thread):
    def __init__(self,text):
        self.text = text
        super().__init__()

    def run(self):
        # do some stuff that takes a long time
        # to the text you're given as input

def main():
    root = Tk()
    text = StringVar()

    def callbackFunc(text):
        top = Toplevel(root)
        ttk.Label(top,text="I'm working here!").pack()
        thread = GetReport(text)
        thread.start()
        while thread.is_alive():
            root.update() # this keeps the GUI updating
        top.destroy() # only when thread dies.

    e_text = ttk.Entry(root,textvariable=text).pack()
    ttk.Button(root,text="Frobnicate!",
        command = lambda: callbackFunc(text.get())).pack()