Exactement comme le dit la question. Les widgets Text
ont l'événement <<Modified>>
, mais les widgets Entry
n'apparaissent pas.
Ajoutez un Tkinter StringVar à votre widget Entry. Liez votre rappel au StringVar en utilisant la méthode de trace.
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()
Au moment de la rédaction de ce document (2017, Python 3.6, tkinter version 8.6.6), la documentation suggère que .trace
est obsolète. La forme suggérée semble maintenant être:
sv.trace_add("write", callback)
Cela fonctionne très bien si vous souhaitez recevoir une notification chaque fois que la variable est modifiée. Toutefois, mon application souhaite uniquement être notifiée lorsque l'utilisateur termine l'édition du texte. J'ai trouvé que le système de "validation" fonctionnait bien ici:
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()
Ceci invoquera callback
chaque fois que le widget d'entrée perd son focus (j'ai ajouté un second widget d'entrée afin que le premier puisse réellement perdre le focus!)
Merci Steven! Tkinter Folklore, de Russell Owen, explique comment obtenir la valeur StringVar directement à partir de l'argument name (PY_VAR #) à l'aide de globalgetvar (), mais pas comment mapper le nom sur un widget. Votre méthode lambda pour changer les arguments de rappel est comme par magie (pour nous novices en Python, au moins).
Lorsqu'il y a plus d'une entrée, il est souvent nécessaire de connaître non seulement la valeur, mais l'entrée qui a été modifiée. En développant légèrement l’exemple de Steven, ce qui suit (Python3) transmet un index qui peut être utilisé pour garder trace de plusieurs entrées.
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()
Pourquoi avez-vous besoin de savoir quand l'entrée est modifiée?
Vous avez probablement besoin d'un autre comportement:
Dans ce cas, vous pouvez simplement gérer la touche Entrée
self.entry.bind('<Return>', self.on_enter)
def on_enter(self, key_info):
text = self.entry.get()
Vous pouvez également utiliser l'événement KeyRelease qui sera déclenché chaque fois que l'utilisateur clique sur le widget.
Que vous pouvez que filtrer pour les changements.
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()
J'espère que ça aide.
J'utilise Python 3.6 et je ne pouvais pas faire fonctionner .trace. Le code suivant permet d'accepter ou de modifier une valeur par défaut de StringVar. on_changed est appelé lorsque la touche de retour est enfoncée.
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()
Je connais une autre variante.
avant de saisir le code, cela pourrait mieux expliquer le chemin du codage: lire ici
et il y a mon 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()
il y a 2 variantes: en appuyant sur le bouton et en entrant à l'entrée . maintenant vous pouvez sélectionner n'importe quelle variante