Die richtige Antwort lautet: Verwenden Sie das validatecommand
Attribut des Widgets. Leider ist diese Funktion in der Tkinter-Welt stark unterdokumentiert, obwohl sie in der Tkinter-Welt ausreichend dokumentiert ist. Obwohl es nicht gut dokumentiert ist, bietet es alles, was Sie für die Validierung benötigen, ohne auf Bindungen oder Ablaufverfolgungsvariablen zurückgreifen oder das Widget innerhalb des Validierungsverfahrens ändern zu müssen.
Der Trick besteht darin, zu wissen, dass Tkinter spezielle Werte an Ihren Validierungsbefehl übergeben kann. Diese Werte geben Ihnen alle Informationen, die Sie wissen müssen, um zu entscheiden, ob die Daten gültig sind oder nicht: den Wert vor der Bearbeitung, den Wert nach der Bearbeitung, wenn die Bearbeitung gültig ist, und mehrere andere Informationen. Um diese zu verwenden, müssen Sie jedoch ein wenig Voodoo machen, um diese Informationen an Ihren Validierungsbefehl zu übergeben.
Hinweis: Es ist wichtig, dass der Validierungsbefehl entweder True
oder zurückgibt False
. Alles andere führt dazu, dass die Validierung für das Widget deaktiviert wird.
Hier ist ein Beispiel, das nur Kleinbuchstaben zulässt (und alle diese funky Werte druckt):
import tkinter as tk # python 3.x
# import Tkinter as tk # python 2.x
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
# valid percent substitutions (from the Tk entry man page)
# note: you only have to register the ones you need; this
# example registers them all for illustrative purposes
#
# %d = Type of action (1=insert, 0=delete, -1 for others)
# %i = index of char string to be inserted/deleted, or -1
# %P = value of the entry if the edit is allowed
# %s = value of entry prior to editing
# %S = the text string being inserted or deleted, if any
# %v = the type of validation that is currently set
# %V = the type of validation that triggered the callback
# (key, focusin, focusout, forced)
# %W = the tk name of the widget
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)
# Disallow anything but lowercase letters
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()
Weitere Informationen darüber, was beim Aufrufen der register
Methode unter der Haube passiert, finden Sie unter Eingabeüberprüfung tkinter
Nachdem ich Bryans Code studiert und experimentiert hatte, erstellte ich eine minimale Version der Eingabevalidierung. Der folgende Code öffnet ein Eingabefeld und akzeptiert nur numerische Ziffern.
Vielleicht sollte ich hinzufügen, dass ich noch Python lerne und gerne alle Kommentare / Vorschläge akzeptiere.
quelle
entry.configure(validatecommand=...)
und schreiben die Leutetest_val
statttestVal
, aber dies ist ein gutes, einfaches Beispiel.Verwenden Sie a
Tkinter.StringVar
, um den Wert des Eintrags-Widgets zu verfolgen. Sie können den Wert von überprüfen,StringVar
indem Sie a einstellentrace
darauf setzen.Hier ist ein kurzes Arbeitsprogramm, das nur gültige Floats im Eintrags-Widget akzeptiert.
quelle
Während ich Bryan Oakleys Antwort studierte, sagte mir etwas, dass eine weitaus allgemeinere Lösung entwickelt werden könnte. Im folgenden Beispiel werden eine Modusaufzählung, ein Typwörterbuch und eine Setup-Funktion zu Validierungszwecken vorgestellt. In Zeile 48 finden Sie beispielsweise die Verwendung und eine Demonstration der Einfachheit.
quelle
Bryans Antwort ist richtig, aber niemand erwähnte das Attribut 'invalidcommand' des tkinter-Widgets.
Eine gute Erklärung finden Sie hier: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html
Text kopiert / eingefügt bei defektem Link
Das Eintrags-Widget unterstützt auch eine ungültige Befehlsoption, die eine Rückruffunktion angibt, die aufgerufen wird, wenn der validate-Befehl False zurückgibt. Dieser Befehl kann den Text im Widget mithilfe der .set () -Methode für die zugehörige Textvariable des Widgets ändern. Das Einrichten dieser Option funktioniert genauso wie das Einrichten des Befehls validate. Sie müssen die .register () -Methode verwenden, um Ihre Python-Funktion zu verpacken. Diese Methode gibt den Namen der umschlossenen Funktion als Zeichenfolge zurück. Dann übergeben Sie als Wert der Option invalidcommand entweder diese Zeichenfolge oder als erstes Element eines Tupels, das Substitutionscodes enthält.
Hinweis: Es gibt nur eine Sache, die ich nicht herausfinden kann: Wenn Sie einem Eintrag eine Validierung hinzufügen und der Benutzer einen Teil des Textes auswählt und einen neuen Wert eingibt, gibt es keine Möglichkeit, den ursprünglichen Wert zu erfassen und zurückzusetzen der Eintritt. Hier ist ein Beispiel
quelle
Hier ist eine einfache Möglichkeit, den Eingabewert zu validieren, bei der der Benutzer nur Ziffern eingeben kann:
PS: Dieses Beispiel kann sehr nützlich sein, um eine App wie calc zu erstellen.
quelle
quelle
Antwort auf das Problem von orionrobert, sich mit der einfachen Validierung von Textersetzungen durch Auswahl zu befassen, anstatt separate Löschungen oder Einfügungen:
Eine Ersetzung des ausgewählten Textes wird als Löschung gefolgt von einer Einfügung verarbeitet. Dies kann beispielsweise zu Problemen führen, wenn beim Löschen der Cursor nach links bewegt werden soll, während beim Ersetzen der Cursor nach rechts bewegt werden soll. Glücklicherweise werden diese beiden Prozesse sofort ausgeführt nacheinander . Daher können wir zwischen einer Löschung für sich und einer Löschung unterscheiden, auf die unmittelbar eine Einfügung aufgrund einer Substitution folgt, da letztere das Leerlauf-Flag zwischen Löschung und Einfügung nicht geändert hat.
Dies wird mit einem SubstitutionFlag und einem ausgenutzt
Widget.after_idle()
.after_idle()
führt die Lambda-Funktion am Ende der Ereigniswarteschlange aus:Natürlich weiß man nach einer Ersetzung während der Validierung des Löschteils immer noch nicht, ob eine Einfügung folgen wird. Zum Glück jedoch mit:
.set()
,.icursor()
,.index(SEL_FIRST)
,.index(SEL_LAST)
,.index(INSERT)
, können wir am meisten gewünschtes Verhalten nachträglich erreichen (da die Kombination unserer neuen substitutionFlag mit einer Insertion ist eine neue , einzigartige und letzte Veranstaltung.quelle