简体   繁体   English

替代 Time.Sleep() 暂停 function

[英]Alternative To Time.Sleep() for pausing a function

I created an example code because my original is too big and has private information(My own) in it.我创建了一个示例代码,因为我的原始代码太大并且其中包含私人信息(我自己的)。

While running a program from a Tkinter GUI, it runs the program but makes the GUI unresponsive because of time.sleep() blocking the GUI from updating.从 Tkinter GUI 运行程序时,它运行该程序但由于 time.sleep() 阻止 GUI 更新而使 GUI 无响应。

I am trying to avoid using timers because it fires a different function after a duration instead of simply pausing the function and then continuing the same function.我试图避免使用计时器,因为它会在一段时间后触发不同的 function,而不是简单地暂停 function,然后继续相同的 function。

Is there an alternative that does not block the GUI but still adds a delay inside of the function?有没有不阻止 GUI 但仍然在 function 内部增加延迟的替代方案?

Example Code:示例代码:

from tkinter import *
import time

wn = Tk()
wn.geometry("400x300")
MyLabel = Label(wn, text="This is a Status Bar")
MyLabel.pack()

def MyFunction():
    Value = 1
    while Value < 10:
        print("Do something")
        time.sleep(1) **# - here blocks everything outside of the function**
        MyLabel.config(text=Value)
        # A lot more code is under here so I cannot use a timer that fires a new function
    Value = 1

MyButton = Button(wn, text="Run Program", command=MyFunction)
MyButton.pack()

wn.mainloop()

Edit: Thanks so much, you're answers were fast and helpful, I changed the code and added "wn.mainloop()" after the delay and replaced "time.sleep(1)" with wn.after(100, wn.after(10, MyLabel.config(text=Value))编辑:非常感谢,您的回答很快而且很有帮助,我更改了代码并在延迟后添加了“wn.mainloop()”,并将“time.sleep(1)”替换为 wn.after(100, wn.之后(10,MyLabel.config(文本=值))

here is the final code:这是最终代码:

from tkinter import *
import time

wn = Tk()
wn.geometry("400x300")
MyLabel = Label(wn, text="This is a Status Bar")
MyLabel.pack()

def MyFunction():
    Value = 0
    while Value < 10:
        print("Do something")
        wn.after(10, MyLabel.config(text=Value))
        Value += 1
    wn.mainloop()

MyButton = Button(wn, text="Run Program", command=MyFunction)
MyButton.pack()

wn.mainloop()

The short answer is that you can use wn.after() to request a callback after a certain amount of time.简短的回答是您可以使用wn.after()在一定时间后请求回调。 That's how you handle it.你就是这样处理的。 You get a timer tick at a one-per-second rate, and you have enough state information to let you proceed to the next state, then you go back to the main loop.您以每秒一次的速率获得计时器滴答声,并且您有足够的 state 信息让您继续执行下一个 state,然后您 go 返回主循环。

Put another way, timers are exactly how you have to solve this problem.换句话说,定时器正是解决这个问题的方法。

Fundamentally, any callback function in Tkinter runs in the main GUI thread, and so the GUI thread will block until the function exits.从根本上说,Tkinter 中的任何回调 function 都在主 GUI 线程中运行,因此 GUI 线程将阻塞,直到 function 退出。 Thus you cannot add a delay inside the function without causing the GUI thread to be delayed.因此,您不能在不导致 GUI 线程延迟的情况下在 function 中添加延迟。

There are two ways to solve this.有两种方法可以解决这个问题。 One would be to refactor your function into multiple pieces so that it can schedule the remaining work (in a separate function) via .after .一种方法是将您的 function 重构为多个部分,以便它可以通过.after安排剩余的工作(在单独的函数中)。 This has the advantage of ensuring that all of your functions are running in the main thread, so you can perform GUI operations directly.这样做的好处是确保你的所有功能都在主线程中运行,因此你可以直接执行 GUI 操作。

The other way is to run your function in a separate thread that is kicked off whenever your main callback is executed.另一种方法是在一个单独的线程中运行 function,只要执行主回调,该线程就会启动。 This lets you keep all the logic inside the one function, but it can no longer perform GUI operations directly - instead, any GUI operations would have to go through an event queue that you manage from the main thread.这使您可以将所有逻辑保留在一个 function 中,但它不能再直接执行 GUI 操作 - 相反,任何 GUI 操作都必须通过您从主线程管理的事件队列 go。

You can combine after() and wait_variable() to simulate time.sleep() without blocking tkinter from handling pending events and updates:您可以组合after()wait_variable()来模拟 time.sleep( time.sleep()而不会阻止 tkinter 处理未决事件和更新:

def tk_sleep(delay):
    v = wn.IntVar()
    # update variable "delay" ms later
    wn.after(delay, v.set, 0)
    # wait for update of variable
    wn.wait_variable(v)

Using tk_sleep() in your while loop:在 while 循环中使用tk_sleep()

def MyFunction():
    Value = 1
    while Value < 10:
        print("Do something")
        tk_sleep(1000) # waits for one second
        MyLabel.config(text=Value)
        # A lot more code is under here so I cannot use a timer that fires a new function
        Value += 1

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

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