Tkinter Validierung eines Timecodes funktioniert nicht

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mrrockkz
User
Beiträge: 12
Registriert: Donnerstag 2. März 2023, 15:24

Hallo zusammen,

ich habe folgenden Code um nur die Eingabe eines gültigen Timecodes zu erlauben, jedoch kann ich den Doppelpunkt nicht selbst eingeben (was ich jedoch gerne tun würde). Sobald ich drei Zahlen eingebe und die dritte Zahl dadurch automatisch mit einem Doppelpunkt ersetzt wird, setzt die Validierung komplett aus und ich kann fortlaufend eintragen was ich will, weil die Validierung nicht mehr funktioniert. Worin kann der Fehler liegen?

Code: Alles auswählen

        runtime_label = tk.Label(metadata_window, text="Runtime (01:30:20:10):", background=GUI_BG_COLOR,
                                 foreground=GUI_TEXT_COLOR)
        runtime_label.pack(padx=0, pady=8)
        self.runtime_entry = tk.Entry(metadata_window, background="#333333", foreground=GUI_TEXT_COLOR, width=42,
                                      textvariable=runtime_var, validate="key")
        self.runtime_entry.pack()
        validate_runtime_entry_command = metadata_window.register(self.validate_runtime_entry)
        self.runtime_entry.config(validatecommand=(validate_runtime_entry_command, '%S'))


    def validate_runtime_entry(self, input):
        time_str = self.runtime_entry.get().strip()
        if input.isdigit() and len(time_str.replace(':', '')) < 8:
            # Add colon after every two digits
            if len(time_str.replace(':', '')) in [2, 4, 6]:
                self.runtime_entry.insert(len(time_str), ':')
            return True
        elif input == '\b':
            return True
        else:
            try:
                # Check format first
                datetime.datetime.strptime(time_str, '%H:%M:%S:%f')
                # Then check if it's a valid time
                h, m, s, f = map(int, time_str.split(':'))
                if not (0 <= h <= 23 and 0 <= m <= 59 and 0 <= s <= 59 and 0 <= f <= 47):
                    raise ValueError
                return True
            except ValueError:
                return False
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe da keine persönliche Erfahrung, aber was du da tust ist im Zweifel einfach illegal. Das system befindet sich gerade in einer validierung, und du hackst in der validierung neuen Inhalt rein, der dann eine validierung erfordert….

Laut https://anzeljg.github.io/rin2/book2/24 ... ation.html ging es ein invalidcommand, das explizit erlaub Änderungen zu machen, wenn die validierung daneben ging. Versuch deine doppelpunkterei darauf umzustellen.
mrrockkz
User
Beiträge: 12
Registriert: Donnerstag 2. März 2023, 15:24

__deets__ hat geschrieben: Mittwoch 5. April 2023, 09:18 Ich habe da keine persönliche Erfahrung, aber was du da tust ist im Zweifel einfach illegal. Das system befindet sich gerade in einer validierung, und du hackst in der validierung neuen Inhalt rein, der dann eine validierung erfordert….

Laut https://anzeljg.github.io/rin2/book2/24 ... ation.html ging es ein invalidcommand, das explizit erlaub Änderungen zu machen, wenn die validierung daneben ging. Versuch deine doppelpunkterei darauf umzustellen.
Danke. Selbst wenn ich die Ergänzung mit den Doppelpunkten aus dem Code entferne, funktioniert es nicht. Ich kann dann gar nichts mehr in das Feld eintippen.
Ich erkenne den Fehler leider nicht :cry:
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da du per key abfragst, kann man ja auch nie eine gueltige Eingabe machen. Du musst focusout benutzen.
mrrockkz
User
Beiträge: 12
Registriert: Donnerstag 2. März 2023, 15:24

