如何在python中验证条目小部件?

时间:2014-06-06 15:59:53

标签: python validation tkinter

我使用Tkinter创建GUI,用于从用户收集信息。我需要验证:

  • 名字和姓氏只包含字母,撇号和短划线
  • 地址
  • 电话号码具有正确的位数
  • 有效生日(2月31日不存在,出生年份为1900年至2014年)
  • 电子邮件地址包含' @'和'。'

这是我的代码:

from tkinter import *
import datetime

class tkwindow:

def __init__(self):

    window = Tk() # Create window
    window.title("Contact Form") # Give window a title

    menubar = Menu(window) # Create menu bar
    window.config(menu = menubar) # Display menu bar

    '''Using the pulldown menu allows easier access to the menu items instead of using a pop-up menu '''

    # Create pulldown menu and add to menu bar
    messagesMenu = Menu(menubar, tearoff = 0)
    menubar.add_cascade(label = "Messages", menu = messagesMenu)
    messagesMenu.add_command(label = "Send a Birthday Greeting", command = self.bdayGreeting)
    messagesMenu.add_command(label = "Print Address", command = self.printAddress)

    # Create another menu option
    endMenu = Menu(menubar, tearoff = 0)
    menubar.add_cascade(label = "End", menu = endMenu)
    endMenu.add_command(label = "Reset Form", command = self.resetForm)
    endMenu.add_command(label = "Exit Program", command = window.quit)

    # Using Label widget
    labelFirst = Label(window, text = "First Name: ").grid(row = 1, column = 1, sticky = E)
    labelLast = Label(window, text = "Last Name: ").grid(row = 2, column = 1, sticky = E)
    labelAddress = Label(window, text = "Address: ").grid(row = 3, column = 1, sticky = E)
    labelPhone = Label(window, text = "Phone Number (8005551234): ").grid(row = 4, column = 1, sticky = E)
    labelBday = Label(window, text = "Birthday (MM/DD/YYYY): ").grid(row = 5, column = 1, sticky = E)
    labelEmail = Label(window, text = "Email Address (user@domain.com): ").grid(row = 6, column = 1, sticky = E)

    # Using Entry widget
    self.firstName = StringVar()
    entryFirst = Entry(window, textvariable = self.firstName, justify = LEFT).grid(row = 1, column = 2, sticky = W)

    self.lastName = StringVar()
    entryLast = Entry(window, textvariable = self.lastName, justify = LEFT).grid(row = 2, column = 2, sticky = W)

    self.address = StringVar()
    entryAddress = Entry(window, textvariable = self.address, justify = LEFT).grid(row = 3, column = 2, sticky = W)

    self.phone = StringVar()
    entryPhone = Entry(window, textvariable = self.phone, justify = LEFT).grid(row = 4, column = 2, sticky = W)

    self.bday = StringVar()
    entryBday = Entry(window, textvariable = self.bday, justify = LEFT).grid(row = 5, column = 2, sticky = W)

    self.email = StringVar()
    entryEmail = Entry(window, textvariable = self.email, justify = LEFT).grid(row = 6, column = 2, sticky = W)

    self.errorLblFirst = Label(window, fg = "red")
    self.errorLblFirst.grid(row = 1, column = 3)

    self.errorLblLast = Label(window, fg = "red")
    self.errorLblLast.grid(row = 2, column = 3)

    self.errorLblAddress = Label(window, fg = "red")
    self.errorLblAddress.grid(row = 3, column = 3)

    self.errorLblPhone = Label(window, fg = "red")
    self.errorLblPhone.grid(row = 4, column = 3)

    self.errorLblBday = Label(window, fg = "red")
    self.errorLblBday.grid(row = 5, column = 3)

    self.errorLblEmail = Label(window, fg = "red")
    self.errorLblEmail.grid(row = 6, column = 3)

    # Using Button widget
    buttonSubmit = Button(window, text = "Submit", command = self.submit).grid(row = 7, column = 2, sticky = E)

    window.mainloop()

def resetForm(self):

    self.firstName.set('')
    self.errorLblFirst["text"] = ''
    self.lastName.set('')
    self.errorLblLast["text"] = ''
    self.address.set('')
    self.errorLblAddress["text"] = ''
    self.phone.set('')
    self.errorLblPhone["text"] = ''
    self.bday.set('')
    self.errorLblBday["text"] = ''
    self.email.set('')
    self.errorLblEmail["text"] = ''

def validFirst(self):

    for letter in self.firstName.get():
        if not letter.isalpha() and letter not in "'-":
            self.errorLblFirst["text"] = " * Letters, apostrophes('), and hypens(-) only"
            return False

    return True

def validLast(self):

    for letter in self.lastName.get():
        if not letter.isalpha() and letter not in "'-":
            self.errorLblLast["text"] = " * Letters, apostrophes('), and hypens(-) only"
            return False

    return True

