Tkinter GUI中的多线程,不同类中的线程

7
我是一名有用的助手,可以为您进行文本翻译。
我目前正在学习Tkinter GUI编程。我在多线程概念中卡住了。尽管这个主题在这里已经讨论了几次,但我仍然无法理解并将其应用到我的小样例程序中。
下面是我的代码:
from PIL import Image, ImageTk 
from Tkinter import Tk, Label, BOTH
from ttk import Frame, Style
from Tkinter import *
import time


class Widgets(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.grid()
        self.parent = parent
        self.initUI(parent)

    def initUI(self, parent):
        self.parent.title("Count Numbers")

        for r in range(10):
            self.parent.rowconfigure(r, weight=1)    
        for c in range(10):
            self.parent.columnconfigure(c, weight=1)        

        self.button1 = Button(parent, text = "count")
        self.button1.grid(row = 1, column = 1, rowspan = 1, columnspan = 2, sticky = W+E+N+S )
        self.button1["command"] = self.countNum

        self.button2 = Button(parent, text = "say Hello")
        self.button2.grid(row = 1, column = 7, rowspan = 1, columnspan = 2, sticky = W+E+N+S) 
        self.button2["command"] = PrintHello(self).helloPrint

    def countNum(self):
        for i in range(10):
            print i
            time.sleep(2)   

class PrintHello(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.grid()
        self.parent = parent

    def helloPrint(self):
        print "Hello"

def main():
    root = Tk()
    root.geometry("300x200")
    app = Widgets(root)
    root.mainloop()

if __name__ == '__main__':
    main() 

enter image description here

输出是一个带有2个按钮的GUI界面-第一个按钮打印数字,第二个按钮打印“Hello”。但是在单击第一个按钮时,GUI会冻结,同时数字正在被打印。在寻找解决方法时,我发现“多线程”可能有所帮助。但是经过多次尝试,我无法将多线程应用于我的示例程序中。
2个回答

7
Pythonista的回答非常好。但我想补充一些额外的观点。 GUI是事件驱动的。它们在循环中处理事件,不时地调用您的代码块(称为回调)。因此,您的代码或多或少是事件循环中的客人。正如您所注意到的,您的代码块应该快速完成,否则它们会阻塞事件处理,使GUI无响应。这是与教程中经常看到的线性程序完全不同的编程模型。要执行更长时间的计算或任务,您可以将它们拆分成小块并使用after。或者您可以在另一个进程中执行它们,并使用after定期检查它们是否已完成。
以下观点源于正确使用多线程非常困难的事实。 CPython(使用最广泛的Python实现)具有所谓的全局解释器锁。这确保只有一个线程可以同时执行Python字节码。当其他线程正在忙于执行Python字节码时,运行GUI的线程什么也不做。因此,多线程不能完全解决GUI无响应的问题。
许多GUI工具包都不是线程安全的,tkinter也不例外。这意味着您只应从运行mainloop的线程中进行tkinter调用。(在Python 3.x中,tkinter已变得线程安全。)

7

对于这么简单的事情,您不需要使用线程。

GUI 冻结是因为您在函数内部使用了 time.sleep,它会阻塞主线程直到完成。

只需使用 Tk 的内置 after 方法。将您的函数更改为:

def countNum(self, num=0):
    if num < 10:
        print num
        root.after(2000, lambda: self.countNum(num + 1))
    else:
        print "Stopping after call"
after方法接受以下参数:
after(delay_ms, callback, arguments)

时间单位为毫秒,1000 毫秒 = 1 秒。因此,我们将传递2000毫秒以实现2秒的延迟。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接