我希望如果一个字段有无效条目,则在移出该字段时显示消息,并且焦点应保留在该字段上。但在下面的代码中,当移出第一个字段时,也会触发下一个字段的验证。我已经评论了设置焦点,否则,它会进入无限循环。
from tkinter import *
from tkinter import ttk, messagebox
root = Tk()
def callback1():
if (len(e1.get()) <4):
messagebox.showinfo("error", "Field 1 length < 4")
#e1.focus_set()
return False
else:
return True
def callback2():
if (len(e2.get()) <4):
messagebox.showinfo("error", "Field 2 length < 4")
#e2.focus_set()
return False
else:
return True
e1 = Entry(root, validate="focusout", validatecommand=callback1)
e1.grid()
e2 = Entry(root, validate="focusout", validatecommand=callback2)
e2.grid()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
当您将光标置于 中e1,键入不满足validatecommand条件的内容,然后尝试将光标置于 中时e2,会发生以下事件序列:
e1失去焦点并打电话callback1e2并e2获得焦点e1焦点并准备好弹出...e2失去焦点并打电话callback2e2弹出消息框窗口e1在队列中等待的弹出窗口问题的根本原因是消息框窗口获得焦点,进而触发另一个输入框。由于事件的强烈相互作用,这种方法似乎非常脆弱。
请注意,如果您只是将信息打印到终端,则一切都会完美运行,因为终端不会获得焦点。
因此,我建议您使用替代方法显示信息,其中显示信息的小部件不会窃取焦点。一种选择是使用标签显示信息。
现在讨论第二个问题,如果您希望条目在输入的文本无效时保留焦点,您可以使用全局变量 ( hanging) 来跟踪用户是否正在成功填写条目。
如果用户正在填写一个条目,他/她将无法将光标放在另一个条目中,因为FocusIn1和FocusIn2当等于 True 时返回“break” hanging。
您可以使用标签替换下面工作代码中的打印语句。
from tkinter import *
from tkinter import ttk, messagebox
root = Tk()
hanging = False #True implies that the user is in the process of filling an entry successfully
def onFocusOut1():
global hanging
hanging = True
if (len(e1.get()) <4):
print("error", "Field 1 length < 4")
e1.focus_set()
return False
else:
hanging = False
return True
def onFocusOut2():
global hanging
hanging = True
if (len(e2.get()) <4):
print("error", "Field 2 length < 4")
e2.focus_set()
return False
else:
hanging = False
return True
def onFocusIn1():
if hanging:
return "break"
e1.configure(validate="focusout", validatecommand=onFocusOut1)
def onFocusIn2():
if hanging:
return "break"
e2.configure(validate="focusout", validatecommand=onFocusOut2)
e1 = Entry(root)
e1.grid()
e2 = Entry(root)
e2.grid()
#Binding both the entries to FocusIn
e1.bind("<FocusIn>", lambda e: onFocusIn1())
e2.bind("<FocusIn>", lambda e: onFocusIn2())
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
PS:事实证明,您实际上可以在工作代码中使用messagebox.showinfo它本身来代替。print第一个问题和第二个问题一起自动解决了。因此,这为您的问题提供了完整的解决方案。