1

I would like to filter dataset with a delay.

I have this basic layout:

import tkinter as tk
    
def filter(*args):
   print('entry callback', 'changed %s' % str(args))
   print('limit result set with', filter_input.get())

if __name__ == "__main__":
    master = tk.Tk()
    filter_input = tk.StringVar(value='')  # filter mode
    # filter_input.trace('w', filter)  # simple trace triggers immediately
    # filter_input.trace_variable('w', filter)  # trace_variable as well
    filter_input.trace_add('write', filter)  # trace_add should replace previous (deprecated)
    entry_field = tk.Entry(master, textvariable=filter_input)
    entry_field.pack()
    tk.mainloop()

I started with main Tkinter python page

I went through the main widget documentation

There are a bunch of more documentation around the globe, but I can't find anywhere any mention about a delay implemented. Can anyone help me to find out, if there is possible to call the filter function after some defined amount of time? Maybe another wrapper function could help?

EDIT:

It looks like I need to clear out the desired functionality. This is somehow what I am after but I need a delay instead of "user-stops-typing" activity.

Kube Kubow
  • 398
  • 1
  • 6
  • 18

1 Answers1

2

If you just want to call the function with a delay then use after(ms,func) to call the function after ms milliseconds. So your function could be like:

def filter(*args):
    # print(f'entry callback changed {str(args)}')
    print(f'limit result set with {filter_input.get()}')
    master.after(1000,filter) # Call this function every 1000 millisecond or 1 second

if __name__ == "__main__":
    master = tk.Tk()
    ....
    
    filter() # Call the function initially
    tk.mainloop()

So you can also get rid of StringVar here as you are using after() and nothing else. If you want to end this after() loop, then use after_cancel(id).

EDIT:

If you want to see the input with just a delay once each time the window is open, then try this:

first = True
def show():
    global first
    if first and entry_field.get():
        first = False
        master.after(3000,lambda: print(entry_field.get()))

if __name__ == "__main__":
    master = tk.Tk()

    ......
    entry_field.bind('<Key>',lambda e: show())    

EDIT 2: This will call the function also when the box is cleared and typed again:

first = True
def show():
    global first
    if entry_field.get():
        if first:
            first = False
            master.after(3000,lambda: print(entry_field.get()))
    else:
        first = True
Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
  • thank you, interesting option, but in my case it has to be running until the application exit. I would prefer to run only once - and with delay (if possible of course) – Kube Kubow Mar 23 '21 at 09:12
  • @KubeKubow This will keep running forever till the app is exited – Delrius Euphoria Mar 23 '21 at 09:14
  • yes, that is the point. I would like to avoid this approach. I prefer one-time trigger with a delay (if possible). – Kube Kubow Mar 23 '21 at 09:15
  • @KubeKubow What is the delay you prefer. – Delrius Euphoria Mar 23 '21 at 09:17
  • Type inside entry box -> wait some time (lets say 3 sec initially) -> trigger the filter function. If this is not possible, I can accept you answer and somehow adapt to it. – Kube Kubow Mar 23 '21 at 09:20
  • @KubeKubow Yes if you mean to just show the input ONCE ONLY for the entire span of your application, yes I will update the answer. – Delrius Euphoria Mar 23 '21 at 09:22
  • there is apparently a misunderstanding. The Entry box is for filtering the result set. Each time a user types a text, I want to trigger a filter function - but with a delay. – Kube Kubow Mar 23 '21 at 10:03
  • @KubeKubow and how would python know if the user has finished typing their word. – Delrius Euphoria Mar 23 '21 at 10:05
  • I want a delay after typing, as I wrote in the question. But that is the concept I am after. – Kube Kubow Mar 23 '21 at 10:16
  • @kubekubow Not sure how you are going to be able to identify if the user has finished typing. Only the user knows if they have finished typing. Unless I'd there is a button to notify the app. – Delrius Euphoria Mar 23 '21 at 10:32
  • 1
    No need to identify - I just want to trigger filter not as frequent as user types - and this completely solves it, thank you! – Kube Kubow Mar 23 '21 at 10:37
  • @KubeKubow - did you ever figure out how to add that delay of 'user stopped typing' activity? Im in need of a similar solution and so far have not had any success. [https://stackoverflow.com/q/71580494/8729576] – Salvatore Mar 24 '22 at 01:40