2017-09-25 27 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はテスト可能なバージョンです。そして、ここで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

wow mike!あなたは本当に手伝ってくれました。あなたは私の必要以上に多くのことをしました。おそらく私の目標や問題を正しく説明できませんでした。最初の編集では、int()を削除する方が良いとわかっていますが、とにかくエラーは発生しません。 intをintにキャストするのはエラーであってはなりません。 2回目の編集では、私の目標が間違っていると思う。 2番目のリストボックスに挿入する必要があるエントリに値を挿入しないでください。しかしそれは問題ではありません。命名についてのヒントをありがとう。私はそれを念頭に置いておきます。遅れについてのことは私の問題でした。 >あなたは私のためにそれを修正しました!>:D < –

+1

@aran:あなたの質問はちょっと面倒だったので、あなたの目標は何だと思っていました。混乱させて申し訳ありません。フォーカス部分の私の更新を見てください。私はあなたが使用することを好むかもしれない焦点部分のための2番目のオプションを追加しました。 –

+0

ええ。それは実際にはさらに優れています。ありがとうございました:) –

関連する問題