我目前正在学习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()
输出是带有2个按钮的GUI-首先打印数字,然后打印第二个" Hello"。但是在单击第一个按钮时,GUI会在数字打印时冻结。在寻找解决方案时,我发现了多线程'可能有帮助。但经过多次尝试,我无法对我的示例程序应用多线程。
答案 0 :(得分:6)
你不需要为这么简单的东西进行线程化。
GUI处于冻结状态,因为您正在阻止主线程的函数内部放置time.sleep
,直到它完成。
只需使用内置after
方法的Tk即可。将您的功能更改为。
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秒。因此,我们传递2,000毫秒,延迟2秒。
答案 1 :(得分:4)
Pythonista的答案很棒。但是我想谈谈其他一些观点。
after
。或者你可以使用multiprocessing
在另一个进程中对他们进行处理。但是,如果他们已经完成,您仍然需要定期检查(再次使用after
)。以下几点源于正确执行多线程的事实 hard 。
CPython(最常用的Python实现)具有所谓的全局解释器锁。这确保了一次只有一个线程可以执行Python字节码。当其他线程忙于执行Python字节码时,运行GUI的线程什么都不做。 因此,多线程不能解决无响应的GUI问题。
许多GUI工具包都不是线程安全的,而tkinter也不例外。这意味着您应仅从运行mainloop
的线程中进行tkinter调用。