Creating, changing and checking text / tkinter 2

by Alex
Creating, changing and checking text / tkinter 2

Download lesson code from GitLab: https://gitlab.com/PythonRu/tkinter-uroki

Creating text elements

The Entry widget is a text element on a single line. Together with the Label and Button classes, it is one of the most used in Tkinter.

How to Create a Text Item

The following example shows how to create a login form with two instances for username and password fields. Each password character is displayed as an asterisk. The Login button displays the values in the console, and the Clear button deletes the contents of both fields, returning the focus to username:

import tkinter as tk
class LoginApp(tk.Tk):
def __init__(self):
super().__init__()
self.username = tk.Entry(self)
self.password = tk.Entry(self, show="*")
self.login_btn = tk.Button(self, text="login",
command=self.print_login)
self.clear_btn = tk.Button(self, text="clear,
command=self.clear_form)
self.username.pack()
self.password.pack()
self.login_btn.pack(fill=tk.BOTH)
self.clear_btn.pack(fill=tk.BOTH)
def print_login(self):
print("Login: {}".format(self.username.get()))
print("Password: {}".format(self.password.get()))
def clear_form(self):
self.username.delete(0, tk.END)
self.password.delete(0, tk.END)
self.username.focus_set()
if __name__ == "__main__":
app = LoginApp()
app.mainloop()

Как создать текстовый элемент

How instances work

Entry widget instances are created in the parent window or frame by being passed as the first argument. Optional keywords can be used to specify additional properties. The username in this example has none, and the password has a show argument with the string “*”, which will output each character as an asterisk. The get() method will get the current text as a string. This is used in the print_login() method, which outputs the contents of Entry in the standard output(stdout). The delete() method takes two arguments that represent the range of characters to be deleted. It is only important to remember that the indexes start at 0 and do not include the last character. If you pass only one argument, the character at that position is deleted. The clear_form() method removes the content from index 0 to the END constant, which clears all content. The focus is then returned to the username field. The content of the Entry widget can be modified using the insert() method, which takes two arguments:

  • index – the position where you want to insert the text (the index of the first one is 0)
  • string – the string that will be inserted

The standard pattern for resetting the content to its default value is a combination of the delete() and insert() methods: Another pattern is to add text where the cursor is. The INSERT constant is used for this: Like Button, the Entry class also takes the relief and state parameters to change the outline style and state. It is also worth noting that delete() and insert() calls are ignored when state is “disabled” or “readonly”.

Tracking Text Changes

Tk variables allow you to send notifications to applications when incoming values change. There are 4 classes of variables in Tkinter: BooleanVar, DoubleVar, IntVar, and StringVar. Each of them wraps a value of the appropriate Python type, which must match the type of widget attached to the variable. This feature is especially useful if you want to automatically update certain parts of the application based on the current state of the widgets.

How to track text changes

In the following example, an instance of StringVar is associated with an Entry that has a textvariable parameter. Such variables track write operations using the show_message() callback method:

import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.var = tk.StringVar()
self.var.trace("w", self.show_message)
self.entry = tk.Entry(self, textvariable=self.var)
self.btn = tk.Button(self, text="Clear",
command=lambda: self.var.set(""))
self.label = tk.Label(self)
self.entry.pack()
self.btn.pack()
self.label.pack()
def show_message(self, *args):
value = self.var.get()
text = "Hi, {}!".format(value) if value else ""
self.label.config(text=text)
if __name__ == "__main__":
app = App()
app.mainloop()

When something is entered in this widget, the text of the label is updated to the one that was composed with the value of the Tk variable. For example, if you type the word “World”, the label will display Hello, World! If you don’t enter any text at all, nothing will be displayed. To demonstrate the possibilities of interactive customization of the variable content, a button was added that clears the field when clicked. Как отслеживать изменения текста

How Changing Text Works

The first lines of the application’s constructor create an instance of StringVar and attach a callback function for write mode. Valid values for this mode:

  • w – called when the variable is written
  • r – called when the variable is read
  • u (from unset) – called when the variable is removed

When called, the callback function receives three arguments: the internal variable name, an empty string (it is used in other Tk variable types), and the mode that triggered the operation. When you declare it with *args, these arguments become optional, because the callback values are no longer used. The get() method of Tk wrappers returns the current value of the variable, and the set() method updates it. They also notify alltrace methods. Therefore, changing the contents of a field using the GUI and pressing the Clear button triggers a call to the show_message() method. The Tk variables are optional for field widgets, but they are mandatory for other widget classes, such as the Checkbutton and Radiobutton classes.

Validating text in fields

Most often, text entry fields are fields that follow certain validation rules, such as a maximum length or a certain format. Some applications allow you to enter any kind of content and perform validation after the entire form has been submitted. Under certain conditions, it is necessary to prevent the possibility of invalid content in a text field. The following examples will show how to implement this behavior by using validation options in the Entry widget.

How to validate text

The following application demonstrates how to validate text in an entry field using regular expressions:

import re
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.pattern = re.compile("^\w{0,10}$")
self.label = tk.Label(self, text="Enter login")
vcmd = (self.register(self.validate_username), "%i", "%P")
self.entry = tk.Entry(self, validate="key",
validatecommand=vcmd,
invalidcommand=self.print_error)
self.label.pack()
self.entry.pack(anchor=tk.W, padx=10, pady=10)
def validate_username(self, index, username):
print("validate character" + index)
return self.pattern.match(username) is not None
def print_error(self):
print("Prohibited character in username")
if __name__ == "__main__":
app = App()
app.mainloop()

If you run this script and enter a character other than a letter of the alphabet or a number, the content will not change, but instead an error message will be displayed in the console. The same will happen if you try to enter more than 10 characters, because the regular expression limits the total number.

How text validation works

When the validate parameter is key, validation is triggered any time the content is changed. The default value is none, which means that validation will not happen. The values can also be focusin or focusout, where validation is performed when focus is gained or lost. The focus value performs validation in both cases. In all situations, validation takes place if you set the value to all. The validatecommand function is called each time validation is started. It should return true if the content is validated. Otherwise it returns false. Because more information is needed to determine if the content is valid, a Tcl wrapper is created over the Python function using the register method of the Widget class. A substitution is then added for each parameter to be passed to the function. Eventually these values are grouped into a tuple. The described corresponds to the following line from the example: vcmd = (self.register(self.validate_username), "%i", "%P") The following substitutions can be used:

  • %d – type of action. 1 – add, 0 – delete, -1 – rest;
  • %i – index of the string to be inserted or deleted;
  • %p – content entity, if the change is allowed;
  • %s – the string content before the change;
  • %s – the string to be inserted or deleted;
  • %v- the type of validation in progress;
  • %v – type of validation that triggers the action;
  • %w – name of the Entry widget.

The invalidcommand parameter takes a function that is called when validatecommand returns false. The same substitutions can be applied to it as well, but in this example the print_error() method has been passed directly to the class. The Tcl/Tk documentation suggests that you should not mix validatecommand and textvariable parameters, because a failed Tk variable value will disable validation altogether. The same will happen if validatecommand does not return a boolean value. A detailed introduction to regular expressions is available in the official Python documentation at https://docs.python.org/3.7/howto/regex.html.

Related Posts

LEAVE A COMMENT