Cómo pasar un valor a una entrada validatecommand

Sep 15 2020

Estoy validando un formulario en tkinter usando validatecommand. Hay dos entradas, una solo debe aceptar números enteros y la otra flota.
Aquí está el código básico:

import tkinter as tk
class Form(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        validCmd1 = (self.register(self.val1), "%P")
        validCmd2 = (self.register(self.val2), "%P")
        self.lab1 = tk.Label(self, text = "Float:")
        self.lab1.grid(row = 1, column = 0, padx = 10, pady = 10)
        self.ent1 = tk.Entry(self, validate = "key", validatecommand = validCmd1)
        self.ent1.grid(row = 1, column = 1)
        self.lab2 = tk.Label(self, text = "Integer:")
        self.lab2.grid(row = 2, column = 0, padx = 10, pady = (0,10))
        self.ent2 = tk.Entry(self, validate = "key", validatecommand = validCmd2)
        self.ent2.grid(row = 2, column = 1)
    def val1(self, value):
        try:
            float(value)
        except:
            return False
        else:
            return True
    def val2(self, value):
        try:
            int(value)
        except:
            return False
        else:
            return True
app = Form()
app.mainloop()

En lugar de escribir dos funciones diferentes para dos tareas muy similares, intenté pasar un número entero al comando de validación (1 para flotante, 2 para entero). Intenté usar lambdas para pasar valores a las funciones de validación, primero en la parte self.register: self.register(lambda: self.val1(1))pero esto dio TypeError: <lambda>() takes 0 positional arguments but 1 was giveny la segunda vez intenté usar lambda en el comando validatecommand: validatecommand = lambda: validCmd1(1)que da TypeError: 'tuple' object is not callable.
¿Es posible pasar valores a un comando de validación?

Respuestas

1 BryanOakley Sep 15 2020 at 20:31

La validatecommandopción toma una tupla que puede tener los argumentos que desee. Por ejemplo, si desea pasar un número entero, es tan fácil como esto:

validCmd1 = (self.register(self.val), 1, "%P")
validCmd2 = (self.register(self.val), 2, "%P")

def val(self, arg, value):
    print(f"val1 arg='{arg}' value='{value}'")
    ...

A veces es más fácil de entender si separa el registro del comando del valor pasado a validatecommand. Por ejemplo:

vcmd = self.register(self.val)
...
self.ent1 = tk.Entry(..., validatecommand = (vcmd, 1, "%P"))
self.ent2 = tk.Entry(..., validatecommand = (vcmd, 2, "%P"))