自上次在 tkinter 中按下按键后经过一段时间后调用函数

Calling a function after time period has elapsed since last key press in tkinter

我在 Python 的 tkinter 应用程序中有一个条目。如果用户更改条目内容,程序将通过 onValidate 函数做出反应。

现在,如果用户有一段时间没有按下任何键,我想 select 输入字段中的所有文本。

下面我尝试使用 after 函数在 1000 毫秒后 select_all_text,但它似乎不起作用。

import tkinter as tk  

class MyEntry(tk.Frame):

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.vcmd = (self.register(self.onValidate),
                        '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')

        self.entry = tk.Entry(self, validate="key", validatecommand=self.vcmd)
        self.entry.pack(side="top", fill="x")

        self.select_all_text()

    def select_all_text(self):
        self.entry.focus()
        self.entry.select_range(0,'end')

    def onValidate(self, d, i, P, s, S, v, V, W):
        self.root.after(1000, self.select_all_text)

        return True

if __name__ == "__main__":
    root = tk.Tk()
    MyEntry(root).pack(fill="both", expand=True)

    root.mainloop()

此外,每次按下新键时计时器都应重置,这样 select_all_text 仅在自上次按键后经过足够长的时间后才会被调用。在下面的示例中,每次按键后都会调用 select_all_text,这不是我们想要的行为。

我在想是否可以跟踪自上次按键以来的时间,如果超过某个阈值,则会调用函数。这样的方法也能解决问题

如果自上次在 tkinter 中按下按键以来已经过去了足够长的时间,如何调用函数?

当您保留对 after returns 的 id 的引用时,您可以使用 after_cancel 取消它。有了这个,你可以取消预定的功能并在每次按键时重新安排它:

class MyEntry(tk.Frame):

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent
        self.after_id = None

        ...

    def onValidate(self, d, i, P, s, S, v, V, W):
        if self.after_id:
            self.parent.after_cancel(self.after_id)
        self.after_id = self.parent.after(1000, self.select_all_text)

        return True

请注意,我还在 self.parent 中保存了您作为参数传递给 MyEntry 的根 window,并使用它来调用 after


P.S。您实际上并不需要 Entry 的 validatecommand 命令来执行此操作(当然,如果您已经使用了 validatecommand,则可以)。您可以将函数绑定到每个按键:

class MyEntry(tk.Frame):

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent
        self.after_id = None

        self.entry = tk.Entry(self)
        self.entry.bind('<Key>', self.entry_keypress)

        ...

    def entry_keypress(self, e):
        print(self.after_id)
        if self.after_id:
            self.parent.after_cancel(self.after_id)
        self.after_id = self.parent.after(1000, self.select_all_text)