88 votes

Comment puis-je obtenir un rappel d'événement lorsqu'un widget Entry Tkinter est modifié?

Exactement comme le dit la question. Les widgets Text ont l'événement <>, mais les widgets Entry ne semblent pas l'avoir.

120voto

Steven Rumbalski Points 16838

Ajoutez un StringVar Tkinter à votre widget Entry. Liez votre fonction de rappel au StringVar en utilisant la méthode de traçage.

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

0 votes

@Nicholas: L'échantillon de code fonctionne tel quel. Qu'est-ce que tu trouves qui manque?

1 votes

J'ai essayé votre solution dans mon code qui a une structure auto, puisque j'ai besoin de changer les propriétés de certains widgets, mais je n'ai pas pu transmettre la structure auto à la trace. Ainsi, j'ai besoin d'utiliser la méthode 'bind' et la balise pour appeler la méthode avec la structure 'self'

1 votes

@ArtOfWarfare: Vous avez tort. Copiez-collez le code dans un interpréteur Python 2.7 (print et Tkinter import doivent être modifiés pour Python 3 ; le lambda resterait le même). Vous verrez que le code s'exécute comme prévu. L'expression lambda est analogue à def anonymous(name, index, mode, sv=sv):return callback(sv) sauf que c'est une expression, pas une déclaration. StringVar.trace appelle son rappel avec des arguments inutiles (name, index, mode) que nous ignorons et au lieu de cela, nous créons une fermeture sur le StringVar lui-même (sv) que nous utilisons ensuite dans le rappel.

63voto

Matthew Daws Points 687

Au moment de l'écriture (2017, Python 3.6, tkinter version 8.6.6) les documents suggèrent que .trace est obsolète. Forme suggérée maintenant semble être:

sv.trace_add("write", callback)

Cela fonctionne très bien si vous souhaitez être notifié à chaque fois que la variable est modifiée. Cependant, mon application souhaite juste être notifiée lorsque l'utilisateur a fini d'éditer le texte. J'ai trouvé que profiter du mécanisme de "validation" fonctionne 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 le focus (j'ai ajouté un 2ème widget d'entrée pour que le 1er puisse réellement perdre le focus!)

13voto

Dave Points 1415

Merci Steven! Le folklore de Tkinter de Russell Owen explique comment obtenir la valeur de StringVar directement à partir de l'argument name (PY_VAR#) en utilisant globalgetvar(), mais pas comment mapper le nom à un widget. Votre méthode lambda pour changer les arguments de rappel est comme de la magie (pour nous les nouveaux venus en Python, du moins).

Lorsqu'il y a plus d'une Entry, il est souvent nécessaire de savoir non seulement la valeur, mais quelle Entry a été modifiée. En reprenant légèrement l'exemple de Steven, le code suivant (Python3) passe un indice qui peut être utilisé pour suivre plusieurs Entries.

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

11voto

user2839567 Points 13

Vous pouvez également utiliser l'événement KeyRelease qui sera déclenché à chaque fois que l'utilisateur clique sur le widget.
Vous pouvez ensuite filtrer les modifications.

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("", 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, 'Le texte a-t-il changé ? {}'.format(changed))
        self.prevlaue = value

#créer l'interface graphique
GUI()

J'espère que cela vous aidera.

5voto

Manngo Points 2894

J'ai pu faire ce dont j'avais besoin en utilisant l'événement . Voici un exemple:

import tkinter
from tkinter import ttk

def doSomething(event):
    text = event.widget.get()
    print(text)

window = tkinter.Tk()
testEntry = ttk.Entry(window)
testEntry.bind('', doSomething)
testEntry.grid(column=0,row=0)
thingEntry = ttk.Entry(window)
thingEntry.bind('', doSomething)
thingEntry.grid(column=0,row=1)
startButton = ttk.Button(window,text='OK',command=lambda: print('click'))
startButton.grid(column=0,row=2, sticky='W')

window.mainloop()
print('Au revoir')

La partie importante est:

def doSomething(event):
    text = event.widget.get()
    print(text)

testEntry.bind('', doSomething)

En utilisant Entry.bind(event,function) vous pouvez attacher un écouteur d'événements, dans ce cas la fonction doSomething. Cette fonction reçoit un paramètre, un objet Event. Vous pouvez ensuite lire ce qui se trouve dans le widget Entry en utilisant event.widget.get().

Chaque fois que vous quittez un Entry, sa valeur est imprimée. Cela inclut lorsque vous cliquez sur le bouton. Comme vous le verrez dans le test, l'événement du bouton est déclenché après l'événement de l'Entry,

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X