Search code examples
python-3.xvalidationtkintertkinter-entry

Validate Email in Entry widget content more than once - tkinter


I have a code that correctly validates email, but this happens only once. So if the email is invalid, it wont let me validate it again. Is there a way how to validate it over and over?

import tkinter as tk
from tkinter import *
from tkinter import ttk
import re

class Test(tk.Frame):
    def __init__(self, root):
        self.root = root
        self.root.geometry("{}x{}+250+150".format(500, 500))
        
        self.entry()

    def testAlphaValue(self, value):
        if value.isalpha():
            return True
        else:
            return False

    def testEmail(self, email):
        regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
        wdg = self.wdgLst
        if(re.search(regex, email)):
            return wdg.configure(text='Email is valid')    
        else:
            return wdg.configure(text='Email is invalid')

    def entry(self):
        self.formFrame = LabelFrame(self.root, bg='grey', bd=1)
        self.formFrame.place(x=50, y=50, width=400, height=400)

        regEmail = self.root.register(self.testEmail)
        regAlpha = self.root.register(self.testAlphaValue)

        nameEnt = Entry(self.formFrame)
        nameEnt.config(validate="key", validatecommand=(regAlpha, '%S')) 
        nameEnt.grid(row=0, column=1)

        emailEnt = Entry(self.formFrame)
        emailEnt.config(validate="focusout", validatecommand=(regEmail, '%P'))
        emailEnt.grid(row=0, column=0)
        emailLbl = Label(self.formFrame, text='Email', font=("Helvetica", 8))
        emailLbl.grid(row=1, column=0)
        self.wdgLst = emailLbl

root=tk.Tk()
test = Test(root)
root.mainloop()

Thank you!


Solution

  • Here is a working code for ya which validates email on focus-out event (as you wanted) - (must read the reason with explanation below the code)

    import tkinter as tk
    from tkinter import *
    from tkinter import ttk
    import re
    
    class Test(tk.Frame):
        def __init__(self, root):
            self.root = root
            self.root.geometry("{}x{}+250+150".format(500, 500))
            
            self.entry()
    
        def testAlphaValue(self, value):
            if value.isalpha():
                return True
            else:
                return False
            
        def checkEmail(self, val):
            if re.search(regex, val):
                self.wdgLst.configure(text='Email is valid')
                return True
            else:
                self.wdgLst.configure(text='Email is Invalid')
                return False
    
        def entry(self):
            self.formFrame = LabelFrame(self.root, bg='grey', bd=1)
            self.formFrame.place(x=50, y=50, width=400, height=400)
    
            regEmail = self.root.register(self.checkEmail)
            regAlpha = self.root.register(self.testAlphaValue)
    
            nameEnt = Entry(self.formFrame)
            nameEnt.config(validate="key", validatecommand=(regAlpha, '%S')) 
            nameEnt.grid(row=0, column=1)
    
            emailEnt = Entry(self.formFrame)
            emailEnt.config(validate="focusout", validatecommand=(regEmail, '%P'))
            emailEnt.grid(row=0, column=0)
            emailLbl = Label(self.formFrame, text='Email', font=("Helvetica", 8))
            emailLbl.grid(row=1, column=0)
            self.wdgLst = emailLbl
    
    root=tk.Tk()
    regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
    test = Test(root)
    root.mainloop()
    

    ***REASON FOR THE ISSUE ***

    From what I got to know about the issue, there seems to be a rule which is::

    The function registered to the validate command must return either True or False.
    In any other case, if the function returns something else,  
    it DISABLES the validation for the respected widget.
    

    In your code you were making it return wdg.configure(<something here>) which was disabling the validation right after the first run.

    You can also use the method suggested by @ShaneLoyd above if you wish to change your approach but if you just want to stick to validate commands, go with the above code.