2016-05-25 14 views
2

私のプログラムでは、ユーザーが入力中にguiを更新したいと思います。リソースの理由から、ユーザーがxミリ秒間何かを入力していない場合にのみ実行したいと思います。ここでは動作する例がありますが、2つの追加機能が必要で少し冗長であるため、あまり好きではありません。ユーザーがTkinterの入力をやめるまで待つ

import tkinter as tk 
import random 

COLORS =["red", "orange", "yellow", "green", "blue", "violet"] 

class Application(tk.Frame): 

    def __init__(self,master): 
     self.counter = 0 
     self.master = master 
     tk.Frame.__init__(self) 
     self.pack() 

     self.entry = tk.Entry(self) 
     self.entry.pack() 
     self.entry.bind('<Key>',lambda event: self.handle_wait(event)) 


    def handle_wait(self,event): 
     self.counter += 1 
     counter = self.counter 
     self.after(1000,lambda: self.handle_wait2(counter)) 


    def handle_wait2(self,counter): 
     if self.counter == counter: 
      self.change_color() 

    def change_color(self): 
     random_color = random.choice(COLORS) 
     self.entry.config(background=random_color) 

root = tk.Tk() 
app = Application(root) 
app.mainloop() 

それを行うには良い方法はありますか?

+3

'Entry'ウィジェットのオプションの検証機能を使用して、最後のキーストロークが入力された時刻を記録し、その値を' after() 'コールバック関数でチェックすることができます。 Entryウィジェットの検証の詳細はこちら(http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html)。 – martineau

答えて

2

解決策は、ユーザーが入力をやめた後に実行する機能をスケジュールするためにafterを使用することです。その後、ボタンをクリックするたびにジョブを再開するだけです。

最初に、将来の関数呼び出しを表すIDを格納する変数を作成します。 self.counterは不要なので、捨てることもできます。

def __init__(...): 
    ... 
    self._after_id = None 
    ... 

次に、あなたの結合にラムダを削除します。それは無意味だと、それは必要以上のコードはより複雑になります:

self.entry.bind('<Key>',self.handle_wait) 

最後に、このように見えるためにあなたのhandle_wait機能を変更します。

def handle_wait(self, event): 
    # cancel the old job 
    if self._after_id is not None: 
     self.after_cancel(self._after_id) 

    # create a new job 
    self.after(1000, self.change_color) 

ここにあなたのコードに基づく完全な例です:

import tkinter as tk 
import random 

COLORS =["red", "orange", "yellow", "green", "blue", "violet"] 

class Application(tk.Frame): 

    def __init__(self,master): 
     self.master = master 
     tk.Frame.__init__(self) 
     self.pack() 

     self._after_id = None 
     self.entry = tk.Entry(self) 
     self.entry.pack() 
     self.entry.bind('<Key>',self.handle_wait) 

    def handle_wait(self,event): 
     # cancel the old job 
     if self._after_id is not None: 
      self.after_cancel(self._after_id) 

     # create a new job 
     self._after_id = self.after(1000, self.change_color) 

    def change_color(self): 
     random_color = random.choice(COLORS) 
     self.entry.config(background=random_color) 

root = tk.Tk() 
app = Application(root) 
app.mainloop() 
+0

恐ろしい!どうもありがとうございました。キャンセル機能付きのソリューションは非常にエレガントで、私はそれが存在するのかどうかはわかりませんでした。非常に便利です – Jannick

+0

こんにちは、この便利なコードブライアンありがとう。私はクラスなしで同じことをしようとしています。あなたは '.self'にバインドされた' after(1000、self.change_color) 'を持っています。これをエントリーウィジェットまたはルートにバインドしようとすると、それぞれ' 'の1000がフリーズします...これをフレームにバインドする必要がありますあなたが持っているウィジェットまたはこれを解決する最善の方法は何ですか? – Rhys

+0

@Rhys:私はあなたの用語をよく理解していません。 'after'コマンドは呼び出される関数への参照を与えなければなりません。その関数がクラスの一部であるかどうかは関係ありません。エントリーウィジェットや他のウィジェットにバインドすることは決してありません。それを関数にバインドします。 –

関連する問題