问题描述
我希望用户能够在 Spinbox 小部件中输入一个整数值.如果输入的值不是整数或超出 Spinbox 限制的整数,一旦 Spinbox 失去焦点,Spinbox 内容中的值必须恢复为默认值.
I want the user to be able to enter an integer value in the Spinbox widget. If the value entered is not an integer or is an integer outside the Spinbox limits, as soon as the Spinbox loses focus, the value in the Spinbox's content must revert to a default value.
在示例代码中,我使用 Entry 小部件只是因为 Spinbox 可能会失去焦点.
In the example code, I use the Entry widget just for the Spinbox can lose focus.
如果用户返回 Spinbox 输入新值,则不会验证其输入.我在 交互式验证 tkinter 中的 Entry 小部件内容 中确认了马尔科姆的评论,即validatecommand=command
一旦此命令更新小部件的值,特性就会被清除.
If the user comes back to Spinbox to enter a new value, his entry is not validated.I confirm Malcolm's remark in Interactively validating Entry widget content in tkinter that the validatecommand=command
feature gets cleared as soon as this command updates the widget's value.
有没有办法让在 Spinbox 中输入的值重复验证而不仅仅是一次?
Is there a way to get the value entered in the Spinbox repeatedly validated and not just once?
from tkinter import *
class GUI:
def __init__(self):
# root window of the whole program
self.root = Tk()
self.root.title('Validate Spinbox')
# registering validate and invalid commands
validate_cmd = (self.root.register(self.validate), '%P')
invalid_cmd = (self.root.register(self.invalid))
# creating a Label
items_lbl = Label(self.root, text="# of items (5-10):")
items_lbl.grid(row=0, column=0)
# creating a Spinbox widget
self.items_var = StringVar()
self.items_var.set(7)
items_count = Spinbox(self.root, textvariable=self.items_var,
from_=5, to=10, width=4, validate='focusout',
validatecommand=validate_cmd,
invalidcommand=invalid_cmd)
items_count.grid(row=0, column=1)
# creating an Entry widget
self.entry_var = StringVar()
self.entry_var.set("Input some text here")
text_entry = Entry(self.root, textvariable=self.entry_var)
text_entry.grid(row=1, column=0)
def validate(self, entry):
try:
value = int(entry)
valid = value in range(5, 11)
except ValueError:
valid = False
if not valid:
self.root.bell()
return valid
def invalid(self):
self.items_var.set(7)
if __name__ == '__main__':
main_window = GUI()
mainloop()
推荐答案
我在这里找到了一个很好的解释(在验证一章的最后一段):
I found a great explanation here (in the last paragraph of the chapter Validation):
http://stupidpythonideas.blogspot.fr/2013/12/tkinter-validation.html
如果您的validatecommand(或invalidcommand)直接或间接地修改了条目(例如,通过在其StringVar上调用set),一旦您的函数返回,验证将被禁用.(这就是 Tk 如何防止验证触发另一个验证的无限循环.)您必须重新打开它(通过调用 config).但是你不能在函数内部这样做,因为它在你的函数返回后被禁用.
但是您需要应用一些更改才能使用此技巧.
But you need to apply some changes to be able to use this trick.
您需要使 Spinbox
成为一个实例属性,使用 self
:
You need to make the Spinbox
an instance attribute, with self
:
self.items_count = Spinbox(self.root, textvariable=self.items_var,
from_=5, to=10, width=4, validate='focusout',
validatecommand=validate_cmd,
invalidcommand=invalid_cmd)
self.items_count.grid(row=0, column=1)
然后你可以在 validate
方法中调用 self.items_count.after_idle(...)
:
And then you can call self.items_count.after_idle(...)
inside the validate
method :
def validate(self, entry):
try:
value = int(entry)
valid = value in range(5, 11)
except ValueError:
valid = False
if not valid:
self.root.bell()
self.items_count.after_idle(lambda: self.items_count.config(validate='focusout'))
return valid
这篇关于tkinter 中的小部件验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!