How can I make my dynamically generated tkinter entry form be dynamically validated?

Viewed 25

I want to put separate validation on dynamically created CTkentry fields in tkinter. I cannot get the passing-on off the reference to these dynamically created CTkentry and label fields to work?

This creates the labels which display for every entry field what the problem is

self.errorlbls = [customtkinter.CTkLabel(master=self.master,text = "",text_font=("Roboto Medium", -14)) for s in sections[self.active_database.get()]]

Here the validation is set-up, where i want to pass a reference to the CTkentry (entryreference) and CTklabel (lblss) objects, this works, however due to the register method which is needed to pass everything as a string, also these object references are passed as a string to the validate and on_invalid methods. This means that in these methods I cannot use them any more as a reference to configure them.

dynamic_vcmd = [(self.master.register(self.validate), '%P', fieldname, entryreference, regexx, lblss) for fieldname, entryreference, regexx, lblss in zip(sections[self.active_database.get()], self.entries, regex_entries[self.active_database.get()], self.errorlbls)]    
dynamic_ivcmd = [(self.master.register(self.on_invalid), fieldname, entryreference, regexx, lblss) for fieldname, entryreference, regexx, lblss in zip(sections[self.active_database.get()], self.entries, regex_entries[self.active_database.get()], self.errorlbls)]

Here is the error, it says that the lblss and entryreference objects are strings instead of the wanted CTkentry and CTklabel objects.

def show_message(self, entryreference, lblss, error='', color='white'):
    """
    Changes the to be showed message the user the right message on validation
    """
    lblss.configure(text = error)
    entryreference.configure(foreground = color)

When I try to pass on a reference of the dynamically created CTkentry and CTklabel fields on to on_invalid() and validate() through the register method, it converts these references to strings. I know this is a problem due to the register method that needs to be used, however I need to have the reference to these objects in order to change the color of the entry field and change the message displayed in the labels that correspond to the entry fields. Is there a workaround for this?

class DatabaseConfigForm:
    def render_frame_right(self, empty:bool = True):
        
        self.lbls = [customtkinter.CTkLabel(master=self.master,text = f"{s}") for s in sections[self.active_database.get()]]
        self.errorlbls = [customtkinter.CTkLabel(master=self.master,text = "",text_font=("Roboto Medium", -14)) for s in sections[self.active_database.get()]]
    
        #set up validation
        dynamic_vcmd = [(self.master.register(self.validate), '%P', fieldname, entryreference, regexx, lblss) for fieldname, entryreference, regexx, lblss in zip(sections[self.active_database.get()], self.entries, regex_entries[self.active_database.get()], self.errorlbls)]    
        dynamic_ivcmd = [(self.master.register(self.on_invalid), fieldname, entryreference, regexx, lblss) for fieldname, entryreference, regexx, lblss in zip(sections[self.active_database.get()], self.entries, regex_entries[self.active_database.get()], self.errorlbls)]
        
        # configures all variable entry fields, labels and errorlabels
        for entry, labels, errorlbls in zip(self.entries, self.lbls, self.errorlbls):
            entry.grid(row=row_counter, column=1, pady=10, padx=20, sticky="w")
            labels.grid(row=row_counter, column=0, pady=10, padx=20, sticky="w")
            print(type(errorlbls))
            errorlbls.grid(row=row_counter, column=2, pady=10, padx=20)
            row_counter += 1 #sets which row the entry fields need to start building

        for entry, vcmds, ivcmds in zip(self.entries, dynamic_vcmd, dynamic_ivcmd):
            entry.configure(validate='focusout', validatecommand=vcmds, invalidcommand=ivcmds)
            print(vcmds)
    def show_message(self, entryreference, lblss, error='', color='white'):
        """
        Changes the to be showed message the user the right message on validation
        """
        lblss.configure(text = error)
        entryreference.configure(foreground = color)
        
    def validate(self, value: str, fieldname, entryreference, regexx, lblss):
        """
        Validate the email entry
        
        Parameter
        ---------
        value: str
        """
        if regexx == "short_text":
            pattern = r'\b[A-Z|a-z]{3}\b'

        pattern = r'\b[A-Z|a-z]{3}\b'       
        #regex pattern that needs to be checked
        if re.fullmatch(pattern, value) is None:
            return False
        
        self.show_message(entryreference, lblss)
        return True
    
    def on_invalid(self, fieldname, entryreference, regexx, lblss):
        """
        Show the error message if the data is not valid
        :return:
        """
        self.show_message(entryreference, lblss, 'Enter a valid alias', 'red')

Could someone help me with this?

0 Answers
Related