Reputation: 93
I have a tkinter application that searches through a list of about 100000 wordlist when user types into the Entry widget (using trace with write callback to capture change in Entry variable).
I want to implement sort of a delay in order to NOT invoke the trace callback (to search the entire 100k wordlist) at EVERY keystroke (as the user might still be typing and it can become rather jerky/slow to invoke the callback function for each keystroke), rather I want to employ some sort of a min time to wait for additional input/keystroke AND/OR a max time since the first key was pressed BEFORE invoking the trace callback function.
I tried implementing a sleep but that is just a blocking call and does not achieve the desired affect. Here is some sample code where entering the string 'password' will invoke the callback (since this is literally just checking against the string 'password', it is super fast, yet in my app I loop over 100k word list for each keystroke which becomes slow). Thank You!
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
SUCCESS = 'Success.TLabel'
def __init__(self):
super().__init__()
self.title('Enter <password>')
self.geometry("200x120")
self.passwordVariable = tk.StringVar()
self.passwordVariable.trace('w', self.validate)
password_entry = ttk.Entry(
self, textvariable=self.passwordVariable) #, show='*'
password_entry.grid(column=0, row=1)
password_entry.focus()
self.message_label = ttk.Label(self)
self.message_label.grid(column=0, row=0)
def set_message(self, message, type=None):
self.message_label['text'] = message
if type:
self.message_label['style'] = type
def validate(self, *args):
confirm_password = self.passwordVariable.get()
if confirm_password == "password":
self.set_message(
"Success: The new password looks good!", self.SUCCESS)
return
if confirm_password.startswith("pas"):
self.set_message('Warning: Keep entering the password')
if __name__ == "__main__":
app = App()
app.mainloop()
Upvotes: 0
Views: 330
Reputation: 15098
I tried to understand what your current code does so I can implement the function here, but I've had no luck. Hopefully you being the author can implement this example onto your code.
The idea here is to schedule a callback to run after x seconds and if it is already scheduled, then cancel it. Sort of like a timer, if you think about it.
from tkinter import *
root = Tk()
SECONDS_TO_WAIT = 1
rep = None
def typing(*args):
global rep
if rep is None:
writing.config(text='Typing...')
else:
root.after_cancel(rep) # if already scheduled, then cancel it
rep = root.after(SECONDS_TO_WAIT*1000, caller)
def caller(*args):
global rep
writing.config(text='Not typing')
rep = None # Set it to None if `caller` GETS executed
var = StringVar()
entry = Entry(root,textvariable=var)
entry.pack(padx=10,pady=10)
entry.focus_force()
writing = Label(root,text='Not typing')
writing.pack()
var.trace('w',typing)
root.mainloop()
This will execute typing
each time the entry widget is edited/written to. And according to the conditions inside the function, caller
gets executed.
Upvotes: 1