Entry validate

Fragen zu Tkinter.
Antworten
Opa Hansi
User
Beiträge: 13
Registriert: Sonntag 12. März 2023, 10:21

Hallo,
ich bin gerade dabei, mir Python beizubringen. Jetzt hänge ich beim Validieren eines entry-Feldes.

def kasse(fenster): #fenster ist vom übergeordneten Programmteil
fr=t.frahmen(fenster,2,2,508,252) #frame wird erstellt
vali = fr.register(vtest)
og=Entry(fr, validate="focusout", validatecommand=(vali,'%P','%W'),font="Arial 10")

#validate
def vtest(char,obj):

print(char)
widget = fr.nametowidget(obj) #wo bekomme ich einen Wert für self her?
print(widget)

return True

Ich finde keinen Weg, an vtest() das Object fr zu übergeben, um widget zu erzeugen.

Danke im Voraus!
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bitte in Zukunft die code-Tags verwenden, damit die in Python relevanten Einrückungen erhalten bleiben.

Was deine Frage angeht: GUI braucht üblicherweise Objekt Orientierung, und mit zb bound methods (also self.vtest) bekommst du das Self Argument angebunden, und kannst auf andere Attribute zugreifen. Zb auch GUI Elemente, die du da angelegt hast.

Alternativ kann bei simpleren Fällen auch functools.partial oder ein lambda herhalten.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Opa Hansi: Das ist mit den ganzen kryptischen Abkürzungen unverständlich. Da stehen Kommentare zu Namen deren Information in den Namen selbst stehen sollte, damit man keinen Kommentar braucht. Wenn eine Methode `create_frame()`/`erstelle_rahmen()` heisst, bräuchte man dafür keinen Kommentar, und bei `vtest()` bräuchte man den Kommentar nicht wenn das `validate()`/`validieren()` hiesse. `t`, `fr`, `vali`, `og` und `obj` sind so gar keine guten Namen. `nametowidget()` riecht komisch, das habe ich noch nie gebraucht. Warum wird da nicht das tatsächliche Widget übergeben?

Zur Frage: Welches `self`?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Opa Hansi
User
Beiträge: 13
Registriert: Sonntag 12. März 2023, 10:21

Zur Frage: Welches `self`?
[/quote]
__blackjack__ hat geschrieben: Sonntag 12. März 2023, 10:54 @Opa Hansi: Das ist mit den ganzen kryptischen Abkürzungen unverständlich. Da stehen Kommentare zu Namen deren Information in den Namen selbst stehen sollte, damit man keinen Kommentar braucht. Wenn eine Methode `create_frame()`/`erstelle_rahmen()` heisst, bräuchte man dafür keinen Kommentar, und bei `vtest()` bräuchte man den Kommentar nicht wenn das `validate()`/`validieren()` hiesse. `t`, `fr`, `vali`, `og` und `obj` sind so gar keine guten Namen. `nametowidget()` riecht komisch, das habe ich noch nie gebraucht. Warum wird da nicht das tatsächliche Widget übergeben?

Zur Frage: Welches `self`?
Dass ist ja das Problem, validatecommand übergibt nur die Namen der Variablen als str, ich möchte aber die Variable bzw. das Widget übergeben !?
Die kryptischen Abkürzungen bitte ich zu entschuldigen, ich programmiere seit 38 Jahren so , habe es mir so beigebracht.

Code: Alles auswählen

def vtest(fr,char,obj):
        print(fr)
        print(char)
        print(obj)
        widget = fr.nametowidget(obj)
        print(widget)
        
        return True
Fehlermeldung:

Code: Alles auswählen

.!frame
Kasse ?
.!frame.!entry
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Hansi\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "F:\Python\Kasse\kasse.py", line 142, in vtest
    widget = fr.nametowidget(obj)
AttributeError: 'str' object has no attribute 'nametowidget'
Benutzeravatar
grubenfox
User
Beiträge: 413
Registriert: Freitag 2. Dezember 2022, 15:49

wieso eigentlich

Code: Alles auswählen

widget =... 
eine 'Validate'-Funktion soll validieren (entsprechend dann True oder False zurückgeben) und keine Widgets erzeugen
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@grubenfox: Da wird ja keines erzeugt, sondern soll das geliefert werden für das diese Validierung ist. Man kann ja die gleiche Validierung auf mehrere Widgets setzen und möchte dann vielleicht gegebenfalls die Hintergrundfarbe auf Rot oder so setzen, falls der Inhalt nicht gültig ist, damit der Benutzer sieht in welchen Eingabefeldern Fehler sind.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
grubenfox
User
Beiträge: 413
Registriert: Freitag 2. Dezember 2022, 15:49

Aha, das klingt sinnvoll. Die Beispiele, die ich gestern fand, hatten nur geprüft... z.B. https://www.pythontutorial.net/tkinter/ ... alidation/
Da wurde dann auch noch eine on_invalid-Funktion erwähnt, die aufgerufen wird wenn die Prüfung eben False ergeben hat. Das scheint mir das Teil für die Rotmarkierung zu sein.

Eben bin ich noch über das hier gestolpert: https://stackoverflow.com/questions/414 ... in-tkinter
Die erste Antwort ist zwar schon 12 Jahre alt, aber wohl noch gültig.
http://tcl.tk/man/tcl8.6/TkCmd/entry.htm#M16
Opa Hansi
User
Beiträge: 13
Registriert: Sonntag 12. März 2023, 10:21

Hier habe ich etwas brauchbares gefunden :
https://stackoverflow.com/questions/343 ... python-278

Code: Alles auswählen

import tkinter as tk

def onvalidate(P,W):
    # only lowercase is valid
#    valid = (P.lower() == P)
    widget = root.nametowidget(W)

    print(widget.get())
    
    valid = P.isdigit()
    print( 'P is:', type(P), P)
    print( 'valid is:', valid)
    # set red background if invalid
    newcolor = 'yellow' if not valid else default_color
    root.nametowidget(W).configure(background=newcolor)
    return valid

def oninvalid(P,W):
    #called if widget is invalid

    widget = root.nametowidget(W)
    print(widget.get())

    # Changing the text clears the 'validate' value
    # so we have to reset it
    widget.after_idle(lambda W: root.nametowidget(W).configure(validate="key"), W)
    widget.delete(0,len(widget.get()))
    #widget.insert(0,"Fehler")

root = tk.Tk()

valhook = (root.register(onvalidate), '%P', '%W')
invhook = (root.register(oninvalid),  '%P','%W')

entry = tk.Entry(root, validate="key", validatecommand=valhook, invalidcommand=invhook)

default_color = entry.cget('background')

entry.pack()
Damit kann ich etwas anfangen!

Danke für Euer Interesse!
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Opa Hansi: Das verwendet globale Variablen und auch wieder ein Umsetzung von einer Zeichenkette in ein Widget. Das ist Tcl, weil Tcl halt nur Zeichenketten als Datentyp kennt und damit dann irgendwie alles macht. Ich würde da Python verwenden und tatsächlich das Python-Widget-Objekt beim Aufruf übergeben. Entweder indirekt weil es ein Attribut der Klasse ist, oder direkt mit `functools.partial()` binden.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten