我如何在我的tk UI中制作一个按钮,使程序在按下它时做大量的事情而不是冻结窗口



我刚刚开始使用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分钟后所有的处理完成后才从这个状态出来。我如何使它不冻结和更新状态文本?

是时候学习多线程了!

发生的事情是GUI(主线程)正在等待方法返回,以便它可以继续更新接口。

你想让按钮的动作产生一个threading.Thread,而不是在主线程中运行繁重的代码。你还需要创建一个Queue来访问其他线程的数据(因为发送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

如果您控制了do_lots_of_stuff,并且可以将其分成小块,则可以在事件队列上放置小作业来执行每个块。

例如,如果您的do_lots_of_stuff正在从文件中读取行,则创建一个方法,读取一行,然后在事件队列中放置一个作业,以便在一两毫秒后调用自己。通过这种方式,事件循环继续运行,代码在每次迭代中进行一些处理。这是一种令人惊讶的有效技术,尽管它只有在你能够将你的"许多东西"分解成原子块的情况下才有效。

如果你不能这样做,你将不得不使用多个线程或多个进程。我个人更喜欢后者——多处理代码编写和调试(可以说)更容易。

相关内容

  • 没有找到相关文章

最新更新