Home > other >  Passing args to Tkinter Callback validating function in Python3, Is it possible?
Passing args to Tkinter Callback validating function in Python3, Is it possible?

Time:09-17

I am a newbie on Python3 and trying tkinter for first time, I recently answered to enter image description here

that ask for inputs.

first 3 Entry row are validated by callback_int that allows only int digits while last 2 Entry rows use callback_str that allow both floats like 1.5 or 0.5 and fractions like 1/7 or 5/7.

My question (sorry it took so long) is:

is there a way to pass function arguments to callback like callback(typez = str) so that I could shorten my code using only one callback function that acts differently for my int and string values ? If I use reg_int = mainwindow.register(callback_int(input,typez='popo')) I got

line ...
if input.isdigit():

AttributeError: 'function' object has no attribute 'isdigit'

I am guessin the problem is in :

reg_int = mainwindow.register(callback_int(input,typez='popo')) #AttributeError: 'function' object has no attribute 'isdigit'
reg_str = mainwindow.register(callback_str('pipi'))

but wasnt able to find anythiong useful , or maybe my approach is in the wrong direction

CodePudding user response:

This uses the lambda statement to pass either "str" or "int" to the typez argument in callback(), so that callback() knows what type the input is. Here is the full code based on my first comment above:

import tkinter as tk
from tkinter import IntVar,StringVar

###############################################################################
def callback(input,typez=None):
    
    if typez == "int":
        if input.isdigit():
            # print(input)
            return True
                            
        elif input == "":
            # print(input)
            return True
    
        else:
            print(input)
            return False

    if typez == "str":
        if len(input) >=1  and input[0] == '/':
            return False
        
        if all([s.isdigit() or s =='/' for s in input]) and input.count('/') <= 1:
            # print([s.isdigit() or s =='/' for s in input])
            # print(input)
            return True
                            
        elif all([s.isdigit() or s =='.' for s in input]) and input.count('.') <= 1:
            # print([s.isdigit() or s =='.' for s in input])
            # print(input)
            return True

        else:
            print('no valid input : ',input)
            return False

def mainwindow():

    mainwindow = tk.Tk()
    mainwindow.geometry('350x350')
    
    tk.Label(mainwindow, text="enter parameters below").grid(row=1)
    
    getN = IntVar()
    geti0 = IntVar()
    getr0 = IntVar()
    getbeta = StringVar(mainwindow, value='0')
    getgamma = StringVar(mainwindow, value='0')

    tk.Label(mainwindow, text="N").grid(row=2)
    tk.Label(mainwindow, text="i0").grid(row=3)
    tk.Label(mainwindow, text="r0").grid(row=4)
    tk.Label(mainwindow, text="beta").grid(row=5)
    tk.Label(mainwindow, text="gamma").grid(row=6)
    
    e1 = tk.Entry(mainwindow,textvariable = getN)
    e1.grid(row=2, column=1)
    e2 = tk.Entry(mainwindow,textvariable = geti0)
    e2.grid(row=3, column=1)
    e3 = tk.Entry(mainwindow,textvariable = getr0)
    e3.grid(row=4, column=1)
    e4 = tk.Entry(mainwindow,textvariable = getbeta)
    e4.grid(row=5, column=1)
    e5 = tk.Entry(mainwindow,textvariable = getgamma)
    e5.grid(row=6, column=1)
    
    reg_int = mainwindow.register(lambda input, typez="int": callback(input, typez=typez))
    reg_str = mainwindow.register(lambda input, typez="str": callback(input, typez=typez))
    
    
    e1.config(validate ="key", validatecommand =(reg_int, '%P'))
    e2.config(validate ="key", validatecommand =(reg_int, '%P'))
    e3.config(validate ="key", validatecommand =(reg_int, '%P'))
    e4.config(validate ="key", validatecommand =(reg_str, '%P'))
    e5.config(validate ="key", validatecommand =(reg_str, '%P'))
    
    solve = tk.Button(mainwindow, text='solve!', command=lambda: [values()]).grid(row=7, column=1, sticky=tk.W, pady=4)
 
    
    def values():
        
        readN = getN.get()
        readi0 = geti0.get()
        readr0 = getr0.get()
        readbeta = eval(getbeta.get(),{"builtins": {}})
        readgamma = eval(getgamma.get(), {"builtins": {}})
        

        
        intN = int(readN)
        inti0 = int(readi0)
        intr0 = int(readr0)
        intbeta = float(readbeta)
        intgamma = float(readgamma)
        
        
        print(intN,'\n',inti0,'\n',intr0,'\n',intbeta,'\n',intgamma)

    
 
    mainwindow.mainloop()
    
mainwindow()

CodePudding user response:

Hi thanks to the mysterious poster that deleted a very well explained answer (Bryan Oakley) I was able to provide another way to solve my problem . Here is the code:

import tkinter as tk
from tkinter import IntVar,StringVar

###############################################################################

def callback(input,typez=None):
    
    if typez == "int":
        if input.isdigit():
            # print(input)
            return True
                            
        elif input == "":
            # print(input)
            return True
    
        else:
            print(input)
            return False

    if typez == "str":
        if len(input) >=1  and input[0] == '/':
            return False
        
        if all([s.isdigit() or s =='/' for s in input]) and input.count('/') <= 1:
            # print([s.isdigit() or s =='/' for s in input])
            # print(input)
            return True
                            
        elif all([s.isdigit() or s =='.' for s in input]) and input.count('.') <= 1:
            # print([s.isdigit() or s =='.' for s in input])
            # print(input)
            return True

        else:
            print('no valid input : ',input)
            return False

def mainwindow():

    mainwindow = tk.Tk()
    mainwindow.geometry('350x350')
    
    tk.Label(mainwindow, text="enter parameters below").grid(row=1)
    
    getN = IntVar()
    geti0 = IntVar()
    getr0 = IntVar()
    getbeta = StringVar(mainwindow, value='0')
    getgamma = StringVar(mainwindow, value='0')

    tk.Label(mainwindow, text="N").grid(row=2)
    tk.Label(mainwindow, text="i0").grid(row=3)
    tk.Label(mainwindow, text="r0").grid(row=4)
    tk.Label(mainwindow, text="beta").grid(row=5)
    tk.Label(mainwindow, text="gamma").grid(row=6)
    
    e1 = tk.Entry(mainwindow,textvariable = getN)
    e1.grid(row=2, column=1)
    e2 = tk.Entry(mainwindow,textvariable = geti0)
    e2.grid(row=3, column=1)
    e3 = tk.Entry(mainwindow,textvariable = getr0)
    e3.grid(row=4, column=1)
    e4 = tk.Entry(mainwindow,textvariable = getbeta)
    e4.grid(row=5, column=1)
    e5 = tk.Entry(mainwindow,textvariable = getgamma)
    e5.grid(row=6, column=1)
    
    reg_int = mainwindow.register(callback) 
    reg_str = mainwindow.register(callback)
    
    
    e1.config(validate ="key", validatecommand =(reg_int, '%P', 'int'))
    e2.config(validate ="key", validatecommand =(reg_int, '%P', 'int'))
    e3.config(validate ="key", validatecommand =(reg_int, '%P', 'int'))
    e4.config(validate ="key", validatecommand =(reg_str, '%P', 'str'))
    e5.config(validate ="key", validatecommand =(reg_str, '%P', 'str'))
    
    solve = tk.Button(mainwindow, text='solve!', command=lambda: [values()]).grid(row=7, column=1, sticky=tk.W, pady=4)
 
    
    def values():
        
        readN = getN.get()
        readi0 = geti0.get()
        readr0 = getr0.get()
        readbeta = eval(getbeta.get(),{"builtins": {}})
        readgamma = eval(getgamma.get(), {"builtins": {}})
        

        
        intN = int(readN)
        inti0 = int(readi0)
        intr0 = int(readr0)
        intbeta = float(readbeta)
        intgamma = float(readgamma)
        
        
        print(intN,'\n',inti0,'\n',intr0,'\n',intbeta,'\n',intgamma)

    
 
    mainwindow.mainloop()
    
mainwindow()

It doesnt use lambda, but just passes the arg as in https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/entry-validation.html :

To set up this callback, you would use these two options in the Entry constructor:

self.w = Entry(self, validate='all',validatecommand=(okayCommand, '%d', '%i', '%S'), ... here  my extra args ...)

Like:

e1.config(validate ="key", validatecommand =(reg_int, '%P', 'int'))
e2.config(validate ="key", validatecommand =(reg_int, '%P', 'int'))
e3.config(validate ="key", validatecommand =(reg_int, '%P', 'int'))
e4.config(validate ="key", validatecommand =(reg_str, '%P', 'str'))
e5.config(validate ="key", validatecommand =(reg_str, '%P', 'str'))
  • Related