为什么 tkinter 输入验证需要调用 register()?

lea*_*ner 6 tkinter python-3.x

def check_the_input_only_allows_digits_only(inp):
    # A function for validating the input, the purpose of this is to let
    # the user enter only digits.
    if inp.isdigit() or inp is "" or inp == "\b" or inp is None:
        return True
    else:
        return False


reg = creditor.register(check_the_input_only_allows_digits_only)
amount.config(validate = "key",validatecommand =  (reg,"%P"))
Run Code Online (Sandbox Code Playgroud)

我知道该函数 check_the_input_only_allows_digits_only已注册,并且对于用户输入的每个字符,都会调用该函数并验证输入。但是为什么每次用户输入内容时.register都不能调用该函数.register?引擎盖下到底发生了什么?

Bry*_*ley 10

要知道的重要一点是,Tkinter 只是一个围绕嵌入式 Tcl 解释器的薄包装。这意味着由于两种语言的根本差异,有时会有一些小的妥协。

Tcl方式

在 Tcl 中进行输入验证时,您指定一个 Tcl 脚本而不仅仅是一个可调用的函数。TCL将扫描特殊字符序列的代码(例如%P%S等),与信息代替它们有关要验证的数据。

用 Tcl 编写时,您的代码可能如下所示:

entry .amount -validate key -validatecommand {
    expr {[string is int %P] || [string length %P]==0}
}
Run Code Online (Sandbox Code Playgroud)

或者,使用 Tcl 函数:

proc check_the_input_only_allows_digits_only {P} {
    expr {[string is int P] || [string length P] == 0}
}
entry .amount \
    -validate key \
    -validatecommand {check_the_input_only_allows_digits_only %P}
Run Code Online (Sandbox Code Playgroud)

Python方式

Python 没有一种简单的方法可以将代码作为字符串传递,即使它这样做了 Tcl 也不会理解它。相反,在 python 中,您必须传递对可调用对象的引用——通常是对函数或方法的引用。

为了在 python 需要可调用的地方传递那些特殊的替换字符,您必须创建一个 Tcl 过程作为您的 python 函数的代理。该命令是在调用register函数时创建的。

proc = creditor.register(check_the_input_only_allows_digits_only)
amount.config(validate = "key", validatecommand =  (proc,"%P"))
Run Code Online (Sandbox Code Playgroud)

如果不使用这些字符,则不需要注册命令。例如,以下代码是调用不带参数的函数的有效方法:

def check_the_input_only_allows_digits_only():
    ...
amount.config(validate = "key",validatecommand = check_the_input_only_allows_digits_only)
Run Code Online (Sandbox Code Playgroud)

当然,传递值%P和其他特殊字符序列是验证功能如此强大的原因。