我有一个条目,一个列表框(下拉列表)和另一个列表框。只要在条目中输入超过3个字符。查找完成列表并将其插入下拉列表并显示下拉列表。如果从下拉列表中选择了某个项目。它的值应该填入条目,条目应该再次获得焦点,光标应该到达条目的末尾。然后,当按下Enter键时,应将条目的值插入另一个列表框。
我在this实用程序的帮助下开发了一个代码,代码运行得非常好。除此之外,我意识到每当我从下拉列表中选择一个选项时,相应的方法被调用两次(我在控制台中从同一个东西得到两个打印件)。但是,如果我选择下拉列表的第一个选项,它会被调用一次(这是另一种情况下实际应该发生的事情),但焦点不会转到条目(这是一个问题)。
这是我的代码:
from tkinter import *
class Autocomplete(Frame, object):
def __init__(self, width, height, entries, *args, **kwargs):
super(Autocomplete, self).__init__(*args, **kwargs)
self._entries = entries
self.listbox_height = height
self.entry_width = width
self.text = StringVar()
self.entry = Entry(
self,
textvariable=self.text,
width=self.entry_width
)
self.frame = Frame(self)
self.listbox = Listbox(
self.frame,
height=self.listbox_height,
width=self.entry_width
)
self.dropdown = Listbox(
self.frame,
height=self.listbox_height,
width=self.entry_width,
background="#cfeff9"
)
def build(self):
self.text.trace("w", lambda name, index, mode, text=self.text: self._update_autocomplete())
self.entry.bind("<Return>", lambda event,: self._add_course())
self.entry.focus_set()
self.entry.pack()
self.frame.pack()
self.listbox.grid(column=0, row=0, sticky=N)
self.dropdown.bind("<<ListboxSelect>>", self._select_entry)
self.dropdown.grid(column=0, row=0, sticky=N)
self.dropdown.grid_forget()
return self
def _update_autocomplete(self):
self.dropdown["height"] = self.listbox_height
self.dropdown.delete(0, END)
text = self.text.get()
if len(text) < 3:
self.dropdown.grid_forget()
return
else:
for entry in self._entries:
if text.lower() in entry.strip().lower():
self.dropdown.insert(END, entry)
listbox_size = self.dropdown.size()
if not listbox_size:
self.dropdown.insert(END, "No results found for '{}'")
self.dropdown["height"] = 1
else:
if listbox_size <= self.dropdown["height"]:
self.dropdown["height"] = listbox_size
self.dropdown.grid(column=0, row=0, sticky=N)
def _select_entry(self, event):
widget = event.widget
value = widget.get(int(widget.curselection()[0]))
print(value)
self.text.set(value)
self.entry.focus_set()
self.entry.icursor(END)
def _add_course(self):
self.listbox.insert(END, self.text.get())
那我在这里错过了什么?
顺便说一下,对代码的任何一般改进也将非常受欢迎。
以下是我的称呼方式:
from tkinter import *
from autocomplete import Autocomplete
from main import *
courses = load_courses_from_file("courses.txt")
root = Tk()
autocomplete_frame = Autocomplete(
60,
10,
list(set(course.name + ", " + course.instructor for course in courses))
).build().pack()
mainloop()
答案 0 :(得分:1)
单击项目时,列表框的选择会更改 - 这是列表框的默认行为。这会导致条目窗口小部件值发生更改,从而触发对_update_autocomplete
的调用。该函数删除列表框中的所有内容,导致选择再次更改。