Reputation: 41
I am trying to create a searchbar using combobox in tkinter and I want that while the user is typing they can see the combobox expanded with values. I am able to expand the combobox but the focus on combobox entry(textbox) is lost as the combo box values are expanded. I have also tried to set focus of textvariable after expanding the combobox values but still in vain. Please provide a solution without creating classes.
# tkinter modules
import tkinter as tk
import tkinter.ttk as ttk
win=tk.Tk()
searchVar = tk.StringVar()
searchVar.trace("w", lambda name, index, mode, searchVar=searchVar:
on_searchText_edit())
searchBar=ttk.Combobox(win,values=["1","2","3"],width=50,textvar=searchVar)
searchBar.grid(row=0,column=1,columnspan=2,padx=5,pady=5)
def on_searchText_edit():
txt=searchBar.focus_get() #searchVar has the focus
searchBar.event_generate('<Down>')
txt.focus_set()
Upvotes: 4
Views: 5158
Reputation: 1217
I believe you will need to create your own widget to accomplish this task. You can use an Entry widget combined with a listbox to do this. I have put some code together that shows this concept for you. The input is case sensitive. The code is not perfect but you can tweak it to fit your needs.
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('420x200')
frm = tk.Frame(self)
self.var = tk.StringVar()
ent = tk.Entry(frm, textvariable=self.var, fg='black', bg='white')
lst = tk.Listbox(frm, bd=0, bg='white')
item_list = ('Big Dog', 'Big Cat', 'big bird', 'Small Bird', 'Small Fish', 'Little Insect', 'Long Snake')
ent.grid(sticky=tk.EW)
frm.grid(sticky=tk.NW)
def get_input(*args):
lst.delete(0, tk.END)
string = self.var.get()
if string:
for item in item_list:
if item.startswith(string):
lst.insert(tk.END, item)
lst.itemconfigure(tk.END, foreground="black")
for item in item_list:
if item.startswith(string):
lst.grid(sticky=tk.NSEW)
elif not lst.get(0):
lst.grid_remove()
else:
lst.grid_remove()
def list_hide(e=None):
lst.delete(0, tk.END)
lst.grid_remove()
def list_input(_):
lst.focus()
lst.select_set(0)
def list_up(_):
if not lst.curselection()[0]:
ent.focus()
list_hide()
def get_selection(_):
value = lst.get(lst.curselection())
self.var.set(value)
list_hide()
ent.focus()
ent.icursor(tk.END)
self.var.trace('w', get_input)
ent.bind('<Down>', list_input)
ent.bind('<Return>', list_hide)
lst.bind('<Up>', list_up)
lst.bind('<Return>', get_selection)
def main():
app = App()
app.mainloop()
if __name__ == '__main__':
main()
Upvotes: 2