Вызов функции после истечения периода времени с момента последнего нажатия клавиши в tkinter - PullRequest
0 голосов
/ 07 марта 2019

У меня есть запись в приложении tkinter на Python. Если пользователь изменяет содержимое записи, программа реагирует через функцию onValidate.

Теперь я хотел бы выделить весь текст в поле ввода, если пользователь какое-то время не нажимал никаких клавиш.

Ниже я попытался select_all_text после 1000 мс, используя функцию after, но, похоже, она не работает.

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 прошло достаточно много времени?

1 Ответ

2 голосов
/ 07 марта 2019

Когда вы сохраняете ссылку на идентификатор, который возвращает after, вы можете отменить его с помощью 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

Обратите внимание, что я также сохранил корневое окно, которое вы передаете в качестве аргумента MyEntry в self.parent, и использовал его для вызова after on.


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