不理解Tkinter输入框验证

3
我有一个带有输入框的 tkinter GUI,我想只允许输入数字。能否有人解释一下验证(validation)中每个命令/代码行的含义?我不理解 vcmd 变量及其它的'%i' '%s'是什么意思。谢谢 :)
更新: 我要在另一个应用程序中使用这个 vcmd 命令,但并不完全理解它。以下是我的验证代码:
def validate(self, action, index, value_if_allowed, prior_value, text, validation_type, trigger_type, widget_name):
    if not int(action):
        return True
    elif text in '0123456789.-+':
        try:
            float(value_if_allowed)
            return True
        except ValueError:
            return False
    else:
        return False

我不明白为什么在这段代码中我需要所有这些内容:
action, index, value_if_allowed, prior_value, text, validation_type, trigger_type, widget_name

为什么我需要这些特定的验证代码才能使其正确运行,它们有什么用处? 您提供的文档很有道理,但是对于我特定的代码来说,一些'%s','%i'之类的东西似乎是不必要的,但只有包含所有这些内容它才能正常工作:

vcmd = (self.master.register(self.validate), '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')

我也想知道self.master.register的作用,请问您能解释一下吗?我还是不太明白。

我现在正在使用我更新的问题中的示例。它可以工作,所以我不想去碰它,但是它需要所有的参数0.o。 - Tweakforce_LG
1个回答

11

如果您不需要任何特殊参数,则无需调用register。例如,以下代码将在没有任何参数的情况下正确调用do_validation

如果您不需要任何特殊参数,则无需调用register。例如,以下代码将在没有任何参数的情况下正确调用do_validation
import tkinter as tk

def do_validation():
    value = entry.get()
    if value == "" or value.isnumeric():
        return True
    return False

root = tk.Tk()
entry = tk.Entry(root, validate='key', validatecommand=do_validation)
entry.pack(fill="x", padx=20, pady=20)

root.mainloop()

然而,在上述情况下,验证将始终落后于一个字符。这是因为验证发生在字符被插入到输入部件之前(即第一次调用时,entry.get()将返回一个空字符串)。整个验证的意义在于防止非法字符,因此在字符插入之前调用命令而不是之后是有意义的。

这就是为什么特殊参数很有用——它们提供足够的上下文信息,以便在将字符或字符插入到部件之前决定其是否合法。

register如何有用

Tkinter是Tcl解释器的包装器,因为tk(tkinter背后的核心技术)是用Tcl实现的。 Tcl和Python一样也是一种编程语言。

在Tcl程序中,您可以像这样使用验证功能:

proc do_validation(new_value) {
    return $new_value == "" || [string is integer $new_value]
}
entry .entry -validate key --validatecommand [list do_validation %P]
当Tcl检测到更改时,它会对参数执行替换,然后使用替换后的参数调用定义的过程。例如,如果您键入"A",则%P将转换为"A",函数将使用"A"作为唯一参数调用。
在Tkinter中,没有直接相关的方法来定义带有运行时替换参数的函数。
不幸的是,tkinter包中的验证功能实现得不太好,因此要正确使用验证,我们必须使用一个小技巧以便把这些特殊参数传递给我们的函数。 register的功能是创建一个新的Tcl命令,该命令调用您的Python命令,同时创建一个新的Python命令,该命令是对这个新的Tcl命令的引用。您可以像使用任何其他Python命令一样使用这个引用。
一个简单的例子
在最简单的情况下,您只需要知道如果允许进行编辑,那么字符串看起来会是什么样子。您可以决定编辑是否会导致有效输入,或者是否会导致无效输入。如果编辑不能产生有效的输入,您可以在实际发生之前拒绝此次编辑。
表示允许编辑的特殊参数是%P 1。我们可以修改注册的函数来接受这个参数,并在注册时添加这个参数。
def do_validation(new_value):
    return new_value == "" or new_value.isnumeric()

...
vcmd = (root.register(do_validation), '%P')
entry = tk.Entry(..., validatecommand=vcmd)

因此,当基础的Tcl代码检测到更改时,它将调用新创建的Tcl命令,并传入一个参数,对应于特殊的%P替换。


1关于所有验证机制的详细说明在这里的tcl文档中进行了全面描述:http://tcl.tk/man/tcl8.5/TkCmd/entry.htm#M7


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接