将 args 传递给 Python3 中的 Tkinter 回调验证函数,这可能吗?

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

我是 Python3 的新手,第一次尝试 tkinter,我最近回答了 using https://www.geeksforgeeks.org/python-tkinter-validating-entry-widget/ 提示。

现在我正在思考 reg_str = mainwindow.register(callback_str)e4.config(validate ="key", validatecommand =(reg_str, '%P')) 的工作原理。

我用谷歌搜索并尝试在 Whosebug 上搜索,但找不到答案,

下面是我的最小可重现示例:

import tkinter as tk
from tkinter import IntVar,StringVar

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

def callback_str(input, typez=None):
    
    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_int)
    reg_str = mainwindow.register(callback_str)
    
    
    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()

程序打开一个小部件:

要求输入。

前 3 个条目行由 callback_int 验证,仅允许 int 数字,而最后 2 个条目行使用 callback_str 允许浮点数(如 1.5 或 0.5)和分数(如 1/7 或 5/) 7.

我的问题(抱歉拖了这么久)是:

有没有办法像 callback(typez = str) 一样将函数参数传递给 callback 这样我就可以仅使用一个回调函数来缩短我的代码,该回调函数对我的 int 和 string 值有不同的作用?如果我使用 reg_int = mainwindow.register(callback_int(input,typez='popo')) 我得到

line ...
if input.isdigit():

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

我猜问题出在:

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

但找不到任何有用的东西,或者我的方法方向错误

这使用 lambda 语句将 "str""int" 传递给 callback() 中的 typez 参数,因此 callback()知道 input 是什么类型。这是基于我上面第一条评论的完整代码:

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()

您好,感谢神秘的发帖者删除了一个解释得很好的答案 (Bryan Oakley),我能够提供另一种方法来解决我的问题。这是代码:

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()

它不使用 lambda,只是像 https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/entry-validation.html 那样传递 arg :

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 ...)

喜欢:

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'))