2017-09-25 1 views
0

항목, 목록 상자 (드롭 다운) 및 다른 목록 상자가 있습니다. 항목 내에 3 자 이상 입력 할 때마다. 완료 목록이 조회되어 드롭 다운에 삽입되고 드롭 다운이 표시됩니다. 항목이 드롭 다운에서 선택되는 경우. 값을 목록 상자에 삽입하고 드롭 다운에서 제거해야하며 항목에 다시 포커스가 있어야합니다. 그러나 그렇지 않습니다.python-entry.focus_set() tkinter에서 작동하지 않습니다

from tkinter import * 


class Autocomplete(Frame, object): 
    def __init__(self, *args, **kwargs): 
     super(Autocomplete, self).__init__(*args, **kwargs) 
     self.text = StringVar() 
     self.entry = Entry(self, textvariable=self.text) 
     self.frame = Frame(self) 
     self.listbox = Listbox(self.frame) 
     self.dropdown = Listbox(self.frame) 

    def build(self): 
     self.text.trace("w", lambda name, index, mode: self._update_dropdown()) 
     self.entry.focus_set() 
     self.entry.pack() 
     self.frame.pack() 
     self.listbox.grid(column=0, row=0, sticky=N) 
     self.dropdown.bind("<<ListboxSelect>>", lambda event: self._select_entry()) 
     self.dropdown.grid(column=0, row=0, sticky=N) 
     self.dropdown.grid_forget() 
     return self 

    def _shorten_dropdown(self, index): 
     self.dropdown.grid_forget() 
     self.dropdown.delete(index) 
     self.dropdown["height"] -= 1 
     self.dropdown.selection_clear(0, END) 
     self.dropdown.grid(column=0, row=0, sticky=N) 

    def _select_entry(self): 
     index = int(self.dropdown.curselection()[0]) 
     value = self.dropdown.get(index) 
     self._shorten_dropdown(index) 
     self.entry.focus_set() 

이는 최소한의 코드였다

여기 내 코드입니다. Here은 테스트 가능한 버전입니다. 나는이 적어도 하나 개의 단어를 작동시킬 수로 변경했다

from tkinter import * 
from autocomplete import Autocomplete 

listt = ["a","aa","aaa","ab","bba","aba","abbnb","cd","c","abc","abcd"] 
root = Tk() 

autocomplete_frame = Autocomplete(
    60, 
    10, 
    listt 
).build() 
autocomplete_frame.pack() 

mainloop() 
+1

귀하의 코드를 테스트 할 수 없습니다. 코드를 복사하여 복사하고 문제가 무엇인지 확인해야합니다. 코드를 테스트 할 수 있도록 [Minimal, Complete, Verifiable example] (https://stackoverflow.com/help/mcve)을 제공해주십시오. –

+0

@ Mike-SMT 전체 코드에 대한 링크를 추가했습니다. –

+1

"테스트 가능한 버전"에 대한 링크는 여전히 테스트 할 수 없습니다. 당신은 어떻게'Autocomplete()'의 객체 인스턴스를 생성하고 있습니까? 해당 클래스를 호출하는 코드가 없습니다. 모든 코드를 제공 할 필요는 없습니다. 그냥 MCVE. 이것은 문제의 메소드와 tkinter 인스턴스를 생성하는 방법을 포함하면됩니다. 코드에는'Tk()'또는'mainloop()'이 없으며 tkinter를 실행하는 데 필요합니다. 클래스를 구현하는 방법을 추측 할 필요없이 예제를 복사하여 복사 할 수 있어야합니다. –

답변

2

그래서 몇 가지 : 그리고 여기에 autocompelete의 인스턴스를 구축 할 수있는 코드입니다. 현재 연속 된 문자열로 더 많은 단어를 계속 입력하려면 작동하지 않습니다.

필자도 결국 그렇게 할 수있을 것이라고 확신하지만 목록 상자에서 단어를 업데이트하고 포커스를 입력 필드로 되 돌리는 문제에 답하려고합니다.

나는 몇 가지를 바꿔야했습니다.

index = int(self.dropdown.curselection()[0]) 

에 :

index = self.dropdown.curselection()[0] 

self.dropdown.curselection()[0]의 반환 값이 이미 INT 그대로

는 우선 변경했다. 다시 정수를 정수로 만들 필요가 없습니다.

두 번째로 내가 변경했다 :

def _add_course(self, value): 
    self.listbox.insert(END, value) 
    self.my_list.append(value) 

에 :

def _add_course(self, value): 
    self.entry.delete(0,END) 
    self.entry.insert(END, value) 
    self.my_list.append(value) 

당신이 목록 상자에 value없는 항목 필드를 삽입하려고했던 것처럼. 또한 self.list을 self.my_list` (으)로 변경했습니다. 내장 함수를 덮어 쓰는 이름을 지정하지 마십시오.

변경해야 할 마지막 사항은 초점을 입력 필드로 다시 설정하는 방법이었습니다. 포커스 문제는 마우스 클릭에 초점을 맞추고 있지만 여전히 목록 상자를 클릭하고 포커스를 맞추고 있다는 사실입니다. 포커스가 입력 필드로 설정되기 전에 마우스 클릭을 마무리 할 시간이 있도록 포커스 세트에 지연을 추가해야합니다.

변경 :

self.entry.focus_set() 

로는 :

self.master.after(200, lambda: self.entry.focus()) 

다시 입력 필드에 포커스를 설정하는 대신 bind() 대신 초점 명령에 버튼 해제 이벤트가 될 것입니다.

당신은뿐만 아니라 이런 식으로 초점을 강제 할 수

self.dropdown.bind("<ButtonRelease-1>", lambda x: self.entry.focus()) 

아래의 코드가 주요 문제에 대한 작동합니다 :

from tkinter import * 

class Autocomplete(Frame, object): 
    def __init__(self, width, height, entries, *args, **kwargs): 
     super(Autocomplete, self).__init__(*args, **kwargs) 
     self.my_list = [] 
     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: self._update_dropdown()) 
     self.entry.focus_set() 
     self.entry.pack() 
     self.frame.pack() 
     self.listbox.grid(column=0, row=0, sticky=N) 
     self.dropdown.bind("<<ListboxSelect>>", lambda event: self._select_entry()) 
     self.dropdown.grid(column=0, row=0, sticky=N) 
     self.dropdown.grid_forget() 
     return self 

    def _update_dropdown(self): 
     self.dropdown["height"] = self.listbox_height 
     self.dropdown.delete(0, END) 
     text = self.text.get() 
     print("update: " + text) 
     if len(text) < 3: 
      self.dropdown.grid_forget() 
      return 
     else: 
      for entry in self._entries: 
       if entry not in self.my_list and text.lower() in entry.lower(): 
        self.dropdown.insert(END, entry) 
     listbox_size = self.dropdown.size() 
     if not listbox_size: 
      self.dropdown.insert(END, "No results found for '{}'".format(text)) 
      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 _shorten_dropdown(self, index): 
     print("shorten: {}".format(str(index))) 
     self.dropdown.grid_forget() 
     self.dropdown.delete(index) 
     if self.dropdown["height"] == 1: 
      self.dropdown.insert(END, "No more results found for '{}'".format(self.text.get())) 
     else: 
      self.dropdown["height"] -= 1 
     self.dropdown.selection_clear(0, END) 
     self.dropdown.grid(column=0, row=0, sticky=N) 

    def _select_entry(self): 
     index = self.dropdown.curselection()[0] 
     value = self.dropdown.get(index) 
     print(value) 
     if "results found for" in value: 
      print("return") 
      return 
     print("select: {}".format(value)) 
     self._shorten_dropdown(index) 
     self._add_course(value) 
     self.master.after(200, lambda: self.entry.focus()) 

    def _add_course(self, value): 
     self.entry.delete(0,END) 
     self.entry.insert(END, value) 
     self.my_list.append(value) 



listt = ["a","aa","aaa","ab","bba","aba","abbnb","cd","c","abc","abcd"] 
root = Tk() 

autocomplete_frame = Autocomplete(60, 10, listt).build() 
autocomplete_frame.pack() 

mainloop() 
+0

와우 마이크! 당신은 정말 도움을 많이했습니다. Tho, 당신은 내가 필요로했던 것보다 훨씬 더 많은 것을했습니다. 아마 제 목표와 문제를 정확하게 설명하지 못했을 것입니다. 첫 번째 편집 int() 제거하는 것이 더 나은 이해하지만 어쨌든 오류가 발생하지 않습니다. int를 int로 다시 캐스팅하는 것은 오류가 아니어야합니다. 두 번째 편집에서는 내 목표가 잘못되었다고 생각합니다. 두 번째 목록 상자에 삽입해야하는 항목에 값을 삽입하면 안됩니다. 그러나 그것은 중요하지 않습니다. 이름 지정에 대한 팁에 감사드립니다. 나는 그것을 명심 할 것이다. 그리고 지연에 관한 것은 내 문제였습니다. 그리고 당신은 저를 위해 고쳐주었습니다!> : D < –

+1

@aran : 당신의 질문은 약간 엉망이되어서 당신의 목표가 무엇인지 생각했습니다. 혼란을 드려 죄송합니다. 포커스 부분에 대한 업데이트를 살펴보십시오.내가 선호하는 포커스 부분에 대해 두 번째 옵션을 추가했습니다. –

+0

예. 그것은 실제로 더 좋습니다. 고마워요 :) –

관련 문제