我刚开始使用Tk并在python中使用它。当你按下它时,我设置了一个按钮,在幕后做了很多(比如两分钟)的东西。我还设置了一个状态文本,以显示发生这种情况时发生了什么。我这样设置:
status_text = Tkinter.StringVar()
ttk.Button(mainframe, text="Stats!", command=go).grid(column=1, row=4)
def go(*args):
status_text.set("Logging in...")
do_lots_of_stuff()
status_text.set("Doing stuff #1...")
do_even_more_stuff()
status_text.set("Success!")
问题是,当您按下该按钮时,窗口会冻结,状态文本实际上永远不会更改。它看起来很破碎,并且直到2-3分钟后所有处理完成才会出现这种状态。如何使其不冻结并更新状态文本?
答案 0 :(得分:1)
是时候学习多线程了!
发生的事情是GUI(主线程)正在等待方法返回,以便它可以继续更新界面。
您需要使按钮的操作产生threading.Thread
,而不是在主线程中运行繁重的代码。您还需要创建一个队列来访问另一个线程中的数据(因为只能从主线程发送GUI请求)。
import threading, Queue #queue in 3.x
my_queue = Queue.Queue()
def go(*args):
my_thread = threading.Thread(target=function_that_does_stuff)
def function_that_does_stuff():
my_queue.put("Logging in...")
do_lots_of_stuff()
my_queue.put("Doing stuff #1...")
do_even_more_stuff()
my_queue.put("Success!")
然后你需要一个在更新事件发生时运行的函数。
def OnUpdate(*args):
try:
status_text.set(my_queue.get())
except Queue.Empty:
pass
答案 1 :(得分:1)
如果您可以控制do_lots_of_stuff
并且可以将其分成小块,则可以在事件队列上放置小作业来执行每个块。
例如,如果您do_lots_of_stuff
正在从文件中读取行,则创建一个读取一行的方法,然后将作业放在事件队列上,以便在一两个ms后调用自身。这样,事件循环继续运行,并且您的代码在每次迭代时都会进行一些处理。这是一种非常有效的技术,但它只有在你能够将你的“大量东西”分解成原子块时才有效。
如果你不能这样做,你将不得不使用多个线程或多个进程。我个人更喜欢后者 - 多处理代码(可以说)编写和调试的难度较小。