Textbox (Entry) Validation in Tk (tkinter)
We have already seen in a previous post how to work with textboxes using the ttk.Entry
class in a Tcl/Tk desktop application. Now let's see how to validate the text that the user writes within a certain textbox, for example, in order to allow only numbers, dates, or other formats, or to apply other types of restrictions.
Let's start with the following code, which creates a window with a textbox (entry
).
|
from tkinter import ttk
|
|
import tkinter as tk
|
|
|
|
root = tk.Tk()
|
|
root.config(width=300, height=200)
|
|
root.title("My App")
|
|
entry = ttk.Entry()
|
|
entry.place(x=50, y=50, width=150)
|
|
root.mainloop()
|
Suppose we want the user to only be able to enter numbers. To do this, we first create a function that will be called every time the user types, pastes, or deletes text in the textbox:
The text
parameter is the string that the user is trying to type or paste into the textbox. If the user is typing, text
will probably be a single character, while if he is pasting something from the clipboard, it can be an entire text. The isdecimal()
string method returns True
if the string is numeric-only, False
otherwise. We are using the return value of isdecimal()
as the result of our own function. This is very important for the validation process. When the result of validate_entry()
is False
, Tk will not allow the user to enter the character or text passed as argument.
Now let's tell our textbox the function that should be called to verify that the content is valid. To do so, change line 7 of the first code into:
Let's clarify this that looks a bit strange, but it's very simple. The first validate
argument tells the textbox what type of validation we're looking for: "key"
means text input. The second is a bit more complex: we pass a tuple that contains the function that is going to take care of validating the data (validate_entry()
, which we must be previously registered via root.register()
) and then a string denoting what information we want to receive as an argument in that function ("%S"
means the text entered by the user).
Complete code:
Run the program and voila! You will see that the user is no longer allowed to enter anything other than numbers.
Let's move on a bit. What happens if, in addition, we want the maximum number of entered characters to be ten? We would need to have in our validate_entry()
function a string with the previous text of the textbox plus the text that is about to be entered, in order to calculate its length and return False
in case that it has more than ten characters. So let's tell Tk we want that data in our function, by adding the string "%P"
to the validatecommand
argument:
And let's change the definition of our function, which will now take two arguments:
text
is the text that the user wants to enter (before it is actually inserted!) and new_text
is the text already contained in the textbox (if any) plus text
. Now let's apply the new restriction:
Great! Let's look at one last example.
Let's say our text box only accepts dates in dd/mm/yyyy
format (for example, 14/08/2022
). What restrictions can we apply? First of all we must make sure that the text has no more than ten characters, just like before. The next thing would be to check that dd
, mm
and yyyy
are decimal numbers. Finally, that between the day and the month and between the month and the year there is a /
(slash) that works as a separator.
Since we're only using the new_text
argument, we're going to modify validatecommand
on the widget creation:
|
entry = ttk.Entry(
|
|
validate="key",
|
|
# We just need "%P".
|
|
validatecommand=(root.register(validate_entry), "%P")
|
|
)
|
Perfect! Now our textbox only accepts dates in the specified format.
Other possible options for validatecommand
are "%d"
, "%i"
and "%s"
(note the lowercase). "%d"
provides an argument that determines the action being validated ("1"
when adding text, "0"
on deletion), which is particularly useful if you want to apply validation when text is added but not when it is deleted, or vice-versa. "%i"
indicates the position where the text is added. "%s"
(lowercase) is the content of the textbox before the modification. We can observe all these values with the following code:
In summary, to validate the insertion or removal of characters entered by the user in a textbox, we must:
Create a function with the validation logic that returns
True
(allow) orFalse
(don't allow).Put the name of the function and the arguments we want it to receive (
"%d"
,"%i"
, etc.) invalidatecommand
when creating the textbox (as we've shown) by usingroot.register()
.Add the
validate="key"
argument when creating the textbox widget.