Geht validatecommand nicht?

Fragen zu Tkinter.
Antworten
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Der Benutzer soll nur gültige Zahlen in ein Entry eingeben können. Bei jedem Tastendruck soll das überprüft werden. Aber validatecommand funktioniert nicht richtig, denn wenn man da die Eingabe liest, ist diese noch gar nicht aktualisiert. Und auch mit einer Textvariablen funktioniert es nicht:

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

from functools import partial

class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.entry = tk.Entry(self,name='#0_entry',validate='key')
        self.entry.pack()

        self.entry.insert(0,1)
        self.entry['validatecommand'] = partial(self.validate,self.entry)

    def validate(self,entry):
        correct = False
        print(self.entry.get())
        try:
            float(self.entry.get())
            correct = True
        except:
            pass
        return correct
        
if __name__ == '__main__':
    Application().mainloop()
Was kann man da tun? Stattdessen ein bind auf <Key> und dann einen Hack mit after?
BlackJack

@Alfons Mittelmeyer: Man könnte in der Referenzdoku von New Mexico Tech nachsehen wie man der Validierungsfunktion/-methode weitere Informationen mitgeben lassen kann: http://infohost.nmt.edu/tcc/help/pubs/t ... ation.html
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack, danke. Ja, was man nocht nicht gemacht hat, weiß man eben manchmal nicht, dann wäre das wohl richtig, wenn es nur Integer sein sollen:

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

from functools import partial

class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.entry = tk.Entry(self,validate='key')
        self.entry.pack()

        # already defined somewhere else ==========
        self.entry.variable = tk.StringVar()
        self.entry.variable.set(1)
        self.entry['textvariable'] = self.entry.variable
        # ==========================================

        validate_command = self.entry.register(self.validate)
        self.entry['vcmd'] = (validate_command,'%P')

        invalidate_command = self.entry.register(self.invalidate)
        self.entry['invcmd'] = (invalidate_command,'%s','%W')

    def validate(self,value_after):
        correct = False
        try:
            a = float(value_after)
            b = int(value_after)
            if a == b:
                correct = True
        except ValueError:
            pass
        return correct
        
    def invalidate(self,value_before,widget_name):
        widgdet = self.nametowidget(widget_name)
        widgdet.variable.set(value_before)

if __name__ == '__main__':
    Application().mainloop()
Aber ganz stimmt es noch nicht. Die erste Ziffer zu ändern bereitet Probleme. Aber leer sollte es auch nicht sein. Da muß man noch überlegen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Naja, da muss man wohl auch leer zulassen und später dann als 0 interpretieren:

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

from functools import partial

class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.entry = tk.Entry(self,validate='key')
        self.entry.pack()

        # already defined somewhere else ==========
        self.entry.variable = tk.StringVar()
        self.entry.variable.set(1)
        self.entry['textvariable'] = self.entry.variable
        # ==========================================

        validate_command = self.entry.register(self.validate)
        self.entry['vcmd'] = (validate_command,'%P')

        invalidate_command = self.entry.register(self.invalidate)
        self.entry['invcmd'] = (invalidate_command,'%s','%W')

    def validate(self,value_after):
        correct = False
        try:
            if not value_after:
                correct = True
            else:
                a = float(value_after)
                b = int(value_after)
                if a == b:
                    correct = True
        except ValueError:
            pass
        return correct
        
    def invalidate(self,value_before,widget_name):
        widgdet = self.nametowidget(widget_name)
        widgdet.variable.set(value_before)


if __name__ == '__main__':
    Application().mainloop()
Nummer_42O
User
Beiträge: 4
Registriert: Samstag 21. September 2019, 14:37

Ich weiß nicht, was jetzt mit den letzten Paar Codeschnipseln passiert ist, die wir zu sehen bekamen, aber mein Lösungsvorschlag wäre folgender:

Code: Alles auswählen

# -*- coding: utf-8 -*-

try:
    from tkinter import *
except ImportError:
    from Tkinter import *

class Application(Tk):
    def __init__(self,**kwargs):
        Tk.__init__(self,**kwargs)
        self.entry=Entry(self,name='#0_entry',validate='key',vcmd=(self.register(self.validate),'%d','%P'),invcmd=self.bell)
        self.entry.pack()
        self.entry.insert(0,1)
    def validate(self,mode,value):
        if mode!=1: return False
        try:
            float(value)
            return True
        except: return False
        
if __name__ == '__main__':
    Application().mainloop()
Nummer_42O
User
Beiträge: 4
Registriert: Samstag 21. September 2019, 14:37

Nummer_42O hat geschrieben: Samstag 21. September 2019, 14:44

Code: Alles auswählen

        if mode!=1: return False
Pardon, das müsste

Code: Alles auswählen

if mode!=1: return True
sein, da beim löschen ja nix überprüft werden muss, weil nix hinzu kommt.
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Nummer_42O: Durch das löschen kann die Eingabe aber auch ungültig werden. "1e2" wird Beispielsweise ungültig wenn man die "1" oder die "2" entfernt, oder ".5" wird ungültig wenn man die "5" entfernt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten