A resposta correta é: use o validatecommand
atributo do widget. Infelizmente, esse recurso está seriamente sub documentado no mundo Tkinter, embora seja suficientemente documentado no mundo Tk. Mesmo que não seja bem documentado, ele tem tudo que você precisa para fazer a validação sem recorrer a ligações ou rastrear variáveis, ou modificar o widget de dentro do procedimento de validação.
O truque é saber que você pode fazer com que o Tkinter passe valores especiais para o seu comando de validação. Esses valores fornecem todas as informações que você precisa saber para decidir se os dados são válidos ou não: o valor antes da edição, o valor após a edição se a edição for válida e vários outros bits de informação. Para usá-los, no entanto, você precisa fazer um pequeno vodu para que essas informações sejam passadas para seu comando de validação.
Nota: é importante que o comando de validação retorne True
ou False
. Qualquer outra coisa fará com que a validação seja desativada para o widget.
Aqui está um exemplo que permite apenas letras minúsculas (e imprime todos os valores funky):
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 obter mais informações sobre o que acontece nos bastidores quando você chama o register
método, consulte Validação de entrada tkinter