I have an entry in tkinter application in Python. If user changes the entry content, program reacts via onValidate
function.
Now I would like to select all text in the entry field, if user has not pressed any keys for a while.
Below I have tried to select_all_text
after 1000
ms using after
function, but it seems not to work.
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()
Also the timer should reset each time a new key is pressed, so that select_all_text
is called only after a long enough time has elapsed since last key press. In the example below select_all_text
is called after each key press, which is not desired behavior.
I was thinking that could one track the time since last key press, and if it exceeds a certain threshold, then function would be called. That kind of method would also solve the problem.
How to call a function if a long enough time has elapsed since last key press in tkinter?
When you keep a reference to the id that after
returns, you can cancel it with after_cancel
. With this, you can cancel the scheduled function and reschedule it on every keypress:
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
Note that I also saved the root window that you pass as the argument to MyEntry
in self.parent
and used that to call after
on.
P.S. You don't really need the Entry's validatecommand
command to do this (but you could if you already use the validatecommand
anyway of course). You can bind the function to every keypress:
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)