GEOG 489
Advanced Python Programming for GIS

2.5.1 Tkinter

PrintPrint

As we already mentioned, Tkinter is the standard GUI for Python, but only in the sense that it is a package in the Python standard library, so it is available for all platforms without requiring any additional installation. Its name stands for “Tk interface”. It is certainly possible that you have not heard about Tk and Tcl before but Tk is one of the oldest free and open-source, cross-platform GUI toolkits (written in the Tcl scripting language and initially released in 1991) and has been adopted for building GUIs in many programming languages. Tkinter has been written by Fredrik Lundh and is essentially a set of wrapper classes and functions that use a Tcl interpreter embedded into the Python interpreter to create and manage the Tk GUI widgets.

To get an impression of how tkinter is used to build a GUI in Python, let us look at the example of creating a simple miles-to-kilometers conversion tool. The tool is shown in the figure below. It has a single window with five different widgets: two label widgets, two widgets for entering or displaying single lines of text, and a button in the middle. The user can enter a number of miles into the line input field at the top, then press the button, and then the entered number of miles will be converted and displayed as kilometers in the line input field at the bottom.

Screenshot of GUI miles to kilometers converter
Figure 2.7 Tkinter version of the miles-to-kilometer converter GUI

We are using a line input field to display the resulting distance in kilometers just to make things more symmetrical. Since we do not want the user to be able to enter anything into this text field, it has been disabled for input and we could just as easily have used another label widget. The Python code to create this tool with the help of tkinter is shown below and the explanation of the code follows.

from tkinter import Tk, Label, Entry, Button, DISABLED, StringVar 

def convert(): 
    """Takes miles entered, converts them to km, and displays the result""" 
    miles = float(entryMiles.get()) 
    kilometers.set(str(miles * 1.60934)) 

# create the GUI 

rootWindow = Tk() # create main window 
rootWindow.title("Miles to kilometers") 
rootWindow.geometry('500x200+0+0') 
rootWindow.grid_columnconfigure(1, weight = 1) 

labelMiles = Label(rootWindow, text='Distance in miles:') # create label for miles field 
labelMiles.grid(row=0, column=0) 

labelKm = Label(rootWindow, text='Distance in kilometers:') # create label for km field 
labelKm.grid(row=2, column=0) 

entryMiles = Entry(rootWindow) # create entry field for miles 
entryMiles.grid(row=0, column=1, sticky='w,e') 

kilometers = StringVar() # create entry field for displaying km 
entryKm = Entry(rootWindow, textvariable = kilometers, state=DISABLED) 
entryKm.grid(row=2, column=1, sticky='w,e') 

convertButton = Button(rootWindow, text='Convert', command = convert) # create button for running conversion 
convertButton.grid(row=1, column=1) 

# run the event processing loop  

rootWindow.mainloop() 

Let us ignore the first few lines of Python code for a moment and first look at lines 10 to 29. This is where the GUI of our little program is produced starting with the root window widget in lines 10 to 13. The widget is created by calling the function Tk() defined in tkinter and the created object is stored in variable rootWindow. We then use different methods of the widget to set its title, initial size, and some properties for its grid layout that we are going to use to arrange the child widgets within the content area of the root window.

Next, the label saying “Distance in miles:” is created. The tkinter widget class for labels is called Label and we provide rootWindow as a parameter to Label(…), so that the widget knows what its parent widget is. As mentioned, we will be using a grid layout, namely one with three rows and two columns. We place the created label in the cell in the first row and first column of its parent by calling the grid(…) method with row = 0 and column = 0. We then take the exact same steps to create the other label and place it in the third row of the first column.

In the next steps, the two text input fields are created as widget objects of the tkinter Entry class. An additional parameter sticky=’w,e’ is used for placing these widgets in the grid. This parameter says that the widgets should expand horizontally (west and east) to fill the entire cell. This is required to make the layout fill out the window horizontally and have the text field grow and shrink when the window is resized. Moreover, the Entry widget for displaying the distance in kilometers is set to DISABLED so that the user cannot enter text into it, and it is associated with a variable kilometers of tkinter class StringVar which is needed for us to be able to change the text displayed in the widget from code.

Finally, the button is created as a widget of tkinter class Button. What is new here is what happens with the ‘command’ parameter given to Button(…) in line 28. Here we are saying that if this button is clicked, the function convert() that we are defining at the top of our code should be executed to deal with this event. So this is an example of connecting an event to an event handler function. What happens in convert() is very simple: With the help of the get() method, we get the current text from the Entry widget for the distance in miles, multiply it with a constant to convert it to kilometers, and then use the set() method of the StringVar object in variable kilometers to change the text displayed in the Entry widget to the distance in kilometers associated with that variable.

In the last line of the code, we call the mainloop() method of our root window to start the infinite event processing loop. The program execution will only return from this call when the user closes the root window, in which case the program execution will be terminated.

The only part of the code we haven’t talked about is the first line where we simply import the widget classes and other auxiliary classes from tkinter that we need in our code.

Hopefully, it is clear that this is just a very prototypical implementation of a miles-to-kilometers conversion tool focusing on the GUI. We have neither implemented any sort of checking whether input values are valid nor any sort of error handling. It is therefore very easy to make the tool crash, e.g. by entering something that is not a number into the field for distance in miles. If you haven’t already done so, we suggest you create a Python script with the code from above and try out the tool yourself and see how the layout adapts if you resize the window. Feel free to experiment with making small changes to the code, like adapting the text shown by the labels or adding another button widget to the currently still empty second row of the first column; then make the button call another event handler function you write to, for instance, just print some message to the console.

Don’t worry if some of the details happening here don’t seem entirely clear at the moment. A real introduction to creating GUIs with Python will follow later in this lesson. Here we just wanted to give you a general idea of how the different concepts we discussed in Section 2.4 are realized in tkinter: You saw how different widgets are created, how they were arranged in a grid layout by placing them in different cells of the layout, how to connect an event (button clicked) with a self-defined event handler function (convert()), and how to execute the application by starting the event processing loop (rootWindow.mainloop()). Now let’s move on and talk about QT as an alternative to tkinter and see how this same example would look like when produced with the PyQt instead of tkinter.