web-dev-qa-db-de.com

Wie erhalte ich einen Ereignisrückruf, wenn ein Widget für den Tkinter-Eintrag geändert wird?

Genau wie die Frage sagt. Text-Widgets haben das <<Modified>>-Ereignis, aber Entry-Widgets erscheinen nicht.

37
bfops

Fügen Sie Ihrem Entry-Widget eine Tkinter-String-Variable hinzu. Binden Sie Ihren Callback mit der Trace-Methode an die 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()  
58

Zum Zeitpunkt des Schreibens (2017, Python 3.6, tkinter Version 8.6.6) legen die Dokumente nahe, dass .trace veraltet ist. Das vorgeschlagene Formular scheint jetzt zu sein:

sv.trace_add("write", callback)

Dies funktioniert sehr gut, wenn Sie eine Benachrichtigung erhalten möchten, wenn die Variable geändert wird. Meine Anwendung möchte jedoch nur eine Benachrichtigung, wenn der Benutzer den Text bearbeitet hat. Ich fand, dass der Mechanismus der "Validierung" gut funktioniert, um hier gut zu funktionieren:

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()

Dadurch wird callback aufgerufen, wenn das Eintrags-Widget den Fokus verliert (ich habe ein Widget für den zweiten Eintrag hinzugefügt, sodass das erste Widget tatsächlich den Fokus verlieren kann!)

14
Matthew Daws

Danke Steven! Russell Owens Tkinter Folklore erläutert, wie der StringVar-Wert direkt aus dem Namensargument (PY_VAR #) mithilfe von globalgetvar () abgerufen wird, jedoch nicht, wie der Name einem Widget zugeordnet wird. Ihre Lambda-Methode zum Ändern der Callback-Args ist wie Zauberei (zumindest für uns Python-Neulinge).

Wenn es mehr als einen Eintrag gibt, ist es oft notwendig, nicht nur den Wert zu kennen, sondern auch, welcher Eintrag geändert wurde. Das folgende Beispiel (Python3) übergibt leicht ein Beispiel von Steven und übergibt einen Index, mit dem mehrere Einträge verfolgt werden können.

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

Warum müssen Sie wissen, wann der Eintrag geändert wurde?

Wahrscheinlich brauchen Sie ein anderes Verhalten:

  1. benutzer gibt Text in Eintrag ein
  2. der Benutzer drückt die Eingabetaste, um die Änderungen zu übernehmen

In diesem Fall können Sie einfach die Eingabetaste verwenden

self.entry.bind('<Return>', self.on_enter)

def on_enter(self, key_info):
    text = self.entry.get()
0
dimon4eg

Sie können auch das KeyRelease-Ereignis verwenden, das jedes Mal ausgelöst wird, wenn der Benutzer auf das Widget klickt. 
Dann können Sie nach Änderungen filtern.

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()

Ich hoffe, es hilft.

0
Avi ba

Ich benutze Python 3.6 und konnte .trace nicht zum Laufen bringen. Mit dem folgenden Code kann ein Standardwert von StringVar akzeptiert oder bearbeitet werden. on_changed wird aufgerufen, wenn die Return-Taste gedrückt wird. 

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

Ich kenne andere Variante.

bevor ich den Code eingebe, könnte ich den Pfad der Kodierung besser erklären: read here

und es gibt meinen Code:

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()

es gibt 2 Varianten: Durch Drücken der Taste und Eingabe zum Eintrag . Jetzt können Sie eine beliebige Variante auswählen

0