2017-09-25 136 views
0

我有一個條目,一個列表框(下拉列表)和另一個列表框。每當輸入內輸入3個以上的字符時。查看完成列表並將其插入到下拉列表中,並顯示下拉列表。如果從下拉列表中選擇一個項目。它的值應該插入到列表框中並從下拉列表中移除,並且該條目應該再次獲得焦點。但事實並非如此。蟒蛇 - 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是可測試的版本。這裏是建立autocompelete的實例代碼:

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

你的代碼是不是測試。我們需要能夠複製粘貼您的代碼並查看您的問題。請提供[最小,完整和可驗證示例](https://stackoverflow.com/help/mcve),以便我們測試您的代碼。 –

+0

@ Mike-SMT我添加了一個鏈接到完整的代碼。 –

+1

到「可測試版本」的鏈接仍然不可測試。你如何創建'Autocomplete()'的對象實例。沒有調用該類的代碼。你不需要提供你所有的代碼。只是一個MCVE。這隻需要包括有問題的方法以及如何創建tkinter實例。您的代碼中沒有'Tk()'或'mainloop()',並且tkinter需要運行。我們需要能夠複製粘貼您的示例,而不必猜測您的課程實施情況。 –

回答

2

那麼幾件事情,我不得不改變得到這個至少一個字工作。目前,如果您希望繼續以連續字符串輸入更多單詞,它將不起作用。

我相信我終於可以得到這個工作,但我試圖回答從列表框中更新單詞並將焦點轉回到輸入字段的問題。我不得不改變幾件事情。

首先,我不得不改變:

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

哇!你真的嘗試過很多幫助。你做得比我需要的多得多,這可能是我沒有正確解釋我的目標和問題。對於第一次編輯,我明白刪除int()會更好,但是我不會收到任何錯誤。將int重新轉換爲int不能是錯誤。對於第二次編輯,我認爲你的目標錯誤。該值不應插入到應該插入到第二個列表框的條目中。但沒關係。感謝關於命名的提示。我會牢記這一點。關於延遲的事情是我的問題。你爲我修好了!>:D < –

+1

@aran:你的問題有點混亂,所以我和我認爲你的目標是一致的。對困惑感到抱歉。看看我的重點部分的更新。我爲您可能更喜歡使用的焦點部分添加了第二個選項。 –

+0

是的。這實際上更好。謝謝:) –