I am currently working on translating my classic tkinter app to customtkinter for GUI design improvement reasons.
While most of the original app is translated without major problems I now face a problem with entry validation. The issue is that customtkinter
does not provide the invalidcommand
argument for the CTkEntry
. Below are some excerpts of my old logic put togeter in a reproduciple sample:
from tkinter import Tk, Entry, Button, StringVar
from re import compile
class App(Tk):
def __init__(self):
super().__init__()
self.var = StringVar()
# The entry to be validated:
self.entry = Entry(self, textvariable=self.var, width=20, validate='focusout',
validatecommand=(self.register(validate_ap), '%P'),
invalidcommand=(self.register(self.reset_ap)))
self.entry.pack()
# The Button to start the processing of the entry information
Button(self, text='process', command=self.print_if_valid).pack()
# The function to change the entry if input is not allowed:
def reset_ap(self):
self.var.set('02200000')
self.entry.after_idle(lambda: self.entry.config(validate='focusout'))
# The function that handles the correct input further
def print_if_valid(self):
if self.var.get() != '02200000':
print(self.var.get())
# The validation function:
def validate_ap(inp):
pattern = compile(r'^(?!0+$)022\d{5}$')
if pattern.match(inp):
return True
else:
return False
if __name__ == '__main__':
app = App()
app.mainloop()
Now if I change to customtkinter
how can I incorporate this behavior without a invalidcommand
argument for the Entry
? I like to put 02200000
inside the Entry
because it shows the user what format is required. Also without the invalidcommand
the current implemented validation does nothing.
I am thinking of implementing the invalidcommand
logic into the processing function (here the print_if_valid
function) but my real usecase is an editor with several inputs with this validation logic, so I do not want to change multiple entries after the user is finished with the wohle form...
Further I am wondering if there is a better way to check in print_if_valid
? Should I use a boolean variable which is toggled in the validation instead of the placeholder value I set or is there even a property of the Entry
widget that is changed by the validatecommand
?
While writing this question I discovered a really simple solution by simply incorporating the logic of reset_ap
into the validate_ap
validation function:
from tkinter import Tk, Entry, Button, StringVar
from re import compile
class App(Tk):
def __init__(self):
super().__init__()
self.var = StringVar()
# The entry to be validated:
self.entry = Entry(self, textvariable=self.var, width=20, validate='focusout',
validatecommand=(self.register(self.validate_ap), '%P'))
self.entry.pack()
# The Button to start the processing of the entry information
Button(self, text='process', command=self.print_if_valid).pack()
# The function that handles the correct input further
def print_if_valid(self):
if self.var.get() != '02200000':
print(self.var.get())
# The validation function is now a classfunction and changes the entry directly instead
# of returning True or False:
def validate_ap(self, inp):
pattern = compile(r'^(?!0+$)022\d{5}$')
if not pattern.match(inp):
self.var.set('02200000')
self.entry.after_idle(lambda: self.entry.config(validate='focusout'))
if __name__ == '__main__':
app = App()
app.mainloop()
However, I am still thinking on how to best check if self.var
is valid for the print_if_valid
function...