如何验证 tkinter 条目

How to validate tkinter entry

我正在开发一个 tkinter 应用程序,它有一个入口小部件和一种方法,当用户在其中键入内容时对其进行验证。问题是 绑定 运行s 更新了 self.entry_str 之前的验证方法,因此它测试了条目中以前的内容。我想让它做的是 运行 self.entry_str 更新后的验证方法,有人知道我该怎么做吗?这是简化的程序:

import sys
import tkinter as tk


class GUI:
    def __init__(self, master):
        # frame
        self.frame = tk.Frame(master)
        self.frame.pack()
        # StringVars
        self.error = tk.StringVar()
        self.error.set('')
        self.entry_str = tk.StringVar()
        self.entry_str.set('')
        # widgets
        self.entry = tk.Entry(self.frame, textvariable=self.entry_str)
        self.entry.bind('<Key>', lambda _: self.validate_entry())
        self.entry.grid(row=0, column=0)
        self.error_label = tk.Label(self.frame, textvariable=self.error, fg='red')
        self.error_label.grid(row=1, column=0)
        self.bttn = tk.Button(self.frame, text='continue', command=sys.exit)
        self.bttn.grid(row=2, column=0)

    def validate_entry(self):
        try:
            _ = int(self.entry_str.get())
        except ValueError:# entry is not valid: disable button and show error
            self.error.set('entry has to be an integer')
            self.bttn.config(state='disabled')
        else:# entry is valid: enable button and hide error
            self.error.set('')
            self.bttn.config(state='normal')


root = tk.Tk()
gui = GUI(root)
root.wm_title('entry validation test')
root.mainloop()

使用<KeyRelease>代替<Key>

更好的方法是使用 .trace

self.entry_str = tk.StringVar()
self.entry_str.set('')
self.entry_str.trace('w', self.validate_entry)

...

def validate_entry(self, *event):
        try:
            _ = int(self.entry_str.get())
         ...

另一种方法是禁止用户输入整数以外的任何内容。

self.entry = tk.Entry(self.frame, textvariable=self.entry_str, validate='key', validatecommand=(master.register(self.validate), "%P"))
...
def validate(self, char):  # this function must return only True or False
        return char.isdigit() or char==''

请注意 self.entry_str 将始终是最新的

你有2个选项。第一个:在用户输入数据之前保存条目数据,并在需要时恢复数据,如下所示:

import sys
import tkinter as tk


class GUI:
    def __init__(self, master):
        # frame
        self.frame = tk.Frame(master)
        self.frame.pack()
        # StringVars
        self.error = tk.StringVar()
        self.error.set('')
        self.entry_str = tk.StringVar()
        self.entry_str.set('')
        # widgets
        self.entry = tk.Entry(self.frame, textvariable=self.entry_str)
        self.entry.bind('<Key>', self.validate_entry)
        self.entry.grid(row=0, column=0)
        self.error_label = tk.Label(self.frame, textvariable=self.error, fg='red')
        self.error_label.grid(row=1, column=0)
        self.bttn = tk.Button(self.frame, text='continue', command=sys.exit)
        self.bttn.grid(row=2, column=0)

        self.current_entry_state = ""
        self.error_occured = False

    def validate_entry(self, event):
        current_entry_state = self.entry_str.get()
        # Save the state only if there are no invalid characters:
        try:
            _ = int(self.entry_str.get())
            self.current_entry_state = current_entry_state
            self.error_occured = False
        except:
            self.error_occured = True
        # Wait for tkinter to display the character
        self.entry.after(1, self._validate_entry)

    def _validate_entry(self):
        try:
            _ = int(self.entry_str.get())
        except ValueError:# entry is not valid: disable button and show error
            self.error.set('entry has to be an integer')
            # Restore the entry's text:
            self.entry.delete("0", "end")
            self.entry.insert("end", self.current_entry_state)
        else:
            if not self.error_occured:# entry is valid: enable button and hide error
                self.error.set('')


root = tk.Tk()
gui = GUI(root)
root.wm_title('entry validation test')
root.mainloop()

还有另一种方法(没有很好地记录)但请看 this and this