Trace in Verbindung mit Entry-Variablen

Fragen zu Tkinter.
Antworten
tryanderror
User
Beiträge: 24
Registriert: Mittwoch 19. Februar 2020, 08:30

Hallo,

ich bin gerade dabei bei einer Gui von mir ein bisschen aufzuräumen und Zeilen zu sparen, bzw. auch Optimierungen zu machen um If-Abfragen zu vereinfachen.
Konkret bin ich momentan dabei Entry-Felder anzulegen und will den Input in diesen Felder Überwachen bzw. soll, wenn ungewollte Zeichen eingelesen werden diese Entfernt werden. Auch zu lange Eingaben sollen verhindert werden.

Da bin ich auf die Tolle Trace-Funktion gestoßen und habe auch mein Ziel erreicht nun aber wollte ich das bisschen kleiner aufschreiben um Übersicht zu behalten.

Also hier erstmal das was so wie es ist Funktioniert:

Code: Alles auswählen

textvars = []
self.entrys = []

for element in range(4):
    textvars.append( tkinter.StringVar() )
    self.entrys.append( tkinter.Entry( width=5, textvariable=textvars[element], justify="center") )

textvars[0].trace("w", lambda name, index, mode, var=textvars[0]: self.clean_input(self.entrys[0].get(),textvars[0]._name))
textvars[1].trace("w", lambda name, index, mode, var=textvars[1]: self.clean_input(self.entrys[1].get(),textvars[1]._name))
textvars[2].trace("w", lambda name, index, mode, var=textvars[2]: self.clean_input(self.entrys[2].get(),textvars[2]._name))
textvars[3].trace("w", lambda name, index, mode, var=textvars[3]: self.clean_input(self.entrys[3].get(),textvars[3]._name))

def clean_input(self, value, var):
    print(value, var)

Man kann sich schon denken was ich wohl im Quelcode reduzieren wollte...
Ich wollte ledeglich die For um eine Zeile ergänzen, damit ich alles in einem Block fertig mache.

Code: Alles auswählen

for element in range(4):
    textvars.append( tkinter.StringVar() )
    self.entrys.append( tkinter.Entry( width=5, textvariable=textvars[element], justify="center") )
    textvars[element].trace("w", lambda name, index, mode, var=textvars[element]: self.clean_input(self.entrys[element].get(),textvars[element]._name))
Resultat ist aber, dass nun Trace nur an dem letzten Entry hängt(auslösen tut es bei jedem Entry), ich habe die einzelnen Entrys auch nochmal mit print ausgeben lassen um sicher zu stellen, dass diese auch alle ihre eigene Variable haben. Ich bekomme egal in welches Feld ich schreibe immer als Variable PY_VAR3, und die Value dieser... Übersehe ich etwas oder verwende ich Trace falsch?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du machst dir das Leben unnoetig schwer durch den permanenten Zugriff auf textvars[element]. Weise die neue StringVar lieber einem Namen zu, den du dann spaeter in textvars steckst. Gleiches gilt fuer das Entry.

Und dann uebergibst du BEIDES gebunden an einen Namen ans lambda, und verwendest das. Denn da liegt dein Fehler: auch wenn du var bindest im Lamba, du benutzt es nicht. Stattdessen greifst due immer ueber die Datenstruktur zu, und den Index element. Der immer auf 3 zeigt, weil das der letzte vergebene Wert war.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Speichere die textvars auch in self.
Wenn Du textvars hast, brauchst Du eigentlich das Entry gar nicht mehr wissen.
Benutze functools.partial statt lambda.

Code: Alles auswählen

for element in range(4):
    textvar = tkinter.StringVar()
    tkinter.Entry(width=5, textvariable=textvar, justify="center").pack()
    textvar.trace("w", partial(self.clean_input, textvar))
    self.textvars.append(textvar)

def clean_input(self, textvar):
    print(textvar, textvar.get())
Benutzeravatar
__blackjack__
User
Beiträge: 14087
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@tryanderror: Das `_name`-Attribut gehört nicht zur öffentlichen API von `StringVar`, da solltest Du nicht drauf zugreifen. Das bedeuten einzelne führende Unterstriche bei Attributnamen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten