La respuesta correcta es utilizar el validatecommand
atributo del widget. Desafortunadamente, esta característica está muy poco documentada en el mundo Tkinter, aunque está suficientemente documentada en el mundo Tk. Aunque no está bien documentado, tiene todo lo que necesita para realizar la validación sin recurrir a enlaces o variables de seguimiento, o modificar el widget desde dentro del procedimiento de validación.
El truco es saber que puede hacer que Tkinter pase valores especiales a su comando de validación. Estos valores le brindan toda la información que necesita saber para decidir si los datos son válidos o no: el valor antes de la edición, el valor después de la edición si la edición es válida y varios otros bits de información. Sin embargo, para usarlos, debe hacer un poco de vudú para que esta información pase a su comando de validación.
Nota: es importante que el comando de validación devuelva True
o False
. Cualquier otra cosa provocará que la validación se desactive para el widget.
Aquí hay un ejemplo que solo permite minúsculas (e imprime todos esos valores originales):
import tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
vcmd = (self.register(self.onValidate),
'%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
self.entry = tk.Entry(self, validate="key", validatecommand=vcmd)
self.text = tk.Text(self, height=10, width=40)
self.entry.pack(side="top", fill="x")
self.text.pack(side="bottom", fill="both", expand=True)
def onValidate(self, d, i, P, s, S, v, V, W):
self.text.delete("1.0", "end")
self.text.insert("end","OnValidate:\n")
self.text.insert("end","d='%s'\n" % d)
self.text.insert("end","i='%s'\n" % i)
self.text.insert("end","P='%s'\n" % P)
self.text.insert("end","s='%s'\n" % s)
self.text.insert("end","S='%s'\n" % S)
self.text.insert("end","v='%s'\n" % v)
self.text.insert("end","V='%s'\n" % V)
self.text.insert("end","W='%s'\n" % W)
if S == S.lower():
return True
else:
self.bell()
return False
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Para obtener más información sobre lo que sucede bajo el capó cuando llama al register
método, consulte Validación de entrada tkinter