2017-09-24 57 views
0

我有一个条目,一个列表框(下拉列表)和另一个列表框。每当输入内输入3个以上的字符时。查看完成列表并将其插入到下拉列表中,并显示下拉列表。如果从下拉列表中选择一个项目。它的值应该填写条目,并且条目应该再次获得焦点,并且光标应该移到条目的末尾。然后,当按Enter键时,条目的值应该插入到另一个列表框中。如果在StringVar上调用set(),则会调用绑定到tkinter小部件的两次()

我已经为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

您的代码将不会以发布的方式运行。 –

+0

@BryanOakley你是什么意思?你的意思是我没有打电话吗?如果是的话我编辑了这篇文章。否则,你确定吗? BC我想我正在运行它,我想我复制粘贴代码! –

回答

1

ListBox的选择改变 - 这是列表框的默认行为。这会导致条目窗口小部件值发生更改,从而触发_update_autocomplete的呼叫。该函数删除列表框中的所有内容,导致选择再次更改。

+0

我明白了!点击第一个元素时,所选元素的编号保持为1,因此它不会改变。尽管我仍然不明白为什么焦点没有改变。我该如何解决这个问题。 –