Python Labs : Building a Graphical User Interface (GUI) with Tkinter

Madhawa Perera
10 min readJun 27, 2019

--

If you are interested in developing applications with GUI and you have a basic knowledge about Python then this article is for you. This article will help you to develop an application with a GUI using Python. I will be discussing concepts like windows, frames, and widgets like radio buttons, dropdowns, buttons, text fields etc. that you might have seen in GUI applications. So far in the "Python Labs" series, I was discussing programs that have command-line input and outputs. In this article, we will be building the GUI as shown in Figure 1 below. If you are new to creating GUIs with Python then this article is for you.

Figure_1

Tkinter is a module/library developed by Fredrik Lundh. It is cross-platform compatible (means that you can run this independent of the operating system that you are using). Further, you don't need to add this module to your Python distribution to get started. Tkinter is by default ported to Python in the form of TKinter module. That is a quick overview of the module that we are going to use to build Figure 1.

Here onwards I will go through all the important section of the code that needs to build the GUI shown in Figure 1. Once you get going and understand the basics and how to use this module/library then it is easier for you to build what you need on your own. There are plenty of resources available online for this module. Yes, it is that popular. Let's get started.

Sample_Code_1

As I mentioned above, Tkinter is in your default Python distribution. Thus, you can import it straight away. [No need pip installs :) ]. In the Sample_Code_1 above, I have imported all the functionalities in Tkinter using *.

Window

Let's start exploring Tkinter functionalities. Firstly, let's create a window. A window can hold a set of widgets. We can add a bunch of widgets like buttons, dropdown menus, radio buttons etc in a window. It's like the base or the root container. A window has the capabilities to close, minimize and maximize and altering its size. Refer the sample_code_2 which creates your root window.

Sample_Code_2

Sample_ Code_2 will give you the output as in Figure_2. Nothing but an empty window. What line 4 in Sample_Code_2 does is, it allows your window to continuously be on the screen until you decide to close it. If you run the code without that line, what will happen is you won't be able to see the windows comes and go. Because your computer is super fast, therefore it pops the window and closes it, since you haven't asked to continuously run it. So what mainloop() does is, it kind of put your code in an endless loop so that your window will be continuously displayed until you close it.

Figure_2

Further, you can edit properties/attributes of a window (Since we name it rootWindow here onwards I will use that name) such as title, geometry etc. Refer the Sample_Code_3 below along with the Figure_3. You can see I have set "Hello World" as the title and made the size of the window to 300x300 (width x height)(you can see it is a square).

Sample_Code_3
Figure_3

Frames

Let's lean the concept called frames (This is for extra knowledge, not related to the task of building Figure_1 so you can skip this if you do not want to learn about frames). Before you start adding some widgets in your window, know what is a frame. Frames can be used to organize your widget placement in a window (Well you can do it without frames as well). It's like an invisible rectangle. You can have multiple frames inside a window and set different widgets in that. Let's first look at the Sample_Code_4 below.

Sample_Code_4

What this code does is, it creates two frames inside the window you created. If you run the code you will see the same output as in Figure_3. Yet, as I mentioned above what this has done is, it has created two invisible rectangles as shown in Figure_4. (I drew those two rectangles by editing the Figure_3 screen capture just to help you to understand).

Figure_4

Let's try to understand the Sample_Code_4. What line 8 does is, it creates an invisible rectangle which could be placed inside a window(rootWindow). Once you pass the rootWindow instance inside the Frame class it will create a frame that could fit into rootWindow. Now you have the created frame and named the variable as topFrame. Even though the frame is created with your code, now you need to place it inside the window. Line 9 does that. So you pack it inside your rootWindow using pack() method. Further, you can see I have used an additional parameter to say that pack it in the TOP of the rootWindow. The parameter side is used to place your frame somewhere you want inside your window. You can provide values like TOP, BOTTOM etc.

In a nutshell, that's about frames. However, I am not going to use frames to organize my widgets in the process of building Figure_1. Instead, I'm going to use a grid layout (Another way of arranging widgets inside a window). Yes, grid means the normal grid you know. You can place your widgets by giving the row and the column numbers.

Grid layout

Think of a spreadsheet. When you are using grid layout you can think of your window as a spreadsheet and then place your widgets accordingly. Let's jump into the Sample_Code_5.

Sample_Code_5

Sample_Code_5 will generate the Figure_5 where you can see how the labels are placed.

Figure_5

Let's quickly go through the Sample_Code_5. In line 12 what I have done is defining a label. I will discuss this further in the section below. For the moment, keep in your mind that a label is a widget that you can use to put some text inside your window. Thus, line 12 defines the widget and some of its characteristics. Likewise, I have defined 7 labels. Next task is to place these labels in a grid layout. Line 22–29 does that. It is simple as passing the required row and the column number as parameters in widget.grid() method.

What's important here is, if you look at line number 26 I have invoked a different method on the window class itself. What this does is creating an empty row in the window. You can see that I have used row0, row1 and row3 but not row 2. If I didn't use line 26, even though you asked to put label 5 to 7 on row 3, the program will put them in row 2 as in the Figure_6. Therefore, I have specified a spacing(empty) row here. Likewise, you can specify the spacing on columns/rows in a grid (including those that contain no widgets) by running the grid_columnconfigure() and grid_rowconfigure() methods on the parent of the widgets (in this scenario, the parent would is the rootWindow). If you use a frame then the parent will be the frame.

Figure_6

There are a lot more things you can with a grid layout. I hope this will be a good start for you to get going.

