Getting started with Tkinter for Python tutorial

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
Getting started with Tkinter for Python tutorial
Getting started with Tkinter for Python tutorial

Software requirements and conventions used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Distribution-independent
Software Python3, tkinter
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 sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

Installing Tkinter

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:

The Tk demonstrative window
The Tk demonstrative window

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 Tk class:

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 empty root window
The empty root 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.Button class. 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 text argument to specify the text which should be visualized on the button.

An example of a button widget
An example of a button widget

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.

Inside the 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”).

The result we obtained by clicking the button
The result we obtained by clicking the button

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 change_root_background_color function altogether:

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()

Control variables

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 text entry widget
The text entry widget

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:

  • StrinVar
  • IntVar
  • DoubleVar
  • BooleanVar

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:

username_var.get()

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 label widget
The label widget

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 BooleanVar:

confirmation = tkinter.BooleanVar(value=True)
checkbox = tkinter.Checkbutton(rootwindow, text="Confirm" variable=confirmation)
The checkbox widget
The checkbox widget

Since the 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 Radiobutton class. 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 radio widgets
The radio widgets

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: grid and place. Let’s briefly see what are the main differences between them.

The 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.

The 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:

button.grid(row=0, column=1)

To make a widget extend on more than one column or one row, we would use the columnspan or 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.

Conclusions

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.



Comments and Discussions
Linux Forum