Python 文本输入事件?
作为我程序的一部分,我向用户询问他们的姓名和班级(高中班级)。一旦用户在输入姓名后按“回车”,按钮将被禁用,并显示“导师”字段。然而,用户本质上能够提交他们的名字,即使他们没有键入任何东西。我只希望在用户开始键入后“回车”按钮处于活动状态 我在下面所做的似乎不起作用:( 此外,我的输入验证不起作用-知道为什么吗Python 文本输入事件?,python,user-interface,events,tkinter,tkinter-entry,Python,User Interface,Events,Tkinter,Tkinter Entry,作为我程序的一部分,我向用户询问他们的姓名和班级(高中班级)。一旦用户在输入姓名后按“回车”,按钮将被禁用,并显示“导师”字段。然而,用户本质上能够提交他们的名字,即使他们没有键入任何东西。我只希望在用户开始键入后“回车”按钮处于活动状态 我在下面所做的似乎不起作用:( 此外,我的输入验证不起作用-知道为什么吗 class Enter_Name_Window(tk.Toplevel): '''A simple instruction window''' def __init__(
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()
第一个明显的问题是这一行:
tutor_var.trace('w', lambda name, index, mode: validate_enter_0_2)
您创建了一个包含三个变量的函数,并将validate\u enter\u 0\u 2
函数作为函数对象返回。这没有任何好处
您想创建一个调用验证\u enter\u 0\u 2
函数的函数。如下所示:
tutor_var.trace('w', lambda name, index, mode: validate_enter_0_2())
您在name\u var
中遇到了完全相同的问题,当然,您还需要在那里解决它
除此之外,您实际上没有名为
validate\u enter\u 2
的函数可调用,因为您将其定义为validate\u enter\u 2
。这意味着您的验证函数只会引发namererror
,而不是执行有用的操作。或者,如果您在代码中的其他地方定义了validate\u enter\u 2
函数,它调用了错误的函数。(这是像enter\u 0\u 2
和enter\u 2
这样的神秘名称不是一件好事的原因之一。)
您的代码至少还有一个问题:您反复尝试使用
name\u 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__'
if len(name_var.get()) > 10 or any(l not in string.ascii_letters for l in name_var.get())
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
在您有机会创建新的条目之前,就会发生该异常
要解决这个问题,您需要在StringVar
上调用get
,只要您想获取它的值,如下所示:
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__'
if len(name_var.get()) > 10 or any(l not in string.ascii_letters for l in name_var.get())
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
最后,正如我在回答您的另一个问题时所解释的,在某些内容发生更改之前,跟踪
验证器不会被调用。这意味着您需要显式调用它,或者显式调用名称变量集(“”)
,或仅禁用“关闭启动”按钮。如前所述,它将启用“关闭启动”,仅当您键入某个内容并将其删除时才禁用
我不确定这些是否是您的代码中唯一的问题,但它们肯定会阻止您的验证按预期工作。因此,您需要修复所有这些问题以及代码中的任何其他错误,然后验证才能工作
根据您的评论:
然而,我想知道如何创建一个弹出消息显示错误
你想什么时候检查?你想检查什么条件,什么时候检查
无论如何,与大多数GUI一样,“弹出”类似内容的方式是一个对话框。Tkinter书中解释了您需要了解的所有内容。但您不需要复制粘贴所有代码,也不需要从头开始编写;stdlib附带了它,它可以为您完成大部分工作。在您的情况下,您可能只需要这样做
…以及强制用户重新输入其名称的内容
如何强制他们?只需删除现有条目内容,就会留下一个空框来填充,这也会禁用按钮。这就是你想要的吗
不管怎样,猜猜你想要什么,它可能看起来像这样:
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__'
if len(name_var.get()) > 10 or any(l not in string.ascii_letters for l in name_var.get())
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
在回调
函数中(键入姓名后单击按钮时调用),而不是仅仅检查某个条件并打印出某些内容,我检查一个条件并弹出一个错误对话框,清除现有名称,并提前返回,而不是创建表单的后半部分。我没有处理其他条件(任何非ASCII字母),但如何添加它应该是显而易见的
但是,这样的验证最好是通过实际验证来完成,而不是让他们等到单击按钮,然后在尝试键入第11个字符、空格或重音字符或其他您不喜欢的字符时立即捕获。然后,您可以弹出一个消息框,或者禁用按钮,直到他们修复它,然后重新启动删除/撤消更改(使用validatecommand
函数比使用trace
函数更容易,如我对上一个问题的回答所示)
最后一件事:与其使用消息框,不如将错误嵌入为表单本身中出现的标签(可能错误描述为红色,带有大旗图标)。这在web应用程序和更现代的GUI中很常见,因为它提供了更即时的反馈,并且对用户流的干扰更小。这是一个后续问题,还是一个在某些方面有所不同的全新问题?(如果是后者,则在哪些方面有所不同?)另外,正如我在上一个问题上告诉你的,请提供一个-我们可以实际运行和调试的东西,而不仅仅是一段随机的代码from Tkinter import*
和import Tkinter as tk
和import Tkinter
。只需执行其中一项操作,而不是全部操作,并一致使用名称。非常感谢验证和事件处理程序都能正常工作。不过,我想知道如何创建一个弹出消息,显示错误和强迫用户执行的操作重新输入他们的名字。Thanks@user3056786:这些问题有些模糊。它们看起来也像是后续问题,应该是一个或多个单独的问题。但我会编辑答案,尝试让您开始。