Labels, Buttons, Radio Buttons, Drop down menus

Now let's see how to work with widgets. Finally!. Widgets are the elements that we are going to place in a window. Here, I'm going to explain about 4 widgets as mention in the subtopic above. Well, they are pretty much similar in the way they were defined. Once you know how to create a label then the other things are pretty much similar except the name of the class. Let's jump to the Sample_Code_6.

Sample_Code_6

First, let's look at labels. Labels can be used to simply display texts on a window. See line 14 on Sample_Code_6. I have passed several parameters to the class Label in order to make the text "Welcome to Tkinter Minion", as shown in Figure_7 below. First, I have passed the window where I need to set label. That is rootWindow. Then the text that I want to display with text="". Parameter fg set the font colour here. Further, I have set the font style, size etc. There are more parameters that you can use with labels. You can read more here. Also, Google is a good source where you will find plenty of examples.

Line 19–21 is utilized to define the dropdown menu. Firstly, I have defined a variable to hold the value that is selected by the user (from the dropdown). Then I set the default value. If the user didn't select any then this will be the input that is going to consider. Next, just like the Label class, we use OptionMenu class here. Rest is pretty similar to what we do with labels. First, we have to pass the window (rootWindow) where we need to display the dropdown. Then the variable (charater_name_entry) which we want to store user input (user selected value from the dropdown menu). After that, the list of values we want to display in the dropdown menu is passed as parameters. Again, you can read further here.

Line 25–29 is used to define two radio buttons (Yes and No) as shown in Figure_7 below. Just like the dropdown menu we need a variable to store the user input. Thus, age_value_choice variable is defined and passed as a parameter to Radiobutton class. I will describe only the new parameter that I have used here. Others are similar as in labels and dropdown menu. The new parameter is the value. You can use any value as a reference to each radio button. This is to identify which radio button user has clicked and then further to carry on development based on that. For example, here, if the user clicks on 'Yes', then the value '1' will be stored in the age_value_choice variable. Thus, you can later use it for develope programming logic.

The final widget that I'm gonna explain here is the button. The button in Sample_Code_6 does not have any action involved with it. That means, even though this code creates a button, we haven't define what to do in an event of a click. In order to do that we have to pass an extra parameter call command. You can see this in Sample_Code_7 line number 67. We have associated the lets_see_button with a function call show_info() . What this does is once a user clicks on the button then what's inside the method show_info() will be executed. Hence we say, the button is associated with an action. You can read further about button widget here.

Before going to the final section, please make a note on the following two websites which I found really helpful when working with Tkinter.

"Tkdocs.com (https://tkdocs.com/tutorial/widgets.html) and Effbot.org (http://effbot.org/tkinterbook/tkinter-index.htm) are two good reference website if you are interested in learning further about Tkinter and its capabilities."

If you execute the Sample_Code_6 correctly it will give you the output as in Figure_7 below.

Figure_7

We are now all set to develop the Figure_1. Other than some brush-up and implementing the function for the button click, we are all set. I have shared the Sample_Code_7 below with complete implementation.

If you look at the function named show_info() in Sample_Code_7, you will see that I have used a couple of new methods. I will quickly go through what each of these lines (inside the method) do.

message_txt is the variable which we hold the Text class. This is the place where we used to display "You are not authorized!" text if the user select radio button associated with 'No'. The functionmessage_txt.insert(0.0, "You are not authorized") does this. Parameter 0.0 says start printing the text from the leftmost corner of the text box. The function message_txt.delete(0.0, 'end') is used to clear this text box every time a user clicks the button. Parameter 0.0 and 'end' means from starting point to the end. If we don't use this delete() function then, every new message will be displayed one after another. It won't delete the previous action.

character_name_entry is the variable which holds the value of the value that user select from the dropdown menu. character_name_entry.get() will give the user's selected value. Similarly, age_value_choice.get()
gives value associated with the selected radio button. If you see line number 45–49 in Sample_Code_7 you will see that we have assigned value 1 for 'Yes' and 2 for 'No'.

Line 15, 17 and 19 is setting the appropriate image based on the user's selection of the dropdown list. Again, before displaying the new image we have to delete the previously loaded image from the grid. This removing part is done by using the for loop in line 9–11. Calling the method grid_forget() will remove it from the window. The method grid_slaves() is call on the parent (which is rootWindow here as we don't use any frames) to find out all widgets mapped to the grid. Methodgrid_info() allows to find the exact position of the widget. In here I want to find the widget set on row number 6.

Well, that's pretty much about it. Now you know all the ingredients I have used to make the soup. Sample_Code_7 has the full recipe. You can copy paste and run the code but make sure to have gru.png, bob.png, kevin.png and no_minion.png files parallel to your .py file. That means everything should be in the same folder. If everything works smoothly output should be the Figure_1. Happy coding…

Sample_Code_7

N.B. On OSX, there will be a fixed height for labels, buttons etc. and will not expand vertically. Also, there are some issues with setting the background colour of a button. You can refer to the commented lines (line 85–92) in Sample_Code_7 for further information. For me fill=X and fill=Y did not work, instead, I used the value fill=BOTH and it expanded horizontally. Let me know if you find a way to solve this. :)

If you like this article and the content that I create, you can buy me a virtual coffee ️😊;

Cheers!

--

--

Madhawa Perera
Madhawa Perera

Written by Madhawa Perera

Research Engineer, HCI Researcher, and Sessional Academic at ANU. Passionate about crafting human-centered AI experiences through Mixed Reality (AR/VR)

No responses yet