交互验证tkinter中的条目小部件内容

2024-05-15 15:56:04 发布

您现在位置:Python中文网/ 问答频道 /正文

在tkinterEntry小部件中交互式验证内容的推荐技术是什么

我已经阅读了关于使用validate=Truevalidatecommand=command的帖子,这些特性似乎受到限制,因为如果validatecommand命令更新Entry小部件的值,它们就会被清除

考虑到这种行为,我们是否应该绑定KeyPressCutPaste事件,并通过这些事件监视/更新Entry小部件的值?(以及我可能错过的其他相关事件?)

或者我们应该完全忘记交互验证而只对FocusOut事件进行验证吗


Tags: 命令true内容部件事件特性validate技术
3条回答

在研究和实验了Bryan的代码之后,我制作了一个输入验证的最小版本。以下代码将显示一个输入框,只接受数字

from tkinter import *

root = Tk()

def testVal(inStr,acttyp):
    if acttyp == '1': #insert
        if not inStr.isdigit():
            return False
    return True

entry = Entry(root, validate="key")
entry['validatecommand'] = (entry.register(testVal),'%P','%d')
entry.pack()

root.mainloop()

也许我应该补充一点,我仍然在学习Python,我很乐意接受任何和所有的评论/建议

使用Tkinter.StringVar跟踪Entry小部件的值。您可以通过在StringVar上设置trace来验证该值

下面是一个简短的工作程序,它只接受Entry小部件中的有效浮动

try:
    from tkinter import *
except ImportError:
    from Tkinter import *  # Python 2


root = Tk()
sv = StringVar()

def validate_float(var):
    new_value = var.get()
    try:
        new_value == '' or float(new_value)
        validate_float.old_value = new_value
    except:
        var.set(validate_float.old_value)

validate_float.old_value = ''  # Define function attribute.

# trace wants a callback with nearly useless parameters, fixing with lambda.
sv.trace('w', lambda nm, idx, mode, var=sv: validate_float(var))
ent = Entry(root, textvariable=sv)
ent.pack()
ent.focus_set()

root.mainloop()

正确答案是,使用小部件的validatecommand属性。不幸的是,这个特性在Tkinter世界中的文档记录严重不足,尽管在Tk世界中的文档记录相当充分。即使它没有很好的文档记录,它也具备了进行验证所需的一切,而无需借助绑定或跟踪变量,也无需在验证过程中修改小部件

诀窍是让Tkinter将特殊值传递给validate命令。这些值为您提供了决定数据是否有效所需的所有信息:编辑前的值、编辑后的值(如果编辑有效)以及其他一些信息。不过,要使用这些命令,您需要执行一些巫术操作,以将这些信息传递给validate命令

注意:validation命令返回TrueFalse非常重要。任何其他操作都会导致关闭小部件的验证

下面是一个只允许小写的示例。为了便于说明,它还打印所有特殊值的值。它们并不都是必要的;你很少需要超过一两个

import tkinter as tk  # python 3.x
# import Tkinter as tk # python 2.x

class Example(tk.Frame):

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        # valid percent substitutions (from the Tk entry man page)
        # note: you only have to register the ones you need; this
        # example registers them all for illustrative purposes
        #
        # %d = Type of action (1=insert, 0=delete, -1 for others)
        # %i = index of char string to be inserted/deleted, or -1
        # %P = value of the entry if the edit is allowed
        # %s = value of entry prior to editing
        # %S = the text string being inserted or deleted, if any
        # %v = the type of validation that is currently set
        # %V = the type of validation that triggered the callback
        #      (key, focusin, focusout, forced)
        # %W = the tk name of the widget

        vcmd = (self.register(self.onValidate),
                '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
        self.entry = tk.Entry(self, validate="key", validatecommand=vcmd)
        self.text = tk.Text(self, height=10, width=40)
        self.entry.pack(side="top", fill="x")
        self.text.pack(side="bottom", fill="both", expand=True)

    def onValidate(self, d, i, P, s, S, v, V, W):
        self.text.delete("1.0", "end")
        self.text.insert("end","OnValidate:\n")
        self.text.insert("end","d='%s'\n" % d)
        self.text.insert("end","i='%s'\n" % i)
        self.text.insert("end","P='%s'\n" % P)
        self.text.insert("end","s='%s'\n" % s)
        self.text.insert("end","S='%s'\n" % S)
        self.text.insert("end","v='%s'\n" % v)
        self.text.insert("end","V='%s'\n" % V)
        self.text.insert("end","W='%s'\n" % W)

        # Disallow anything but lowercase letters
        if S == S.lower():
            return True
        else:
            self.bell()
            return False

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

有关调用register方法时引擎盖下发生的情况的更多信息,请参阅Why is calling register() required for tkinter input validation?

有关规范文档,请参见Validation section of the Tcl/Tk Entry man page

相关问题 更多 >