web-dev-qa-db-ja.com

Tkinter Entryウィジェットが変更されたときにイベントコールバックを取得するにはどうすればよいですか?

まさに質問が言うように。 Textウィジェットには<<Modified>>イベント、ただしEntryウィジェットは表示されません。

43
bfops

Tkinter StringVarをエントリウィジェットに追加します。 traceメソッドを使用して、コールバックをStringVarにバインドします。

from Tkinter import *

def callback(sv):
    print sv.get()

root = Tk()
sv = StringVar()
sv.trace("w", lambda name, index, mode, sv=sv: callback(sv))
e = Entry(root, textvariable=sv)
e.pack()
root.mainloop()  
66

執筆時点(2017、Python 3.6、tkinterバージョン8.6.6)では、ドキュメントでは.traceは非推奨です。推奨される形式は次のとおりです。

sv.trace_add("write", callback)

変数が変更されるたびに通知が必要な場合、これは非常にうまく機能します。ただし、私のアプリケーションは、ユーザーがテキストの編集を終了したときに通知を受け取りたいだけです。私はここでうまく機能するための「検証」メカニズムのピギーバッキングを見つけました。

from tkinter import *

root = Tk()
sv = StringVar()

def callback():
    print(sv.get())
    return True

e = Entry(root, textvariable=sv, validate="focusout", validatecommand=callback)
e.grid()
e = Entry(root)
e.grid()
root.mainloop()

これにより、エントリウィジェットがフォーカスを失うたびにcallbackが呼び出されます(最初のウィジェットが実際にフォーカスを失うことができるように、2番目のエントリウィジェットを追加しました!)

21
Matthew Daws

スティーブンありがとう! Russell OwenのTkinter Folkloreは、globalgetvar()を使用して名前引数(PY_VAR#)からStringVar値を直接取得する方法を説明していますが、名前をウィジェットにマップする方法は説明していません。コールバック引数を変更するラムダメソッドは魔法のようなものです(少なくとも、私たちにとってはPython初心者)。

複数のエントリがある場合、値だけでなく、どのエントリが変更されたかを知る必要があることがよくあります。 Stevenの例を少し拡張して、次の(Python3)は、複数のエントリを追跡するために使用できるインデックスを渡します。

from tkinter import Tk, Frame, Label, Entry, StringVar

class Fruitlist:
    def entryupdate(self, sv, i):
        print(sv, i, self.fruit[i], sv.get())

    def __init__(self, root):
        cf = Frame(root)
        cf.pack()
        self.string_vars = []
        self.fruit = ("Apple", "Banana", "Cherry", "Date")
        for f in self.fruit:
            i = len(self.string_vars)
            self.string_vars.append(StringVar())
            self.string_vars[i].trace("w", lambda name, index, mode, var=self.string_vars[i], i=i:
                              self.entryupdate(var, i))
            Label(cf, text=f).grid(column=2, row=i)
            Entry(cf, width=6, textvariable=self.string_vars[i]).grid(column=4, row=i)

root = Tk()
root.title("EntryUpdate")
app = Fruitlist(root)
root.mainloop() 
9
Dave

私は他のバリアントを知っています。

コードを入力する前に、コーディングのパスをよりよく説明できます:read here

私のコードがあります:

from Tkinter import *

class ttt:
   def __init__(self):
      self.str1 = StringVar()
      self.e1 = Entry(root, textvariable=self.str1)
      self.str1.trace('w', self.callback_1)
      self.e1.pack()

      self.str2 = StringVar()
      self.e2 = Entry(root, textvariable=self.str2, state='readonly')
      self.e2.pack()

      self.str3 = StringVar()
      self.e3 = Entry(root, textvariable=self.str3, state='readonly')
      self.e3.pack()

      bt = Button(root, text = 'ещё', command = self.callback_2)
      bt.pack()

   def callback_1(self, name='', index='', mode=''):
      tmp = self.str1.get()
      if tmp:
         self.str2.set(int(tmp) * 6)
         print self.str2.get()

   def callback_2(self, name='', index='', mode=''):
      tmp = self.str1.get()
      if tmp:
         self.str3.set(int(tmp) * 6)
         print self.str3.get()   

root = Tk()
t = ttt()
root.mainloop()

2つのバリエーションがあります。ボタンを押して入力することです。今、あなたは任意のバリアントを選択することができます

1

ユーザーがウィジェットをクリックするたびに発生するKeyReleaseイベントを使用することもできます。
変更よりもフィルターをかけることができます。

from tkinter import * 
from tkinter import ttk

class GUI():                              
    def __init__(self):  
        self.root = Tk()
        self.sv = StringVar() 
        self.prevlaue=''
        #entry
        self.entry = ttk.Entry(self.root, width=30, textvariable =self.sv)
        self.entry.grid(pady=20,padx=20) 
        self.entry.bind("<KeyRelease>", self.OnEntryClick) #keyup                  
        self.root.mainloop()       

    def OnEntryClick(self, event):
        value=self.sv.get().strip()
        changed = True if self.prevlaue != value else False
        print(value, 'Text has changed ? {}'.format(changed))
        self.prevlaue = value

#create the gui
GUI()

役に立てば幸いです。

0
Avi ba

Python 3.6を使用し、.traceを機能させることができませんでした。次のコードでは、StringVarのデフォルト値を受け入れたり編集したりできます。

from tkinter import Tk, LEFT, BOTH, StringVar
from tkinter.ttk import Entry, Frame


class Example(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.initUI()

    def initUI(self):
        self.parent.title("Entry")
        self.pack(fill=BOTH, expand=1)
        self.contents = StringVar()
        # give the StringVar a default value
        self.contents.set('test')
        self.entry = Entry(self)
        self.entry.pack(side=LEFT, padx=15)
        self.entry["textvariable"] = self.contents
        self.entry.bind('<Key-Return>', self.on_changed)

    def on_changed(self, event):
        print('contents: {}'.format(self.contents.get()))
        return True


def main():
    root = Tk()
    ex = Example(root)
    root.geometry("250x100+300+300")
    root.mainloop()


if __== '__main__':
    main()
0
Oppy