在tkinter 条目
小部件中,用于交互式验证内容的推荐技术是什么?
我已经阅读了有关使用 validate = true
和 validateCommand =命令
的帖子,并且看来这些功能受到> 的清除的限制。 valialatecommand
命令更新条目
widget的值。
鉴于此行为,我们应该在 KeyPress
,剪切
和粘贴
事件并进行监视/更新我们的条目
的情况下绑定。小部件通过这些事件的价值? (以及我可能错过的其他相关事件?)
还是我们应该完全忘记交互式验证,仅在 focus> focusOut
事件上验证?
What is the recommended technique for interactively validating content in a tkinter Entry
widget?
I've read the posts about using validate=True
and validatecommand=command
, and it appears that these features are limited by the fact that they get cleared if the validatecommand
command updates the Entry
widget's value.
Given this behavior, should we bind on the KeyPress
, Cut
, and Paste
events and monitor/update our Entry
widget's value through these events? (And other related events that I might have missed?)
Or should we forget interactive validation altogether and only validate on FocusOut
events?
发布评论
评论(11)
正确的答案是,使用小部件的
validatecommand
属性。不幸的是,在TKINTER世界中,此功能在TK World中已足够充分记录在TKInter世界中。即使没有很好地记录下来,它也需要您需要进行验证的一切,而无需求绑定或跟踪变量,或者从验证过程中修改小部件。诀窍是要知道您可以将tkinter传递给您的validate命令。这些值为您提供了所有您需要了解的信息,以决定数据是否有效:编辑之前的值,如果编辑有效,则编辑后的值以及其他几个信息。但是,要使用这些这些信息,您需要做一点伏都教才能将此信息传递给您的validate命令。
注意:验证命令返回
true
或false
很重要。其他任何事情都会导致小部件关闭验证。这是一个只允许小写的示例。它还以说明性目的打印所有特殊值的值。他们并不是所有必要的;您很少需要一两个以上。
有关
寄存器
方法时发生的事情的更多信息,请参见 tkinter输入验证需要调用寄存器()?有关规范文档的信息,请参见 tcl/tk入门人页面的验证部分
The correct answer is, use the
validatecommand
attribute of the widget. Unfortunately this feature is severely under-documented in the Tkinter world, though it is quite sufficiently documented in the Tk world. Even though it's not documented well, it has everything you need to do validation without resorting to bindings or tracing variables, or modifying the widget from within the validation procedure.The trick is to know that you can have Tkinter pass in special values to your validate command. These values give you all the information you need to know to decide on whether the data is valid or not: the value prior to the edit, the value after the edit if the edit is valid, and several other bits of information. To use these, though, you need to do a little voodoo to get this information passed to your validate command.
Note: it's important that the validation command returns either
True
orFalse
. Anything else will cause the validation to be turned off for the widget.Here's an example that only allows lowercase. It also prints the values of all of the special values for illustrative purposes. They aren't all necessary; you rarely need more than one or two.
For more information about what happens under the hood when you call the
register
method, see Why is calling register() required for tkinter input validation?For the canonical documentation see the Validation section of the Tcl/Tk Entry man page
在研究和实验Bryan的代码之后,我产生了最少的输入验证版本。以下代码将放置一个入口框,仅接受数字数字。
也许我应该补充说,我仍在学习Python,我会很乐意接受所有评论/建议。
After studying and experimenting with Bryan's code, I produced a minimal version of input validation. The following code will put up an Entry box and only accept numeric digits.
Perhaps I should add that I am still learning Python and I will gladly accept any and all comments/suggestions.
使用
tkinter.stringvar
来跟踪条目
widget的值。您可以通过在其上设置trace
来验证StringVar
的值。这是一个简短的工作程序,它仅接受
条目
widget中的有效浮子。Use a
Tkinter.StringVar
to track the value of theEntry
widget. You can validate the value of theStringVar
by setting atrace
on it.Here's a short working program that accepts only valid floats in the
Entry
widget.布莱恩的答案是正确的,但是没有人提到tkinter小部件的“无效”属性。
一个很好的解释在这里:
在损坏链接的情况下,文本复制/粘贴,
条目窗口部门还支持一个无效的选项,该选项指定每当有valialateCommand返回false时指定调用的回调函数。此命令可以通过使用小部件关联的文本变量上的.set()方法来修改小部件中的文本。设置此选项与设置ValidateCommand相同。您必须使用.register()方法包装python函数;此方法将包装函数的名称返回为字符串。然后,您将作为该字符串或包含替换代码的元组的第一个元素作为InvalidCommand选项的值传递。
注意:
我只有一件事我无法弄清楚如何做:如果将验证添加到条目中,并且用户选择了部分文本并键入新值,则无法捕获原始值并重置条目。这是一个示例
Bryan's answer is correct, however no one mentioned the 'invalidcommand' attribute of the tkinter widget.
A good explanation is here:
http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html
Text copy/pasted in case of broken link
The Entry widget also supports an invalidcommand option that specifies a callback function that is called whenever the validatecommand returns False. This command may modify the text in the widget by using the .set() method on the widget's associated textvariable. Setting up this option works the same as setting up the validatecommand. You must use the .register() method to wrap your Python function; this method returns the name of the wrapped function as a string. Then you will pass as the value of the invalidcommand option either that string, or as the first element of a tuple containing substitution codes.
Note:
There is only one thing that I cannot figure out how to do: If you add validation to an entry, and the user selects a portion of the text and types a new value, there is no way to capture the original value and reset the entry. Here's an example
定义返回布尔值的函数,该功能指示输入是否有效。
将其注册为TCL回调,然后将回调名称传递给窗口小部件,以
valialateTecommand
。例如:
Define a function returning a boolean that indicates whether the input is valid.
Register it as a Tcl callback, and pass the callback name to the widget as a
validatecommand
.For example:
Reference.
在研究 Bryan Oakley的答案时,有些事情告诉我,可以开发更一般的解决方案。以下示例介绍了用于验证目的的模式枚举,类型词典和设置功能。参见第48行,例如用法及其简单性的演示。
While studying Bryan Oakley's answer, something told me that a far more general solution could be developed. The following example introduces a mode enumeration, a type dictionary, and a setup function for validation purposes. See line 48 for example usage and a demonstration of its simplicity.
如果要同时设置数字和最大字符,则此代码可以提供帮助。
This code can help if you want to set both just digits and max characters.
这是@Steven Rumbalski的答案 验证 entrac> widget值,通过追踪到
StringVar
- 我已经通过将其编辑到位,在某种程度上进行了调试并改进。下面的版本将所有内容都放入
stringvar
subclass 以封装更好的事情,更重要的是,允许同一时间同时存在多个独立实例,而不会彼此干扰 - 他的实现一个潜在的问题,因为它利用函数属性而不是实例属性,这些属性与全局变量基本相同,并且在这种情况下可能会导致问题。Here's an improved version of @Steven Rumbalski's answer of validating the
Entry
widgets value by tracing changes to aStringVar
— which I have already debugged and improved to some degree by editing it in place.The version below puts everything into a
StringVar
subclass to encapsulates what's going on better and, more importantly allow multiple independent instances of it to exist at the same time without interfering with each other — a potential problem with his implementation because it utilizes function attributes instead of instance attributes, which are essentially the same thing as global variables and can lead to problems in such a scenario.响应 ORIONROBERT的问题 处理简单验证文本替代文本,而不是单独的删除或插入:
将选定文本的替换作为删除处理,然后插入。例如,当删除应将光标移动到左侧时,这可能会导致问题,而替换应将光标移动到右侧。幸运的是,这两个过程彼此之间立即执行 。
因此,我们可以区分删除本身和直接删除,然后直接删除由于替换而引起的插入,因为后者没有改变删除和插入之间的空闲标志。
使用替代品和
widget.after_idle()
来利用这。after_idle()
在事件队列结束时执行lambda功能:当然,在替换后,在验证删除部分时,仍然不知道插入是否会遵循。
幸运的是,有:
.set()
,.icursor()
,.index(sel_first)
,.index(sel_last)
,.index(insert)
,我们可以追溯地实现最期望的行为(因为我们的新替代品与插入的结合是一个新的独特事件。
Responding to orionrobert's problem of dealing with simple validation upon substitutions of text through selection, instead of separate deletions or insertions:
A substitution of selected text is processed as a deletion followed by an insertion. This may lead to problems, for example, when the deletion should move the cursor to the left, while a substitution should move the cursor to the right. Fortunately, these two processes are executed immediately after one another.
Hence, we can differentiate between a deletion by itself and a deletion directly followed by an insertion due to a substitution because the latter has does not change the idle flag between deletion and insertion.
This is exploited using a substitutionFlag and a
Widget.after_idle()
.after_idle()
executes the lambda-function at the end of the event queue:Of course, after a substitution, while validating the deletion part, one still won’t know whether an insert will follow.
Luckily however, with:
.set()
,.icursor()
,.index(SEL_FIRST)
,.index(SEL_LAST)
,.index(INSERT)
,we can achieve most desired behavior retrospectively (since the combination of our new substitutionFlag with an insertion is a new unique and final event.