【问题标题】:How to use the after method to make a callback run periodically?如何使用 after 方法使回调定期运行?
【发布时间】:2023-03-06 09:07:02
【问题描述】:

使用 tkinter,如何使用after 方法使函数定期运行?

例如,我有一个 speak 函数,它只在控制台中打印一些东西:

def speak():
    print("Hello, world!")

如何使用after方法每秒调用speak函数?

【问题讨论】:

  • 此问题旨在规范与 tkinter 中的 after 方法相关的问题。请检查以下随附的答案。与该主题相关的几乎不规范的问题示例:How to use Tkinter after() method?tkinter: how to use after method
  • 这个问题已经被问过很多次了。与其创建一个新问题,不如将现有答案之一编辑为更规范?
  • @BryanOakley 好吧,我想这样做,但问题不是很规范,而且通常与一个精确的问题有关,它不会被用于编辑。所以,我决定写一个简单的问题。

标签: python tkinter


【解决方案1】:

注意:以下代码是在 Python 3.5 中编写和测试的。例如,在调用super 时,可能需要进行一些小的更改。

documentationWidget.after 方法的描述如下:

after(delay_ms, callback=None, *args)

注册一个在给定时间后调用的警报回调。


调度函数

after 方法主要用于在给定延迟后安排函数调用。例如,以下代码安排在一秒后调用函数:

import tkinter as tk

def speak():
    print("Hello world!")

root = tk.Tk()
root.after(1000, speak)

# Output
Hello world!

使函数定期运行

为了使函数定期运行,可以让它在自己的主体末尾调用自己。但是,after 是来自Widget 类的方法,因此需要一个小部件。因此,最好的选择通常是将调度函数放在扩展 Widget 的类中。

以下代码在控制台中每隔一秒打印一次"Hello world!"

import tkinter as tk

class Foo(tk.Tk):
    def periodically_speak(self):
        print("Hello world!")
        self.after(2000, self.periodically_speak)

foo = Foo()
foo.periodically_speak()

使用参数

可能希望将参数传递给定期运行的方法。为此,after 方法将回调后的每个参数解包为要传递给回调的参数。例如,root.after(1000, foo, a, b, c) 将安排对foo(a, b, c) 的呼叫。下面的例子展示了如何使用这个特性来确定函数的行为。

import tkinter as tk

class Foo(tk.Tk):
    def periodically_speak(self, text):
        print(text)
        self.after(2000, self.periodically_speak, text)

foo = Foo()
foo.periodically_speak("Good night world!")

取消通话

after 方法返回一个字符串,对应于调用的 id。可以将其传递给after_cancel 方法,以取消已安排的调用。

以下示例将开始每秒打印"Hello world!",但在按下按钮时将停止。

import tkinter as tk

class Foo(tk.Tk):
    def __init__(self):
        super().__init__()
        self.callId = None
        self.button = tk.Button(self, text="Stop", command=self.stop)
        self.button.pack()

    def periodically_speak(self):
        print("Hello world!")
        self.callId = self.after(2000, self.periodically_speak)

    def stop(self):
        if self.callId is not None:
            self.after_cancel(self.callId)

foo = Foo()
foo.periodically_speak()

旁注

应牢记以下几点。

  • after 方法不保证回调将在给定延迟之后*准确*被调用,但*至少*在它之后。因此,after 不应用于需要精度的地方。
  • 使用time.sleep 来安排或定期运行函数可能很诱人。在 GUI 上工作时必须避免这种情况,因为 `sleep` 会暂停当前线程,大部分时间都是主线程。例如,这可能会停止小部件的刷新,程序将停止响应。

【讨论】:

  • 您的第一个答案不是很规范。当 lambda 是不必要的并且可能具有误导性时,您正在使用 lambda。初学者可能会抓住第一个例子并认为这就是你应该使用after的方式。
  • @BryanOakley 公平点。我们SO Python chat room 中的一些熟悉 Tkinter 的人打算在接下来的几天内查看这对 Q+A 并提出建设性的批评以使其达到新的水平。
  • @BryanOakley 你说得对,我编辑了这一点。正如 PM 2Ring 所说,请随时编辑这篇文章,我只是希望这对您有所帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多