繁体   English   中英

如何在我的 tk UI 中创建一个按钮,使程序在按下时执行大量操作而不冻结 window?

[英]How do I make a button in my tk UI that makes the program do a whole ton of stuff when it is pressed not freeze the window?

我刚刚开始使用 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!")

问题在于,当您按下该按钮时,window 会冻结,并且状态文本实际上从未改变。 它看起来坏了,直到所有处理完成 2-3 分钟后才从 state 中出来。 如何使它不冻结并更新状态文本?

是时候学习多线程了!

发生的事情是 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!")

然后你需要一个在更新事件发生时运行的 function。

def OnUpdate(*args):
    try:
        status_text.set(my_queue.get())
    except Queue.Empty:
        pass

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

例如,如果您do_lots_of_stuff正在从文件中读取行,请创建一个读取一行的方法,然后将作业放入事件队列中,以便在一两毫秒后调用自身。 这样事件循环将继续运行,并且您的代码在每次迭代时都会进行一些处理。 这是一种令人惊讶的有效技术,尽管它只有在您能够将“很多东西”分解成原子块时才有效。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM