I am a newbie on Python3 and trying tkinter for first time, I recently answered to
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'))