def validAddress(self):

    for letter in self.address.get():
        if not letter.isalnum() and letter not in "'- .,":
            self.errorLblAddress["text"] = " * No special characters"
            return False

    return True

def validPhone(self):

    D = 0

    for number in self.phone.get():
        if number.isdigit():
            D += 1
        if D == 10:
            return True
        else:
            self.errorLblPhone["text"] = " * Must be 10-digit phone number without spaces"
            return False

    return True

def validBday(self):

    '''try:
        valid_date = datetime.datetime.strptime(str(self.bday), '%m/%d/%Y')
    except ValueError:
        print('Invalid date!')'''
    return True

def validEmail(self):

    for letter in self.email.get():
        if not letter.isalnum() and letter not in "@.":
            self.errorLblEmail["text"] = " * Must have @ and ."
            return False

    return True

def bdayGreeting(self):
    if self.validBday() and self.validFirst() == True:
        print("Happy Birthday" + self.firstName.get() + "\n" + self.bday.get())

def printAddress(self):
    if self.validFirst() and self.validLast() and self.validAddress() == True:
        print(self.firstName.get() + " " + self.lastName.get() + "\n" + self.address.get())


def submit(self):
    self.validFirst()
    self.validLast()
    self.validAddress()
    self.validPhone()
    self.validBday()
    self.validEmail()

tkwindow()

我有几个问题。

  1. 从def validFirst(self)开始,如何验证不同的输入字段?当我修改代码时,我不断收到NameError: name "asdf" is not definedSyntaxError: unexpected EOF while parsingTypeError: 'int' object is not subscriptable,而我仍然坚持使用validFirst(自我)。
  2. 我在第3列中有一组为错误消息保留的标签:errorLblFirst = Label(window, text = " ", fg = "red").grid(row = 1, column = 3)。当该条目的验证失败时,是否可以将其设置为" * Invalid Entry", fg = "red"?是否有其他方法可以显示错误消息?
  3. 提前感谢您的投入!

    编辑:我更新到我的最新代码。如果您可以查看,大多数验证现在都可以使用validBdayvalidEmail除外。

1 个答案:

答案 0 :(得分:3)

errorLblFirst = Label(...).grid(...)

这样您可以将grid()的结果分配给errorLblFirst,但grid()始终返回None

总是这样做

errorLblFirst = Label(...)
errorLblFirst.grid(...)

现在你可以做(​​例如)

errorLblFirst["text"] = " * Invalid Entry"
errorLblFirst["fg"] = "red"

修改

您忘记了len() for i in range(first):中的validFirst() 而且你不需要eval()。 (你在validPhone()

中遇到了同样的问题
F = 0

fName = True

first = self.firstName.get() # without eval()

for i in range(len(first)): # len()
    if first[i].isdigit():
        F += 1
    if F > 0:
        return False
    else:
       return fName

return fName

但你可以做得更短

for letter in self.firstName.get():
    if letter.isdigit():
        return False

return True

如果你只需要字母(没有空格,逗号等),你可以这样做

return self.firstName.get().isalpha()

修改

我看到First Name可以有撇号和破折号

for letter in self.firstName.get():
    if not letter.isalpha() and letter not in "'-":
        return False

return True

编辑问题self.phoneStringVar

self.phoneStringVar() - 不是string 但是StringVar().get()来获取string

for number in range(len( self.phone.get() )): 

顺便说一句:你可以for循环更多pythonic - 没有range(len())

for char in self.phone.get(): 
    if char.isdigit():     

编辑问题validEmail()validBday()

电子邮件验证需要更多if

例如,您可以添加

email = self.email.get()
if '@' not in email and '.' not in email::
    print( 'email needs @ and . at the same time')

但是'。@'将通过此测试:/

真正的电子邮件验证更复杂。

查看有效的电子邮件示例:https://fightingforalostcause.net/content/misc/2006/compare-email-regex.php


self.bdayStringVar - 使用self.bday.get()代替str(self.bday)


修改

def validPhone(self):

    D = 0

    for number in self.phone.get():
        if number.isdigit():
            D += 1

    # outside 

    if D == 10:
        return True
    else:
        self.errorLblPhone["text"] = " * Must be 10-digit phone number without spaces"
        return False

    return True

甚至

def validPhone(self):

    # remove previous error message
    self.errorLblPhone["text"] = ""

    D = 0

    for number in self.phone.get():
        if number.isdigit():
            D += 1

    if D != 10:
        self.errorLblPhone["text"] = " * Must be 10-digit phone number without spaces"
        return False

    return True

如果数字只能有10位数字(没有空格,没有 - 等):

def validPhone(self):

    # remove previous error message
    self.errorLblPhone["text"] = ""

    D = True

    for number in self.phone.get():
        if not number.isdigit():
            D = False
            break  

    if not D or len(number) != 10:
        self.errorLblPhone["text"] = " * Must be 10-digit phone number without spaces"
        return False

    return True