Tkinter stands for “Tk interface”: the package with the same name on many Linux distributions provides the Python bindings for the Tcl/Tk GUI toolkit. Although other graphical toolkit can be used from Python, like Qt or GTK, Tkinter is the standard (the Python IDLE editor and development environment is written using this toolkit, for example) and probably the easiest to work with. In this tutorial we see the basic concepts behind the usage of Tkinter and how to create and interact with some of the most used widgets.
In this tutorial you will learn:
- How to install Tkinter on the most used Linux distributions
- How to create the root window
- How to add a widget to the root window
- How to specify a button action
- How to use control variables
- How to create entry, label, checkbox and radio widgets
- The pack, grid and place layout manager methods
Software requirements and conventions used
|Category||Requirements, Conventions or Software Version Used|
|Other||Root privileges to install Tkinter|
|Conventions||# – requires given linux-commands to be executed with root privileges either directly as a root user or by use of
$ – requires given linux-commands to be executed as a regular non-privileged user
Although Python is installed by default as part of even the most minimal Linux systems, Tkinter comes not bundled with it; however, it is included in the official repositories of practically all the most used Linux distributions, therefore it is very easy to install. Let’s see how. Supposing we are using Fedora as our daily driver, to install Tkinter, we would run:
$ sudo dnf install python3-tkinter
If instead we our running on Debian, Ubuntu, or one of their derivatives, the package is called
python3-tk, and can be installed by running:
$ sudo apt-get update && sudo apt-get install python3-tk
On Archlinux, to install Tkinter, we just have to pull in the
tk package. To accomplish the task, we use the
pacman package manager, and run:
$ sudo pacman -Sy tk
Once the installation is performed without problems, we open a terminal and run the following command:
$ python3 -m tkinter
The following demonstrative window should appear:
If we click on the button with the “QUIT” text, the window will be closed; if we click on the “Click me!” button, instead, we can see how the text of the button itself will change.
The Root window
Let’s start from the basics. To create a graphical user interface with Tkinter and python, the first thing we have to do, as you can imagine, is to import the
tkinter module. Once the module is imported, we need to create the root window. All the widgets we will use, will ultimately have this window as their parent. A root window is obtained by creating an instance of the
import tkinter if __name__ == '__main__': root = tkinter.Tk()
Now we have our root window, however, if we try to execute the script, nothing is displayed. This is because we need to start what is called the event loop. The event loop is a loop which runs as long as the root window is not destroyed, so that the application can handle all the events such as the click of a button. To start the event loop, all we have to do is to invoke the
mainloop method on the root object:
import tkinter if __name__ == '__main__': rootwindow = tkinter.Tk() rootwindow.mainloop()
If we try to re-launch the script at this point, we should visualize the following window:
The way our graphical interface looks now is pretty useless, let’s admit it. What we can do to make it more useful, is to add a button to it. Let’s see how to do it.
Adding a button to the root window
First the code, than the explanations:
import tkinter if __name__ == '__main__': rootwindow = tkinter.Tk() button = tkinter.Button(rootwindow, text="Click me!") button.pack() rootwindow.mainloop()
Let’s analyze the code we added above. We generated the button by creating an instance of the
tkinter.Buttonclass. The first argument we pass to the constructor of a widget class, is a reference to its parent, which in this case is the root window itself. We also used the
textargument to specify the text which should be visualized on the button.
After we created the instance of the
Button class, we invoked the
pack method on it; this is essential for the widget to be displayed. The method is one of the three we can use to manage the geometry and layout of a widget. We will talk about them in a moment. For now, let’s try to re-launch our script, and see what we obtain:
As expected, the button widget is visualized with the text we specified in our code. If we click on it, however, nothing happens, and a button which performs no actions has no sense.
Specifying the button action
How we can specify the action or command which should be performed when the user clicks on a button? All we have to do is to use the
command argument of the
Button class constructor. Just as an example, let’s say we want to change the background color of the root window when the button is clicked. Let’s modify our code:
import tkinter def change_root_background_color(): rootwindow.config(background="red") if __name__ == '__main__': rootwindow = tkinter.Tk() button = tkinter.Button(rootwindow,text='Click me!',command=change_root_background_color) button.pack(pady=10) rootwindow.mainloop()
Let’s see what changes we made. First of all we added the
command argument to the
Button class constructor. As value to the
command parameter, we passed a function, which is executed when the click event is received. Another change we made, was to use the
pady parameter of the
pack method: this change is purely aesthetic, and is needed to add a vertical (y axis) padding expressed in pixels, to the widget. We made this to be able to visualize the root window background.
change_root_background_color, we wrote the code necessary to change the background color of the root window. The appearance of a window or a widget can be specified by using many parameters when the appropriate class is initialized, or later by using the
config method. To specify the background color, we use the
background parameter (it can be abbreviated to
bg), and pass the color we want to use as value. In this case we used
red, the color name, however, we could also have used its hexadecimal representation (“#FF0000”).
If we now launch our script, and click on the button, we obtain the following result:
In the previous example as value of the
command parameter we passed the name of the function to be executed when the click event is received. This function doesn’t accept any arguments, since the “red” color is hard-coded in it. What if it accepted the color to use as argument? How could we pass it when specifying the command? In such cases we want to use a
lambda, or anonymous, inline function:
import tkinter def change_root_background_color(color): rootwindow.config(background=color) if __name__ == '__main__': rootwindow = tkinter.Tk() button = tkinter.Button(rootwindow,text='Click me!',command=lambda: change_root_background_color("red")) button.pack(pady=10) rootwindow.mainloop()
Since the command to be executed is very simple, and doesn’t contain any complex logic, by using the lambda function we could simplify our code, and remove the
import tkinter if __name__ == '__main__': rootwindow = tkinter.Tk() button = tkinter.Button(rootwindow, text='Click me!', command=lambda: rootwindow.config(background="red")) button.pack(pady=10) rootwindow.mainloop()
In the previous examples we saw the basic usage of a button widget. The button we created just responds to the click event; others like the entry widget, let the user enter a value. We can create an “entry” widget by instantiating the
tkinter.Entry class. Suppose we want create a field to let the user enter his/her name; we would write:
username_entry_widget = tkinter.Entry(rootwindow)
The created widget would look similar to the following:
At this point a question should arise. In our code, how can we get the text the user enters in the widget? We can do that by using control variables. Control variables are created by using the following classes:
The name of the classes are pretty self-explanatory. What to use depends on the type of data we need. The value associated with a control variable can be retrieved by using the
get method. The type of variable returned by the method depends on what class has been used. As you can expect,
StringVar.get returns a string,
IntVar.get returns an integer,
DoubleVar.get returns a float, and
BooleanVar.get returns a boolean value.
When a control variable is associated with a widget, they are synchronized with it, so if the variable value changes (we can use the
set method to change its value in our code) the content of the widget is updated, and vice-versa:
username_var = tkinter.StringVar() username_entry_widget = tkinter.Entry(rootwindow, textvariable=username_var)
We associated the control variable to the widget via the
textvariable constructor parameter (in other widgets, like checkboxes or radio, we would use the
variable parameter instead). To retrieve the name the user entered in the widget, we just would call:
A control variable can be created also with a default value: all we have to do, is to specify it in the constructor. Although it doesn’t make much sense, to use a default name for our variable, we would write:
username_var = tkinter.StringVar(value="Egidio")
The label, checkbox and radio widgets
We briefly saw how to create a “button” and an “entry” widget. Other widgets that are used very often are: label, checkbox and radio. Let’s see how to create them.
To create a label widget we need to instantiate the
tkinter.Label class. This type of widget is used just to display some text, which can be specified via the
text argument. To add a label widget to our root window we would write:
label = tkinter.Label(rootwindow, text="Our first label")
The checkbox widget can be used to let the user perform a choice like selecting a certain feature. We can create one by instantiating the
tkinter.Checkbutton class. To ask the user confirmation, for example, we could associate them with a
confirmation = tkinter.BooleanVar(value=True) checkbox = tkinter.Checkbutton(rootwindow, text="Confirm" variable=confirmation)
confirmation variable associated with the widget is set to
True, the widget appears as “checked” by default:
The radio button widget let the user perform a selection between a set of options. If multiple radio buttons are associated with the same variable, only one can be checked at a time. To create a radio button widget, we use the
Radiobuttonclass. Supposing we want the user to choose a color between white and black, setting the latter as default. Here is what we could write:
color_variable = tkinter.StringVar(value="black") white_radio = tkinter.Radiobutton(rootwindow, text="White", variable=color_variable, value="white") black_radio = tkinter.Radiobutton(rootwindow, text="Black", variable=color_variable, value="black")
The pack, grid and place layout manager methods
We previously saw that when we initialize a widget via the appropriate class, and don’t call the
pack method, it is not visualized. As we said,
pack is one of the three layout manager methods available. The other two are:
place. Let’s briefly see what are the main differences between them.
pack method is the simplest: it should be used only in the most simple cases, where a complex layout is not requested, since it just stacks widgets in one of the four sides of the window. We already saw an example of its usage.
grid method is more modern and allows us to place widgets in the window using a rows/columns grid as a reference. It is the recommended choice in all but the most simple cases. When using the grid method, we can specify in what row and column the widget should be placed. For example, to place the button in the second column of the first row (rows and columns count are zero-indexed) we would write:
To make a widget extend on more than one column or one row, we would use the
rowspan arguments respectively. For example to make the button be placed on the first row and use two columns starting for the first one, we would write:
button.grid(row=0, column=0, columnspan=2)
Finally, with the
place method we can explicitly position a widget in the parent window by using static coordinates. When using this method, as you can imagine, is pretty difficult to handle events such as the changes in dimension of the parent window. By using web development terminology, we could say that our layout would not be very “responsive”.
Layout manager methods cannot be mixed: the same one must be used for all the widgets with the same parent window.
In this tutorial we performed our very first steps in the Tkinter world, and we saw how to create basic graphical interface elements using said library. We saw how to install Tkinter on the most used Linux distributions, how to create a root window and add widgets to it, how to use the button, entry, label, checkbox and radio widgets and manage user input via control variables. Finally, we saw what are the layout and geometry manager methods, and the difference between them.