2017-09-24 10 views
0

항목, 목록 상자 (드롭 다운) 및 다른 목록 상자가 있습니다. 항목 내에 3 자 이상이 입력 될 때마다. 완료 목록이 조회되어 드롭 다운에 삽입되고 드롭 다운이 표시됩니다. 항목이 드롭 다운에서 선택되는 경우. 값이 항목을 채워야하고 항목이 다시 초점을 가져와 커서가 항목의 끝으로 가야합니다. 그런 다음 Enter 키를 누르면 항목의 값을 다른 목록 상자에 삽입해야합니다.python - 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

선택은 변경 -이 목록 상자의 기본 동작입니다. 이로 인해 항목 위젯 값이 변경되어 _update_autocomplete에 대한 호출이 트리거됩니다. 이 함수는 목록 상자의 모든 항목을 삭제하므로 선택 항목이 다시 변경됩니다.

+0

나는 본다! 첫 번째 버튼을 클릭하면 선택한 요소의 번호가 1로 유지되므로 변경되지 않습니다. 비록 내가 아직도 초점이 바뀌지 않는 이유는 모르지만. 그리고 어떻게 해결해야하는지. –