【问题标题】:Alternative To Time.Sleep() for pausing a functionTime.Sleep() 的替代方法用于暂停函数
【发布时间】:2022-02-15 17:47:14
【问题描述】:

我创建了一个示例代码,因为我的原件太大并且其中包含私人信息(我自己的)。

从 Tkinter GUI 运行程序时,它会运行该程序,但由于 time.sleep() 阻止 GUI 更新,因此导致 GUI 无响应。

我试图避免使用计时器,因为它会在一段时间后触发不同的函数,而不是简单地暂停函数然后继续执行相同的函数。

是否有不阻塞 GUI 但仍会在函数内部添加延迟的替代方法?

示例代码:

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()

编辑:非常感谢,您的回答快速而有帮助,我更改了代码并在延迟后添加了“wn.mainloop()”,并将“time.sleep(1)”替换为 wn.after(100 , wn.after(10, MyLabel.config(text=Value))

这是最终代码:

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()

【问题讨论】:

  • 为什么需要屏蔽 GUI?
  • 无法在函数中执行此操作 - 如果您不返回 Tkinter 的主循环,则 GUI 将被冻结。正确的解决方案是使用 .after()(带有 2 个以上参数的版本)来安排函数以供以后执行 - 是的,这确实需要与您的程序完全不同的结构。
  • 另一种方法是使用线程和事件队列模型,您的MyFunction 在单独的线程中运行。还可以选择在单独的线程中使用 async/await(和asyncio.sleep);请参阅stackoverflow.com/questions/49958180/… 获取食谱。
  • wn.after(10, MyLabel.config(text=Value) 不会像您认为的那样做。 wm.after(10, MyLabel.config(text=Value) 立即运行配置步骤。

标签: python tkinter time


【解决方案1】:

简短的回答是,您可以在一定时间后使用wn.after() 请求回调。你就是这样处理的。你会得到一个每秒一次的计时器滴答,你有足够的状态信息让你继续下一个状态,然后你回到主循环。

换句话说,计时器正是解决这个问题的方法。

【讨论】:

    【解决方案2】:

    从根本上说,Tkinter 中的任何回调函数都在主 GUI 线程中运行,因此 GUI 线程将阻塞直到函数退出。因此,您不能在函数内部添加延迟而不导致 GUI 线程延迟。

    有两种方法可以解决这个问题。一种是将您的函数重构为多个部分,以便它可以通过.after 安排剩余的工作(在单独的函数中)。这样做的好处是确保你的所有函数都在主线程中运行,因此你可以直接执行 GUI 操作。

    另一种方法是在一个单独的线程中运行你的函数,只要你的主回调被执行,这个线程就会被启动。这使您可以将所有逻辑保留在一个函数中,但它不能再直接执行 GUI 操作 - 相反,任何 GUI 操作都必须通过您从主线程管理的事件队列。

    【讨论】:

      【解决方案3】:

      您可以结合 after()wait_variable() 来模拟 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)
      

      在您的 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
      

      【讨论】:

        猜你喜欢
        • 2017-05-01
        • 2021-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多