【问题标题】:Entry validatecommand not called after tkinter.messagebox.showwarning() has been called调用 tkinter.messagebox.showwarning() 后未调用条目 validatecommand
【发布时间】:2021-03-02 22:12:34
【问题描述】:

如果用户没有在Entry 中输入整数,我想显示一个警告,这是一个最小的示例:

import tkinter as tk
from tkinter import messagebox

class MainWindow(tk.Tk):
    """ The main window
    """
    def __init__(self):
        tk.Tk.__init__(self)
        self.configure_window()


    def configure_window(self):
        """ Configure the main window
        """
        self.geometry("600x400")
        self.title("Testing entry validate command")
        self.bind_all('<Control-w>', lambda e: self.destroy())
        var1 = tk.StringVar(value="0")
        vcmd = (self.register(self.validate_input))
        entry1 = tk.Entry(
            self,
            textvariable=var1,
            validate='all',
            validatecommand=(vcmd, '%P'))
        entry1.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

    def validate_input(self, txt):
        """ Validate that the input only contains digits
        """
        print(txt)
        if str.isdigit(txt) or txt == "":
            return True
        messagebox.showwarning(
            "Alert", "Please enter a positive integer")
        return False


def main():
    window = MainWindow()
    window.mainloop()

main()

问题是在第一次显示警告消息后没有调用validate_input() 方法。例如,如果用户在条目中输入“0”、“1”、“r”(三个按键),则每次按键都会调用validate_input(),而对于最后一个按键(字母“r”)显示警告消息框。接下来,如果用户继续在条目中键入(在警告消息框中按“确定”后),则不会再为以下击键调用 validate_input() 方法。预期的行为是,无论消息框是否已显示,任何按键都会调用它。

可能是什么问题?

【问题讨论】:

  • 你知道你可以用str.isdigit(txt)代替txt.isdigit()
  • 作为用户,当我输入错误的字符时出现弹出窗口,我会感到非常沮丧。
  • @BryanOakley 这可能是真的,但是一旦用户知道消息框出现后,第一次之后消息框就不会经常显示了

标签: python tkinter


【解决方案1】:

我猜这是因为您将validate 设置为“全部”。 “全部”包括验证焦点输出。当对话框弹出时,条目失去焦点。这会导致 tkinter 在进行验证的过程中尝试进行另一轮验证。这可能会触发验证被关闭,因为您可能会进入一个不可避免的循环。

您需要想出一种方法来提醒用户而不会失去对条目小部件的关注,或者您需要在对话框关闭后恢复验证功能。

【讨论】:

    【解决方案2】:

    由于this 问题没有正确答案,我无法将其作为重复项关闭,但您只需要以下内容:

    def validate_input(self, txt):
        """ Validate that the input only contains digits
        """
        print(txt)
        if txt.isdigit() or txt == "":
            return True
        else:
            messagebox.showwarning("Alert", "Please enter a positive integer")
            self.entry1.config(validate='all',validatecommand=(self.vcmd, '%P')) # Set the validation back
            return False
    

    一定要说self.entry1self.vcmd

    self.vcmd = (self.register(self.validate_input))
    self.entry1 = tk.Entry(self,textvariable=var1,validate='all',validatecommand=(self.vcmd, '%P'))
    self.entry1.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
    

    虽然我不太确定,为什么会发生这种情况,但这解决了它。看起来在messagebox 之后,小部件失去了它的validation,我们必须重新设置它。

    就像 Bryan 所说的,如果你将 validate='all' 更改为 validate='key' 它会修复它:

    self.entry1 = tk.Entry(self,textvariable=var1,validate='key',validatecommand=(self.vcmd, '%P'))
    

    【讨论】:

      【解决方案3】:

      不是最好的解决方案,但它有效:

      import tkinter as tk
      from tkinter import messagebox
      
      class MainWindow(tk.Tk):
          """ The main window
          """
          def __init__(self):
              tk.Tk.__init__(self)
              self.configure_window()
      
      
          def configure_window(self):
              """ Configure the main window
              """
              self.geometry("600x400")
              self.title("Testing entry validate command")
              self.bind_all("<Control-w>", lambda e: self.destroy())
              vcmd = (self.register(self.validate_input))
              entry1 = tk.Entry(self)
              entry1.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
              entry1.bind("<Key>", self.validate_input)
      
          def validate_input(self, event):
              """ Validate that the input only contains digits
              """
              if (event.state & 4) >> 2 == 1:
                  # Ctrl+<event.keysym> was pressed
                  if event.keysym == "c":
                      # Ctrl+c pressed
                      return None
                  if event.keysym == "x":
                      # Ctrl+x pressed
                      return "break"
                  if event.keysym == "v":
                      # Ctrl+v pressed
                      return "break"
              if not (event.char.isdigit() or event.char == ""):
                  messagebox.showwarning(
                      "Alert", "Please enter a positive integer")
                  return "break"
      
      
      def main():
          window = MainWindow()
          window.mainloop()
      
      main()
      

      当您从某个事件返回 "break" 时,该事件被阻止且未被处理。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-03-16
        • 2021-01-02
        • 1970-01-01
        • 2021-04-25
        • 1970-01-01
        • 2020-02-04
        • 2018-12-09
        相关资源
        最近更新 更多