__deets__ hat geschrieben: Donnerstag 6. April 2023, 10:08 Da du per key abfragst, kann man ja auch nie eine gueltige Eingabe machen. Du musst focusout benutzen.
Danke. Leider funktioniert das nicht, sobald es irgendwie "komplizierter wird". Mit "focusout" tut sich leider garnichts.

Nun habe ich es so gelöst.

Code: Alles auswählen

        creditstart_label = tk.Label(metadata_window, text="Creditstart (01:20:10:00):", background=GUI_BG_COLOR,
                                     foreground=GUI_TEXT_COLOR)
        creditstart_label.pack(padx=0, pady=8)
        self.creditstart_entry = tk.Entry(metadata_window, background="#333333", foreground=GUI_TEXT_COLOR, width=42,
                                          textvariable=creditstart_var, validate="key")
        self.creditstart_entry.pack()
        validate_creditstart_entry_command = metadata_window.register(self.validate_creditstart_entry)
        self.creditstart_entry.config(validatecommand=(validate_creditstart_entry_command, '%S'))

    @staticmethod
    def validate_runtime_entry(text):
        if text == "":
            return True

        allowed_chars = set(":0123456789")
        if set(text) <= allowed_chars:
            return True

        return False
Jedoch zerschießt es später das Programm sobald man ausversehen eine Ziffer zu viel oder zu wenig eingibt, da irgendwann die Doppelpunkte aufgelöst werden (sodass es noch 8 Ziffern sind) und in einem anderen Programm werden die Doppelpunkte wieder eingefügt - jedoch funktioniert das nicht zuverlässig bei einer Falscheingabe. Ich bekomme es leider überhaupt nicht gelöst und verzweifle daran. :cry:

Hat hier jemand evtl. einen anderen Lösungsansatz?
Benutzeravatar
__blackjack__
User
Beiträge: 13938
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`validate_runtime_entry()` ist recht kompliziert geschrieben. Was da letztlich gemacht wird ist das hier:

Code: Alles auswählen

    @staticmethod
    def validate_runtime_entry(text):
        return set(text) <= set(":0123456789")
Den ersten Test ob `text` leer ist, kann man sich sparen, weil der in dem Mengentest enthalten ist. Die leere Menge ist Teilmenge von jeder Menge.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
mrrockkz
User
Beiträge: 12
Registriert: Donnerstag 2. März 2023, 15:24

__blackjack__ hat geschrieben: Samstag 8. April 2023, 12:19 `validate_runtime_entry()` ist recht kompliziert geschrieben. Was da letztlich gemacht wird ist das hier:

Code: Alles auswählen

    @staticmethod
    def validate_runtime_entry(text):
        return set(text) <= set(":0123456789")
Den ersten Test ob `text` leer ist, kann man sich sparen, weil der in dem Mengentest enthalten ist. Die leere Menge ist Teilmenge von jeder Menge.
Danke dir, das macht das auf jeden Fall schöner :lol:
Löst leider mein Problem nicht ganz :(
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nachdem ich damit rumgespielt habe, bekomme ich tatsaechlich kein Rueckruf bei focusout. Womit das feature einfach am Arsch ist. Denn auf einzelner Tastendruck-Ebene kann man das nicht vernuenftig validieren. So aergerlich das ist. Dann bleibt wohl nur eine von zwei Moeglichkeiten:

- eigene Validierung, zB indem du einen Dialog machst, und beim "Ok" oder was auch immer die Aktion ist, die Werte pruefst, und dann die Weiterverarbeitung ablehnst, wenn das nicht die passende Eingabe enthaelt.
- Wechseln zu einem GUI-Toolkit, was das kann. Qt zB.
juwido
User
Beiträge: 24
Registriert: Donnerstag 15. Dezember 2022, 13:41

Hallo, ja, sollte einfacher sein, die Validierung im Anschluß an die Eingabe komplett in Python zu erledigen. Der Weg über die tcl-Methoden ist wohl nicht so gut von tkinter unterstützt.
Antworten