如果条目无效,如何防止焦点改变?

Ama*_*nna 5 python tkinter

我希望如果一个字段有无效条目,则在移出该字段时显示消息,并且焦点应保留在该字段上。但在下面的代码中,当移出第一个字段时,也会触发下一个字段的验证。我已经评论了设置焦点,否则,它会进入无限循环。

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)

Sri*_*san 1

当您将光标置于 中e1,键入不满足validatecommand条件的内容,然后尝试将光标置于 中时e2,会发生以下事件序列:

  1. e1失去焦点并打电话callback1
  2. 同时,光标置于e2e2获得焦点
  3. msgbox 窗口获得e1焦点并准备好弹出...
  4. e2失去焦点并打电话callback2
  5. e2弹出消息框窗口
  6. 接下来是e1在队列中等待的弹出窗口

问题的根本原因是消息框窗口获得焦点,进而触发另一个输入框。由于事件的强烈相互作用,这种方法似乎非常脆弱。

请注意,如果您只是将信息打印到终端,则一切都会完美运行,因为终端不会获得焦点。

因此,我建议您使用替代方法显示信息,其中显示信息的小部件不会窃取焦点。一种选择是使用标签显示信息。


现在讨论第二个问题,如果您希望条目在输入的文本无效时保留焦点,您可以使用全局变量 ( hanging) 来跟踪用户是否正在成功填写条目。

如果用户正在填写一个条目,他/她将无法将光标放在另一个条目中,因为FocusIn1FocusIn2当等于 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第一个问题和第二个问题一起自动解决了。因此,这为您的问题提供了完整的解决方案。