Python Tkinter Autocomplete combobox with LIKE search? Python Tkinter Autocomplete combobox with LIKE search? tkinter tkinter

Python Tkinter Autocomplete combobox with LIKE search?


I suspect you need

 if self.get().lower() in element.lower():

instead of

 if element.lower().startswith(self.get().lower()):

to get data like with %LIKE% in database


But I don't know if you get good effect because this Combobox replaces text with suggestion so if you type be then it finds Cranberry and put in place be and you can't write ber.

Maybe you should display Cranberry as separated (dropdown) list, or popup tip.

Or maybe you will have to use string.find() to highlight correct place in Cranberry and continue to type ber in correct place.


EDIT: example how to use Entry and Listbox to display filtered list

In listbox_update I added sorting list (comparing lower case strings)

#!/usr/bin/env python3import tkinter as tkdef on_keyrelease(event):        # get text from entry    value = event.widget.get()    value = value.strip().lower()        # get data from test_list    if value == '':        data = test_list    else:        data = []        for item in test_list:            if value in item.lower():                data.append(item)                    # update data in listbox    listbox_update(data)        def listbox_update(data):    # delete previous data    listbox.delete(0, 'end')        # sorting data     data = sorted(data, key=str.lower)    # put new data    for item in data:        listbox.insert('end', item)def on_select(event):    # display element selected on list    print('(event) previous:', event.widget.get('active'))    print('(event)  current:', event.widget.get(event.widget.curselection()))    print('---')# --- main ---test_list = ('apple', 'banana', 'Cranberry', 'dogwood', 'alpha', 'Acorn', 'Anise', 'Strawberry' )root = tk.Tk()entry = tk.Entry(root)entry.pack()entry.bind('<KeyRelease>', on_keyrelease)listbox = tk.Listbox(root)listbox.pack()#listbox.bind('<Double-Button-1>', on_select)listbox.bind('<<ListboxSelect>>', on_select)listbox_update(test_list)root.mainloop()

At start with full list

enter image description here

Later only with filtered items

enter image description here


EDIT: 2020.07.21

If you want to use <KeyPress> then you have to change on_keyrelease and use event.char, event.keysym and/or event.keycode because KeyPress is executed before tkinter update text in Entry and you have to add event.char to text in Entry (or remove last char when you press backspace)

if event.keysym == 'BackSpace':    value = event.widget.get()[:-1]  # remove last charelse:    value = event.widget.get() + event.char  # add new char at the end

It may need other changes for other special keys Ctrl+A, Ctrl+X, Ctrl+C, Ctrl+E, etc. and it makes big problem.

#!/usr/bin/env python3import tkinter as tkdef on_keypress(event):    print(event)    print(event.state & 4) # Control    print(event.keysym == 'a')    # get text from entry    if event.keysym == 'BackSpace':        # remove last char        value = event.widget.get()[:-1]    elif (event.state & 4): # and (event.keysym in ('a', 'c', 'x', 'e')):        value = event.widget.get()    else:        # add new char at the end                value = event.widget.get() + event.char    #TODO: other special keys    value = value.strip().lower()    # get data from test_list    if value == '':        data = test_list    else:        data = []        for item in test_list:            if value in item.lower():                data.append(item)                    # update data in listbox    listbox_update(data)def listbox_update(data):    # delete previous data    listbox.delete(0, 'end')    # sorting data     data = sorted(data, key=str.lower)    # put new data    for item in data:        listbox.insert('end', item)def on_select(event):    # display element selected on list    print('(event) previous:', event.widget.get('active'))    print('(event)  current:', event.widget.get(event.widget.curselection()))    print('---')# --- main ---test_list = ('apple', 'banana', 'Cranberry', 'dogwood', 'alpha', 'Acorn', 'Anise', 'Strawberry' )root = tk.Tk()entry = tk.Entry(root)entry.pack()entry.bind('<KeyPress>', on_keypress)listbox = tk.Listbox(root)listbox.pack()#listbox.bind('<Double-Button-1>', on_select)listbox.bind('<<ListboxSelect>>', on_select)listbox_update(test_list)root.mainloop()

BTW:

You can also use textvariable in Entry with StringVar and trace which executes function when StringVar changes content.

var_text = tk.StringVar()var_text.trace('w', on_change)entry = tk.Entry(root, textvariable=var_text)entry.pack()

#!/usr/bin/env python3import tkinter as tkdef on_change(*args):    #print(args)              value = var_text.get()    value = value.strip().lower()    # get data from test_list    if value == '':        data = test_list    else:        data = []        for item in test_list:            if value in item.lower():                data.append(item)                    # update data in listbox    listbox_update(data)def listbox_update(data):    # delete previous data    listbox.delete(0, 'end')    # sorting data     data = sorted(data, key=str.lower)    # put new data    for item in data:        listbox.insert('end', item)def on_select(event):    # display element selected on list    print('(event) previous:', event.widget.get('active'))    print('(event)  current:', event.widget.get(event.widget.curselection()))    print('---')# --- main ---test_list = ('apple', 'banana', 'Cranberry', 'dogwood', 'alpha', 'Acorn', 'Anise', 'Strawberry' )root = tk.Tk()var_text = tk.StringVar()var_text.trace('w', on_change)entry = tk.Entry(root, textvariable=var_text)entry.pack()listbox = tk.Listbox(root)listbox.pack()#listbox.bind('<Double-Button-1>', on_select)listbox.bind('<<ListboxSelect>>', on_select)listbox_update(test_list)root.mainloop()