As part of my program I am asking the user for their name and their class (high school class). I am using a text entry function which is successfully accepting the input but I need help on validation: I only want the 'Enter' button to become active once the user has actually started typing as otherwise the user will press the 'Enter' button and deactivate it. Also, I would like to make sure that when they enter their name the program will only accept letters and no numbers at all. For the second entry (school class/tutor class) the user will enter something like 6A1 which is their class. There are about 10 different senior classes in my school so how can I either validate the entry to accept only 1 of these 10 classes or perhaps a drop down menu? Help would be greatly appreciated :)
class Enter_Name_Window(tk.Toplevel):
'''A simple instruction window'''
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.text = tk.Label(self, width=40, height=2, text= "Please enter your name and class." )
self.text.pack(side="top", fill="both", expand=True)
enter_name = Entry(self)
enter_name.pack()
enter_name.focus_set()
def callback():
self.display_name = tk.Label(self, width=40, height=2, text = "Now please enter your tutor group.")
self.display_name.pack(side="top", fill="both", expand=True)
tutor = Entry(self)
tutor.pack()
tutor.focus_set()
Enter_0.config(state="disabled")
Enter_0_2 = Button(self, text="Enter", width=10, command=self.destroy)
Enter_0_2.pack()
Enter_0 = Button(self, text="Enter", width=10, command=callback)
Enter_0.pack()
The way to do what you literally asked, "the 'Enter' button to become active once the user has actually started typing" is to bind the change or keypress event on the
enter_name
, and activateEnter_0
once it's triggered.But that's probably not what you actually want. If the user enters some text and then deletes it, wouldn't it be nicer if the button disabled again? And if the user pastes some text without typing anything, shouldn't that enable the button?
To do that, you want one of two things: validation, or variable tracing.
Before we get into it, you're almost certainly going to want to store the
Enter_0
button as an attribute onself
instead of creating and re-creating new buttons on top of each other. So, I'll do that in my example.Validation, although it's very badly documented in Tkinter and a bit clumsy to use, is very powerful, and the obvious fit for what you're trying to do—validate text:
This probably looks like unreadable magic, and the Tkinter docs give you no guidance. But the Tk docs for
validatecommand
show what it means:key
bit means that the command "will be called when the entry is edited".%P
means the "value of the entry if the edit is allowed". You can stick as many of those%
strings as you want into yourvcmd
, and they will be passed as arguments to yourvalidate
method. So, you could pass(vcmd, '%s', '%P', '%v')
and then definevalidate(self, s, P, v)
.True
orFalse
to accept or reject the change (or returnNone
to stop calling your validation function).Anyway, now, if the user attempts to edit the entry in any way, then the
Enter_0
button will be set toNORMAL
if their edit would give you a non-empty string,DISABLED
otherwise.Variable tracing is conceptually a lot clunkier, but in practice often simpler. It's also not completely documented, but at least it's somewhat documented.
The idea is to create a
StringVar
, attach it to theEntry
, and put a "write trace" on it, which is a function that gets called every time the variable is updated (which happens every time theEntry
changes contents). Like this: