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
Later only with filtered items
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()