Dans certains cas de saisie de données, il vaut mieux vérifier chaque caractère pour l'empêcher ou pour le modifier, que d'attendre la sortie du widget (perte de focus) ou même la fin d'une saisie complète pour découvrir qu'il y a des caractères interdits ou inadaptés dans une valeur. Par exemple, on peut vouloir empêcher la lettre “O” dans un code postal, ou convertir les caractères accentués en non-accentués.
On utilise des options du widget Entry (validate et validatecommand) qui, curieusement, ne sont pas dans le manuel Tkinter de Mexico (2008). Par contre, ils se trouvent ici: http://effbot.org/tkinterbook/entry.htm.
Dans l'exemple ci-dessous, on veut limiter la saisie à soit un chiffre (de 0 à 9), soit la touche backspace.
la ligne:
self.saisie.bind("<Key>", self.quelletouche)
fera que chaque touche clavier va générer un évènement qui lancera la méthode “quelletouche()”. Celle-ci ne fera qu'une seule chose: elle stockera la valeur de l'évènement.
La ligne:
self.saisie.configure(validate="key",validatecommand=self.veriftouche)
fera que seules les touches qui rendent la méthode veriftouche() vraie (=True) seront insérées dans le widget Entry. Dans le cas contraire, rien ne sera inséré.
Rien n'empêche, dans la méthode de validation, de renvoyer un message d'alerte comme un “bip” lorsque la touche qui vient d'être saisie n'est pas dans la liste acceptable:
def veriftouche(self): if (self.touche.char in "0123456789") or (self.touche.keysym == "BackSpace"): return True else: self.bell() return False
Dernier point, en cas d'insertion, il vaut mieux que celle-ci respecte le protocole de validation plutôt que d'utiliser la méthode habituelle “.insert(). On le fait ici en utilisant .event_generate(car) qui envoie tout simplement le caractère comme s'il venait du clavier. Pour bien montrer que cette insertion passe par la validation, j'ai mis “toto” au milieu de la chaîne à insérer.
#!/usr/bin/python # -*- coding: utf-8 -*- import Tkinter class Application(Tkinter.Frame): def __init__(self, master=None): Tkinter.Frame.__init__(self, master, background="ivory") self.grid() self.saisie=Tkinter.Entry(self, background="white", width=50) self.saisie.configure(validate="key",validatecommand=self.veriftouche) self.saisie.bind("<Key>", self.quelletouche) self .saisie.grid(row=0, column=0, sticky="EW") self.bout=Tkinter.Button(self, text="insert", command=lambda x="123toto789": self.insevent(x)) self.bout.grid(row=1) self.saisie.focus_set() self.touche=None def quelletouche(self, event): self.touche=event def veriftouche(self): return (self.touche.char in "0123456789") or (self.touche.keysym == "BackSpace") def insevent(self, ch): for car in ch: self.saisie.event_generate(car) fen=Tkinter.Tk() app=Application(fen) fen.mainloop()
On utilise la même technique que précédemment.
#!/usr/bin/python # -*- coding:utf-8 -*- from __future__ import division import Tkinter ################################################################## class Application(Tkinter.Frame): def __init__(self, master=None): Tkinter.Frame.__init__(self, master) self.grid() self.varsaisie = Tkinter.StringVar() self.varsaisie.set("") self.saisie=Tkinter.Entry(self, background="white", width=50, textvariable=self.varsaisie) self.saisie.bind("<Key>", self.quelletouche) self.saisie.grid(row=0,column=0,padx=3, pady=6) self.saisie.focus_set() self.alpha1 = u"àÀâÂçÇéÉèÈêÊëËîÎïÏôÔùÙûÛüÜÿŸ" self.alpha2 = u"aAaAcCeEeEeEeEiIiIoOuUuUuUyY" def quelletouche(self, event): self.touche=event self.saisie.configure(validate="key",validatecommand=self.veriftouche) def veriftouche(self): i = self.alpha1.find(self.touche.char) if i>=0: self.saisie.event_generate(self.alpha2[i]) return False else: return True ############################################################################## # lancement et affichage au centre de l'écran de l'application # if __name__ == "__main__": fen=Tkinter.Tk() fen.title(u"Saisie controlée") app=Application(fen) fen.mainloop()
Amusez-vous bien!