Reputation: 11
I'm writing my first GUI program with Tkinter (first program in Python too, actually).
I have an Entry widget for searching, and the results go to a Listbox. I want the results to update as the user types, so I made a callback like this:
search_field.bind("<KeyRelease>", update_results)
The problem is that updates the search many times in a row. Since the results will be coming from a database query, that generates a lot of unnecessary traffic. What I really want is for it to update every second or so, or to wait a second after the user stops typing and then search. What's the easiest way to do that? Thanks
UPDATE: That works great for what I described, but now I've realized that I also need to trigger an update after the user stops typing. Otherwise, the last few characters are never included in the search. I think I have to un-accept the answer in order for this to go back into the list of questions...
Upvotes: 1
Views: 291
Reputation: 2055
Figured it out. I call the decorated function with a delay using any_widget.after(delay_in_ms, function).
Upvotes: 0
Reputation: 107598
A nice way to do this is a simple caching decorator:
import time
def limit_rate( delay=1.0 ):
""" produces a decorator that will call a function only once per `delay` """
def wrapper( func ): # the actual decorator
cache = dict( next = 0 ) # cache the result and time
def limited( *args, **kwargs):
if time.time() > cache['next']: # is it time to call again
cache['result'] = func( *args, **kwargs) # do the function
cache['next'] = time.time() + delay # dont call before this time
return cache['result']
return limited
return wrapper
It works like this:
@limit_rate(1.5)
def test():
print "Called test()"
time.sleep( 1 )
return int(time.time())
print [test() for _ in range(5)] # test is called just once
You would simply add this decorator somewhere and decorate your update_results
function with it.
Upvotes: 3