Python 3 / tkinter 3 value selection fields

by Alex
Python 3 / tkinter 3 value selection fields

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

Selecting numeric values

The previous material was about working with text input, but sometimes you need to restrict the field to work exclusively with numeric values. This is necessary for the Spinbox and Scale classes, which allow users to select a numeric value from a range or list of valid choices. However, there are differences in how they are displayed and configured. This program has Spinbox and Scale for selecting an integer from 0 to 5:

import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.spinbox = tk.Spinbox(self, from_=0, to=5)
self.scale = tk.Scale(self, from_=0, to=5,
orient=tk.HORIZONTAL)
self.btn = tk.Button(self, text="output values",
command=self.print_values)
self.spinbox.pack()
self.scale.pack()
self.btn.pack()
def print_values(self):
print("Spinbox: {}".format(self.spinbox.get()))
print("Scale: {}".format(self.scale.get()))
if __name__ == "__main__":
app = App()
app.mainloop()

For debugging purposes, a button has also been added that outputs a value when pressed: Выбор числовых значений

How value selection works

Both classes accept from_ and to parameters, which denote a range of matching values – the underscore at the end is mandatory because the from parameter is originally defined in Tck/Tk, although it is a reserved keyword in Python. A handy feature of the Scale class is the resolution parameter, which adjusts the rounding accuracy. For example, a value of “0.2” will allow you to choose such: 0.0, 0.2, 0.4, and so on. The default value is 1, so the widget rounds all entered numbers to the nearest integer. You can also get the value of each widget using the get() method. The important difference is that Spinbox returns the number as a string, while Scale returns an integer or a floating-point number if the rounding takes decimal values. The Spinbox class has settings that are similar to those of Entry: textvariable and validate parameters. The only difference is that the rules will be limited to numeric values.

Creating radio buttons fields (radio buttons)

With the Radiobutton widget you can let the user choose among several options. This works for a relatively small number of mutually exclusive choices. Multiple Radiobutton instances can be connected using the Tkinter variable. In this way, if an option is selected that has not previously been selected, it will override the selection of the previous one. The following example creates three buttons for the parameters Red, Green and Blue. Each press displays the name of the corresponding color in lower case:

