作为我课程的一部分,我向用户询问他们的姓名和班级(高中班级)。用户在输入姓名后按“Enter”键,按钮将被禁用,并显示“tutor”字段。然而,即使用户没有输入任何内容,用户实际上也能够提交他们的名字。我只希望在用户开始输入后“Enter”按钮处于活动状态。
我在下面所做的事似乎不起作用:(
另外,我的输入验证不起作用 - 知道原因吗?
class Enter_Name_Window(tk.Toplevel):
'''A simple instruction window'''
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.text = tk.Label(self, width=40, height=2, text= "Please enter your name and class." )
self.text.pack(side="top", fill="both", expand=True)
name_var = StringVar()
def validate_enter_0():
self.Enter_0.config(state=(NORMAL if name_var.get() else DISABLED))
print("validate enter worked")
name_var.trace('w', lambda name, index, mode: validate_enter_0)
enter_name = Entry(self, textvariable=name_var)
enter_name.pack()
enter_name.focus_set()
def callback():
if len(name_var) > 10 or any(l not in string.ascii_letters for l in name_var):
print("Input validation worked")
self.display_name = tk.Label(self, width=40, height=2, text = "Now please enter your tutor group.")
self.display_name.pack(side="top", fill="both", expand=True)
tutor_var = StringVar()
def validate_enter_2():
self.Enter_0_2.config(state=(NORMAL if tutor_var.get() else DISABLED))
print("validate enter worked")
tutor_var.trace('w', lambda name, index, mode: validate_enter_0_2)
tutor = Entry(self, textvariable=tutor_var)
tutor.pack()
tutor.focus_set()
self.Enter_0.config(state="disabled")
self.Enter_0_2 = Button(self, text="Enter", width=10, command=self.destroy)
self.Enter_0_2.pack()
self.Enter_0 = Button(self, text="Enter", width=10, command=callback)
self.Enter_0.pack()
答案 0 :(得分:1)
第一个明显的问题是这一行:
tutor_var.trace('w', lambda name, index, mode: validate_enter_0_2)
您创建了一个带有三个变量的函数,并将validate_enter_0_2
函数作为函数对象返回。这没有任何好处。
您想要创建一个调用 validate_enter_0_2
函数的函数。像这样:
tutor_var.trace('w', lambda name, index, mode: validate_enter_0_2())
您与name_var
存在完全相同的问题,当然还需要在那里修复它。
除此之外,您实际上并没有拥有一个名为validate_enter_0_2
的函数来调用,因为您将其定义为validate_enter_2
。这意味着您的验证功能只会引发NameError
而不是有用。或者,如果您在代码中的其他位置定义了validate_enter_2
函数,则会调用错误的函数。 (这就是像enter_0_2
和enter_2
这样神秘的名字不是一件好事的一个原因。)
您的代码至少还有一个问题:您反复尝试使用name_var
StringVar
对象,就好像它是一个字符串一样。你不能这样做。如果您实际查看控制台输出,Tkinter会告诉您这一点,并带有这样的追溯:
Exception in Tkinter callback
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1410, in __call__
return self.func(*args)
File "tkval2.py", line 25, in callback
if len(name_var) > 10 or any(l not in string.ascii_letters for l in name_var):
AttributeError: StringVar instance has no attribute '__len__'
在你有机会创建新的Entry
之前,就会发生这种异常。
要解决此问题,您需要在get
上调用StringVar
,只要您想获取其值,就像这样:
if len(name_var.get()) > 10 or any(l not in string.ascii_letters for l in name_var.get())
最后,正如我在你的另一个问题的答案中解释的那样,你的trace
验证器在发生变化之前不会被调用。这意味着您需要显式调用它,或者明确地name_var.set('')
调用它,或者只是禁用禁用按钮。如上所述,它将启动,并且只有在您键入内容然后将其删除时才会禁用。
我不确定这些是您代码中唯一的问题,但所有这些问题肯定会阻止您的验证按预期工作。因此,您需要先修复所有这些错误以及代码中的任何其他错误,然后再进行操作。
来自您的评论:
但我想知道如何创建一个显示错误的弹出消息...
你想什么时候做?您想检查什么条件,以及何时检查它?
无论如何,就像在大多数GUI中一样,“弹出”这样的东西的方式是一个对话框。 Tkinter书中的Dialog Windows解释了你需要知道的一切。但是您不需要复制粘贴所有代码,也不需要从头开始编写代码; stdlib附带Tkinter helper modules,可以为您完成大部分工作。在您的情况下,您可能只想要tkMessageBox
。
......以及强迫用户重新输入姓名的内容
强迫他们怎么样?只是删除现有的Entry内容会留下一个空框来填写,这也会禁用该按钮。这就是你想要的吗?
无论如何,猜测你想要什么,它看起来像这样:
def callback():
if len(name_var.get()) > 10:
tkMessageBox.showerror("Bad name", "Your name is too long. What's wrong with good American names like Joe?")
name_var.set('')
return
# the rest of your code here
在callback
函数中(在键入名称后单击按钮时调用),而不仅仅是检查某些条件并打印出来的东西,我检查一个条件并弹出一个错误对话框,清除现有的名称,并提前返回,而不是创建表单的后半部分。我没有处理你的其他条件(任何非ASCII字母),但显而易见的是如何添加它。
然而,通过实际验证可能更好地完成这样的验证 - 而不是让它们等到他们点击按钮,一旦他们尝试键入第11个字符,空格或重音字符或其他任何内容时立即捕获它你不喜欢。然后你可以弹出一个消息框,并禁用按钮直到他们修复它,拒绝/撤消更改(使用validatecommand
功能比使用trace
功能更容易,如我所示回答你之前的问题)。
最后一件事:代替消息框,最好只是将错误嵌入,例如,表单中出现的标签(可能带有红色的错误描述,带有一个大标志图标)。这在Web应用程序和更现代的GUI中很常见,因为它提供了更直接的反馈,并且不那么突出用户流。