import tkinter as tk
COLORS = [(("Red", "red"), ("Green", "green"), ("Blue", "blue")]
class ChoiceApp(tk.Tk):
def __init__(self):
super().__init__()
self.var = tk.StringVar()
self.var.set("red")
self.buttons = [self.create_radio(c) for c in COLORS]
for buttons in self.buttons:
button.pack(anchor=tk.W, padx=10, pady=5)
def create_radio(self, option):
text, value = option
return tk.Radiobutton(self, text=text, value=value,
command=self.print_option,
variable=self.var)
def print_option(self):
print(self.var.get())
if __name__ == "__main__":
app = ChoiceApp()
app.mainloop()

If you run the script, it will show the application where Red is already selected. Создание полей с радиокнопками

How Radiobuttons Work

To avoid repeating code to initialize Radiobuttons, you need to define a service method that is called from the generated list. Thus, the values of each tuple in the COLORS list are unpacked and the local variables are passed as options to the Radiobutton. It is very important to avoid repetition if possible. Since StringVar is common to all Radiobuttons, they are automatically concatenated, and the user can choose only one option. The default value in the program is “red. But what happens if this line is omitted, and the StringVar value doesn’t match any of the buttons? In this case it will coincide with the default value of option tristatevalue, i.e., the empty string. Because of this, the widget displays in undefined “tri-state” mode. You can change this with the config() method, but even better, set the correct default value so that the variable is initialized in a valid state.

Implementing checkboxes

Choosing from two options is usually implemented using checkboxes with an enumeration of options, where each option is independent of the others. In the following example, you can see how this concept is implemented using Checkbuttons. The following application demonstrates how to create checkboxes that must be associated with an IntVar variable to keep track of the state of the button:

import tkinter as tk
class SwitchApp(tk.Tk):
def __init__(self):
super().__init__()
self.var = tk.IntVar()
self.cb = tk.Checkbutton(self, text="Active?
variable=self.var,
command=self.print_value)
self.cb.pack()
def print_value(self):
print(self.var.get())
if __name__ == "__main__":
app = SwitchApp()
app.mainloop()

In this example, the value of the widget is simply displayed each time it is clicked. Реализация чекбоксов

How Checkboxes Work

Similar to Button Checkbuttons take Command and text parameters. You can use the onvalue and offvalue options to define values for the checked and empty checkboxes. An integer variable is used because the default values are 1 and 0. But it can be any other integer. You can even use other types of variables with checkbuttons:

var = tk.StringVar()
var.set("OFF")
checkbutton_active = tk.Checkbutton(master, text="Active?", variable=self.var,
onvalue="ON", offvalue="OFF",
command=update_value)

The only restriction is that onvalue and offvalue must match the Tkinter variable type. In that case, since “ON” and “OFF” are strings, the variable must also be StringVar. Otherwise, the Tcl interpreter will return an error when trying to set a corresponding value to a different type.

Displaying a list of items

The Listbox widget contains text items that the user can select using the mouse or keyboard. It is possible to configure whether one or more items will be available for selection. The following program creates such a selector, where the options are days of the week. There is a button to display the current selection, as well as a number of buttons to change the way the selection is made:

import tkinter as tk
DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"]
MODES = [tk.SINGLE, tk.BROWSE, tk.MULTIPLE, tk.EXTENDED]
class ListApp(tk.Tk):
def __init__(self):
super().__init__()
self.list = tk.Listbox(self)
self.list.insert(0, *DAYS)
self.print_btn = tk.Button(self, text="Print Selection",
command=self.print_selection)
self.btns = [self.create_btn(m) for m in MODES]
self.list.pack()
self.print_btn.pack(fill=tk.BOTH)
for btn in self.btns:
btn.pack(side=tk.LEFT)
def create_btn(self, mode):
cmd = lambda: self.list.config(selectmode=mode)
return tk.Button(self, command=cmd,
text=mode.capitalize())
def print_selection(self):
selection = self.list.curseselection()
print([self.list.get(i) for i in selection])
if __name__ == "__main__":
app = ListApp()
app.mainloop()

Try changing modes and look at the output: Отображение списка элементов

How selecting items from a list works

You can create an empty Listbox object and add all elements using the insert() method. The index 0 indicates that the elements should be added at the beginning of the list. On the next line, the DAYS list is unpacked, but individual elements can be added to the end with the END constant: self.list.insert(tk.END, "New item")
The current selection is extracted using the curselection() method. It returns the indexes of the selected items. And to further transform them into corresponding text items, the get() method is called for each item in the list. As a result, the list is displayed in STDOUT for debugging. In this example, the selectmode parameter can be changed to get different behavior:

  • SINGLE – one option;
  • BROWSE – one option, which can be moved with the arrow keys;
  • MULTIPLE – several variants;
  • EXTENDED – several variants with ranges, which are selected with the Shift and Ctrl keys.

If there are many items, it may be necessary to add a vertical scrollbar. To do this, the yscrollcommand option must be used. In this example, both widgets are wrapped in the same window. You just have to remember to specify the fill parameter, so that the scrollbar takes up all the space on the y-axis.

def __init__(self):
self.frame = tk.Frame(self)
self.scroll = tk.Scrollbar(self.frame, orient=tk.VERTICAL)
self.list = tk.Listbox(self.frame, yscrollcommand=self.scroll.set)
self.scroll.config(command=self.list.yview)
# ...
self.frame.pack()
self.list.pack(side=tk.LEFT)
self.scroll.pack(side=tk.LEFT, fill=tk.Y)

There is also an xscrollcommand parameter for the horizontal axis.

Related Posts

LEAVE A COMMENT