“Chapter 9. Develop GUI-Based Applications” in “Introduction to Computer Programming with Python”
Chapter 9 Develop GUI-Based Applications
In terms of user interface, there are two types of computer systems or applications: terminal-based, which can be run from a terminal, and those with a graphical user interface (GUI), or GUI-based. So far, the applications we have programmed have all been terminal-based. In this chapter you will learn how to develop GUI-based applications in Python.
Learning Objectives
After completing this chapter, you should be able to
- • explain terminal-based applications and GUI-based applications as well as their differences.
- • explain which Python libraries are available for developing GUI-based applications.
- • discuss the widgets, functions, other classes, and methods provided in the Tkinter module.
- • use widgets, functions, classes, and methods provided in the Tkinter module to design and implement a graphical user interface for a given application.
- • develop GUI-based applications using the Tkinter module.
- • discuss the themed Tkinter(Ttk) module and how it differs from the Tkinter module.
9.1 Terminal-Based Applications Versus GUI-Based Applications
A computer terminal is a device, often referring to a utility program in today’s Windows environment, that can receive and deliver data or commands. The following shows what a terminal on Windows 11 looks like:
(base) PS C:\Users\james>
A terminal-based application is a program that runs from the command line within a terminal. For that reason, terminal-based applications are also called applications with a command-line interface. The following shows a Python program with a command-line interface running within a terminal.
(base) PS C:\workshop\comp218\samples\project2> python '.\perfect number.py'
tell me the upper bound:33
6 = [1, 2, 3] 28 = [1, 2, 4, 7, 14]
(base) PS C:\workshop\comp218\samples\project2> python '.\perfect number.py'
tell me the upper bound:53
6 = [1, 2, 3] 28 = [1, 2, 4, 7, 14]
(base) PS C:\workshop\comp218\samples\project2>
The terminal-based program shown above takes an integer as upper bound from the user and then finds all perfect numbers between 1 and the upper bound. With a terminal-based application, only a keyboard can be used by users to interact with the application.
A GUI-based application provides users with a graphical interface so that users can interact with the application with keyboard and mouse. VS Code IDE is an example of a GUI-based application we have been using throughout this text.
The difference between terminal-based and GUI-based applications is obvious. Although GUI-based applications are more user-friendly and more common today, terminal-based applications still exist and are used by some IT professionals, such as system administrators.
In the next section, we will learn how to develop GUI-based applications with Python.
9.2 Designing and Developing GUI-Based Applications in Python
The key component of a GUI-based application is a graphical user interface (GUI) on which both mouse and keyboard can be used to interact with the application on a two-dimensional graphic interface. As mentioned above, GUI-based applications are more user-friendly than terminal-based applications. This is why most computer applications used today are GUI-based.
In general, you need to ask yourself the following questions when designing a GUI app:
- • What will be shown to users?
- • What input will be taken from users?
- • What actions will we allow users to take?
- • What actions will be taken in response to the users’ input?
- • Where do we display the results of the actions?
Several Python modules are available for developing GUI-based applications.
- • Tkinter, a de facto GUI library for Python applications, comes with the standard Python distribution so that you can import and use it right away. Documentation on tkinter can be found at https://docs.python.org/3/library/tk.html. You learned how to use Python modules and packages, including tkinter, in Chapter 8.
- • PyGObject is a Python implementation of GObject-based libraries such as GTK, GStreamer, WebKitGTK, GLib, GIO, and some others. If you have played with Linux, you will probably know the GTK- and GNOME-based graphical user interfaces. The project is hosted at https://pygobject.readthedocs.io/en/latest/.
- • PyQt5 is another GUI library for Python GUI-based application development that implements the well-known Qt graphic framework. Information about PyQt5 can be easily found on the internet, and its home is at https://pypi.org/project/PyQt5/.
We chose to use a module called tkinter for its popularity among Python application developers and because of its light weight. The tkinter module usually comes with the standard Python distribution. To test if you have it installed, run import tkinter as shown below to see if you will get the same output:
>>> import tkinter
>>> dir(tkinter)
['ACTIVE', 'ALL', 'ANCHOR', 'ARC', 'BASELINE', 'BEVEL', 'BOTH', 'BOTTOM', 'BROWSE', 'BUTT', 'BaseWidget', 'BitmapImage', 'BooleanVar', 'Button', 'CASCADE', 'CENTER', 'CHAR', 'CHECKBUTTON', 'CHORD', 'COMMAND', 'CURRENT', 'CallWrapper', 'Canvas', 'Checkbutton', 'DISABLED', 'DOTBOX', 'DoubleVar', 'E', 'END', 'EW', 'EXCEPTION', 'EXTENDED', 'Entry', 'Event', 'EventType', 'FALSE', 'FIRST', 'FLAT', 'Frame', 'GROOVE', 'Grid', 'HIDDEN', 'HORIZONTAL', 'INSERT', 'INSIDE', 'Image', 'IntVar', 'LAST', 'LEFT', 'Label', 'LabelFrame', 'Listbox', 'MITER', 'MOVETO', 'MULTIPLE', 'Menu', 'Menubutton', 'Message', 'Misc', 'N', 'NE', 'NO', 'NONE', 'NORMAL', 'NS', 'NSEW', 'NUMERIC', 'NW', 'NoDefaultRoot', 'OFF', 'ON', 'OUTSIDE', 'OptionMenu', 'PAGES', 'PIESLICE', 'PROJECTING', 'Pack', 'PanedWindow', 'PhotoImage', 'Place', 'RADIOBUTTON', 'RAISED', 'READABLE', 'RIDGE', 'RIGHT', 'ROUND', 'Radiobutton', 'S', 'SCROLL', 'SE', 'SEL', 'SEL_FIRST', 'SEL_LAST', 'SEPARATOR', 'SINGLE', 'SOLID', 'SUNKEN', 'SW', 'Scale', 'Scrollbar', 'Spinbox', 'StringVar', 'TOP', 'TRUE', 'Tcl', 'TclError', 'TclVersion', 'Text', 'Tk', 'TkVersion', 'Toplevel', 'UNDERLINE', 'UNITS', 'VERTICAL', 'Variable', 'W', 'WORD', 'WRITABLE', 'Widget', 'Wm', 'X', 'XView', 'Y', 'YES', 'YView', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_cnfmerge', '_default_root', '_exit', '_flatten', '_join', '_magic_re', '_setit', '_space_re', '_splitdict', '_stringify', '_support_default_root', '_test', '_tkerror', '_tkinter', '_varnum', 'constants', 'enum', 'getboolean', 'getdouble', 'getint', 'image_names', 'image_types', 'mainloop', 're', 'sys', 'wantobjects']
A GUI application starts with a frame or window of a given size in terms of pixels, which is divided into rows and columns. Each of the grids is numbered from top to bottom, left to right, as shown in the following diagram:
(0,0) | (0,1) | (0,2) | (0,3) | (0,4) | (0,5) |
(1,0) | (1,1) | (1,2) | (1,3) | (1,4) | (1,5) |
(2,0) | (2,1) | (2,0) | (2,3) | (2,4) | (2,5) |
(3,0) | (3,1) | (3,2) | (3,3) | (3,4) | (3,5) |
(4,0) | (4,1) | (4,2) | (4,3) | (4,4) | (4,5) |
(5,0) | (5,1) | (5,2) | (5,3) | (5,4) | (5,5) |
Please note that although the frame size is measured in pixels, the coordinate of each grid above is only a relative location within the grid and has nothing to do with pixels. The size of each grid is dynamically determined by the object or widget placed in it.
Tkinter Module
The following code running from Python interactive mode renders a window/frame (as shown in Figure 9-1):
>>> from tkinter import *
>>> f = Tk()
The following statements can be used to set the title and the size of the window:
>>> f.title("My First GUI App")
>>> f.geometry("300 x 200")
Figure 9-1: A window rendered by Python with Tkinter
Within this frame/window, we can place specific objects, called widgets, to serve their designated purposes, as detailed below:
- • Label displays text and bitmaps.
- • Entry displays simple text.
- • Button displays a button and associates a command with the button that can be invoked.
- • Checkbutton displays a button with only an on or off state. It is often used in groups to provide a number of options for users to select.
- • Menu displays menu bars, pull-down menus, and pop-up menus.
- • OptionMenu allows the user to select a value from a menu.
- • PanedWindow is a container that may contain a number of panes.
- • Radiobutton displays a radio button with an on/off state. It is used in groups, from which the user can select only one option at a time.
- • Frame is a container to organize other widgets.
- • LabelFrame is a spacer or container for complex window layouts.
- • Text displays text in multiple lines.
- • Canvas provides an area on which you can draw shapes such as lines, ovals, polygons, and rectangles in your application.
- • Scale provides a slider showing numerical scale.
- • Scrollbar adds scrolling capability to various widgets, such as text and list boxes.
- • Spinbox is a variant of the standard Tkinter Entry widget and selects from a fixed number of values.
- • Toplevel provides a separate window container.
The following is a code sample in Jupyter Notebook:
In [ ]: |
|
Out [ ]: | The window will be rendered as shown in Figure 9-2: |
In the above, the first statement creates a label object with the text “This is my first label” on it, whereas the second statement places the object in a specific grid of the window. If no arguments are specified for the grid, the default value is used, which is the next available grid in the window in order from top to bottom, left to right.
Figure 9-2: A GUI example with more details
Similarly, we can add an Entry widget to the window using the following statements:
In [ ]: |
|
By now the window should look like the one shown in Figure 9-3.
Figure 9-3: A GUI example with added entry widget
In addition to the Entry widget for taking single-line text input, the Button and Text widgets take mouse click and multiple-line text input, respectively, from users. We can add buttons and text boxes to the window with the following statements:
In [ ]: |
|
The rendered window is shown in Figure 9-4.
Within the window, you can type in the entry field, type more in the text area, and click the button, but the app does not do anything in response, as shown in Figure 9-5.
Figure 9-4: A GUI example with more widgets added
Figure 9-5: A GUI example taking user input
How can we make the app respond to the user’s input and do what we want it to do? We need to attach an even handler to the intended object, such as a button, as shown below:
In [ ]: |
|
In the above, we first define a function as a handler, which simply changes the text on the button to “You clicked me,” then attaches the handler to the button using the config() method built into the button object. As expected, the text on the button changes after a click on the button, as shown in Figure 9-6.
To learn more details about each of the widgets listed above, we can call for help in Python interactive mode or Jupyter Notebook. The following example shows how to get help on the Frame widget in Jupyter Notebook:
Figure 9-6: Now the GUI is able to respond to user input
In [ ]: |
|
As always, you can also search the internet for any widget in the tkinter module to get help, including very detailed discussions on its use.
With what we have learned so far, we should be ready to develop a real GUI-based application, which is the GUI version of a grade conversion program. The conversion is based on the data in Table 9-1, and the case study is in Table 9-2.
Letter grade | % | Letter grade | % |
---|---|---|---|
A+ | 90–100 | C+ | 67–69 |
A | 85–89 | C | 64–66 |
A- | 80-84 | C- | 60-63 |
B+ | 76–79 | D+ | 55–59 |
B | 73–75 | D | 50–54 |
B− | 70–72 | F | 0–49 |
The problem | To develop a GUI-based application that can take the a numerical grade from a user and convert it to a letter grade. |
The analysis and design | The application is meant to convert numerical grades to letter grades based on the conversion table shown as Table 9-1. The information flow is: Get a numerical grade from user → convert to a letter grade → display the letter grade In previous chapters, we showed how to develop a terminal-based application to do this conversion, where the input and output were all done on a standard terminal. In a GUI-based application, the input and output/display need to be done on a graphic interface. Consider the widget in the tkinter module. We need an Entry widget for input and a Label widget to display the converted letter grade, a Button to start a conversion, and another Button to exit and close the application. Of course, we also need a function to do the actual conversion. |
The code |
|
In the coding example, the .grid() method positions a widget in the parent widget in a grid or cell. The options that can be used with the .grid() method are as follows:
- column = number—uses cell identified with given column (starting with 0)
- columnspan = number—spans several columns
- in = master—uses master to contain this widget
- in_ = master—uses master to contain this widget
- ipadx = amount—adds internal padding in x direction
- ipady = amount—adds internal padding in y direction
- padx = amount—adds padding in x direction
- pady = amount—adds padding in y direction
- row = number—uses a cell identified with a given row (starting with 0)
- rowspan = number—span several rows
- sticky = NSEW—tells on which sides this widget will stick to the cell boundary if the cell is larger
Note that we placed a method of the imported tkinter module named .mainloop() at the very end of the program. The call to the method is necessary to keep the window of the GUI-based app alive when running the code from the Python program file. Otherwise, the window will disappear as soon as the Python Virtual Machine (PVM) reaches the end of the program file.
You may wonder why the GUI window we created from the Python interactive shell stays alive without the .mainloop() statement. The reason is very simple: because PVM is still waiting for you to input a numeric grade, which means that the file (standard IO file) won’t reach the end as long as you have not quit the Python interactive shell.
The GUI application can also be placed in a frame. The result and the code are shown in Figure 9-7 and below. As you can see, it has become nicer.
Figure 9-7: A GUI application doing grade conversion
"""
You are required to design a GUI-based program using the Tkinter
module to convert numeric grades to alpha letter/grades.
"""
from tkinter import *
def n_to_l(n_g):
n_g = round(float(n_g))
if n_g in range(90, 101):
lg = f"Letter grade of {n_g} is A+"
elif n_g in range(85, 90):
lg = f"Letter grade of {n_g} is A"
elif n_g in range(80, 85):
lg = f"Letter grade of {n_g} is A-"
elif n_g in range(76, 80):
lg = f"Letter grade of {n_g} is B+"
elif n_g in range(73, 76):
lg = f"Letter grade of {n_g} is B"
elif n_g in range(70, 73):
lg = f"Letter grade of {n_g} is B-"
elif n_g in range(67, 70):
lg = f"Letter grade of {n_g} is C+"
elif n_g in range(64, 67):
lg = f"Letter grade of {n_g} is C"
elif n_g in range(60, 64):
lg = f"Letter grade of {n_g} is C-"
elif n_g in range(55, 60):
lg = f"Letter grade of {n_g} is D+"
elif n_g in range(50, 54):
lg = f"Letter grade of {n_g} is D"
elif n_g in range(0, 50):
lg = f"Letter grade of {n_g} is F"
else:
lg = "invalid mark!"
return lg
def hdl():
n = int(ent1.get())
lb2.config(text = f"{n_to_l(n)}")
return -1
w = Frame()
# to add frame widget
w.master.title("My GUI-based grade converter in Frame")
w.master.geometry("500 x 200")
lb1 = Label(text = "Please input percentage grade:")
lb1.grid(column = 2, row = 1, rowspan = 3, pady = 30)
ent1 = Entry()
ent1.grid(column = 3, row = 1, rowspan = 3, pady = 30)
btn = Button(text = "Convert", background = "#FF0000")
btn.grid(column = 2, row = 5, rowspan = 3, pady = 30)
btn.config(command = hdl)
btn_quit = Button(text = "Quit", background = "#FF0000")
btn_quit.grid(column = 6, row = 5, rowspan = 3, pady = 30)
btn_quit.config(command = quit)
lb2 = Label(text = "Letter grade will be displayed here")
lb2.grid(column = 2, row = 8, rowspan = 3)
mainloop()
# this statement must be placed below all others to keep the window alive
If you don’t like placing widgets with the .geometry() method, you may use the .pack() method to let the PVM automatically place the widgets for you. The new GUI-based app and the revised Python code are shown in Figure 9-8 and below.
Figure 9-8: Frame widget is used in the GUI application
"""Revised grade conversion: placing widgets with the .geometry() method."""
from tkinter import *
def n_to_l(n_g):
n_g = round(float(n_g))
if n_g in range(90, 101):
lg = f"Letter grade of {n_g} is A+"
elif n_g in range(85, 90):
lg = f"Letter grade of {n_g} is A"
elif n_g in range(80, 85):
lg = f"Letter grade of {n_g} is A-"
elif n_g in range(76, 80):
lg = f"Letter grade of {n_g} is B+"
elif n_g in range(73, 76):
lg = f"Letter grade of {n_g} is B"
elif n_g in range(70, 73):
lg = f"Letter grade of {n_g} is B-"
elif n_g in range(67, 70):
lg = f"Letter grade of {n_g} is C+"
elif n_g in range(64, 67):
lg = f"Letter grade of {n_g} is C"
elif n_g in range(60, 64):
lg = f"Letter grade of {n_g} is C-"
elif n_g in range(55, 60):
lg = f"Letter grade of {n_g} is D+"
elif n_g in range(50, 54):
lg = f"Letter grade of {n_g} is D"
elif n_g in range(0, 50):
lg = f"Letter grade of {n_g} is F"
else:
lg = "invalid mark!"
return lg
def hdl():
n = int(ent1.get())
lb2.config(text = f"{n_to_l(n)}")
return -1
w = Tk()
w.title("My GUI-based grade converter")
w.geometry("500 x 200")
lb1 = Label(text = "Please input percentage grade:")
lb1.pack(fill = Y, expand = 1)
ent1 = Entry()
ent1.pack(expand = 0)
btn_convert = Button(text = "Convert", background = "#33FF88")
btn_convert.pack(padx = 10, side = LEFT, expand = 0)
btn_convert.config(command = hdl)
btn_quit = Button(text = "Quit", background = "#FF0000")
btn_quit.pack(padx = 10, side = RIGHT, expand = 0)
btn_quit.config(command = quit)
lb2 = Label(text = "Letter grade will be displayed here")
lb2.pack(fill = Y, expand = 1)
mainloop()
# this statement must be placed at the end to keep the window alive
As you can see, the GUI-based app is rendered much more nicely with the .pack() method. The .pack() method is used to pack a widget in the parent widget. The options of the .pack() method and their meaning are as follows:
- • after = widget—packs it after you have packed the widget
- • anchor = NSEW (or subset)—positions widget according to a given direction
- • before = widget—packs it before you pack the widget
- • expand = bool—expands the widget if the parent size grows
- • fill = NONE or X or Y or BOTH—fills the widget if the widget grows
- • in = master—uses master to contain the widget
- • in_= f—uses fx to contain the widget
- • ipadx = amount—adds internal padding in x direction
- • ipady = amount—adds internal padding in y direction
- • padx = amount—adds padding in x direction
- • pady = amount—adds padding in y direction
- • side = TOP or BOTTOM or LEFT or RIGHT—indicates where to add the widget
Because all the widgets inherit behaviours from the Widget class, it is worth learning about the general methods available in the Widget class for manipulating widgets.
tkinter.ttk—Tk-Themed Widgets
In the past, people have complained about the look of GUI and the widgets of tkinter, which led to the development of themed widgets of tkinter, or Ttk for short. Now the Ttk module is part of the standard Python distribution. To use it, all you need to do is to import the modules in the sequence shown below to make sure Ttk overrides definitions of classes as intended.
>>> from tkinter import *
>>> import tkinter.ttk
Because themed widgets is based on the tkinter module, it overrides definitions of classes, widgets, and methods.
Again, once imported, you can use help(tkinter.ttk) to get a rather detailed documentation of the module, as summarized below:
As for all GUI libraries, the core of the module are the widgets and methods associated with the widgets. All widget classes inherit from a generic class called Widget. The following is a list of widgets defined in the themed Tk module.
Button(Widget)
Ttk Button displays a textual label and/or image and evaluates a command when pressed. In addition to the methods inherited from Widget, it has method specific for its purpose, invoke(self), which invokes the command associated with the button.
Checkbutton
Ttk Checkbutton will be either in an on or off state. It has a specific method called invoke(self) in addition to those inherited from Widget. The invoke(self) will switch the Checkbutton between on and off states, further invoke the associated command, and return the result of executing the command associated with Checkbutton.
Entry(Widget, tkinter.Entry)
Ttk Entry displays a one-line text string that allows that string to be edited by the user. It inherits from Widget and tkinter.Entry.
Combobox(Entry)
Ttk Combobox widget combines a text field with a pop-down list of values. It inherits from Ttk Entry, described above. It has two methods of its own:
- 1. current(self, newindex = None)—if newindex is supplied, it sets the combobox value to the element at position newindex in the list of values. Otherwise, it returns the index of the current value in the list of values or −1 if the current value does not appear in the list.
- 2. set(self, value)—sets the value of the combobox to “value.”
Spinbox(Entry)
Ttk Spinbox is an Entry with increment and decrement arrows. It is commonly used for number entry or to select from a list of string values.
Frame(Widget)
Ttk Frame is a container used to group other widgets together.
LabeledScale(Frame)
Ttk Scale is used with Ttk Label, indicating its current value. Ttk Scale can be accessed through instance.scale, and Ttk Label can be accessed through instance.label.
Label(Widget)
Ttk Label displays a textual label and/or image.
Labelframe(Widget)
Ttk Labelframe is a container used to group other widgets together. It has an optional label, which may be a plaintext string or another widget.
Menubutton(Widget)
Ttk Menubutton displays a textual label and/or image. It will display a menu when pressed.
OptionMenu(Menubutton)
Ttk OptionMenu allows the user to select a value from a menu.
Notebook(Widget)
Ttk Notebook manages a collection of windows and displays a single one at a time. Each child window is associated with a tab that the user may select to make the associated window show up. This gives us a way to implement tabs like those in web browsers.
Panedwindow(Widget, tkinter.PanedWindow)
Ttk Panedwindow displays a number of subwindows stacked either vertically or horizontally. It has the following specific methods:
- 1. remove(self, child)
- 2. insert(self, pos, child, **kw)—inserts a pane at the specified positions.
- 3. pane(self, pane, option = None, **kw)—queries or modifies the options of the specified pane.
- 4. sashpos(self, index, newpos = None)—if newpos is specified, sets the position of sash number index and returns the new position of sash number index.
Progressbar(Widget)
Ttk Progressbar shows the status of a long-running operation. It can operate in two modes. Determinate mode shows the amount completed relative to the total amount of work to be done, and indeterminate mode provides an animated display to let the user know that something is happening.
Radiobutton
Ttk Radiobuttons are used in groups to show or change a set of mutually exclusive options. The specific method invoke(self) sets the option variable to the option value, selects the widget, and invokes the associated command. It returns the result of the command or an empty string if no command is specified.
Scale(Widget, tkinter.Scale)
Ttk Scale is typically used to control the numeric value of a linked variable that varies uniformly over some range.
Scrollbar(Widget, tkinter.Scrollbar)
Ttk Scrollbar controls the viewport of a scrollable widget.
Separator(Widget)
Ttk Separator displays a horizontal or vertical separator bar.
Sizegrip(Widget)
Ttk Sizegrip allows the user to resize the containing top-level window by pressing and dragging the grip.
Treeview(Widget, tkinter.XView, tkinter.YView)
Ttk Treeview displays a hierarchical collection of items. Each item has a textual label, an optional image, and an optional list of data values. The data values are displayed in successive columns after the tree label. It has the following specific methods:
- • bbox(self, item, column = None)
It returns the bounding box (relative to the Treeview widget’s window) of the specified item in the form of x y width height. If a column is specified, it returns the bounding box of that cell. If the item is not visible (i.e., if it is a descendant of a closed item or is scrolled off-screen), it returns an empty string.
- • column(self, column, option = None, **kw)
It queries or modifies the options for the specified column. If kw is not given, it returns a dictionary of the column option values. If option is specified, then the value for that option is returned. Otherwise, it sets the options to the corresponding values.
- • delete(self, *items)
It deletes all specified items and all their descendants. The root item may not be deleted.
- • detach(self, *items)
It unlinks all of the specified items from the tree. The items and all of their descendants are still present and may be reinserted at another point in the tree but will not be displayed. The root item may not be detached.
- • exists(self, item)
It returns True if the specified item is present in the tree; returns False otherwise.
- • focus(self, item = None)
if an item is specified, it sets the focus item to item. Otherwise, it returns the current focus item, or '' if there is none.
- • get_children(self, item = None)
It returns a tuple of children belonging to item. If the item is not specified, it returns root children.
- • heading(self, column, option = None, **kw)
It queries or modifies the heading options for the specified column. If kw is not given, it returns a dict of the heading option values. If option is specified, then the value for that option is returned. Otherwise, it sets the options to the corresponding values. Valid options/values include text, image, anchor, and a callback command.
- • identify(self, component, x, y)
It returns a description of the specified component under the point given by x and y or the empty string if no such component is present at that position.
- • identify_column(self, x)
It returns the data column identifier of the cell at position x. The tree column has ID #0.
- • identify_element(self, x, y)
It returns the element at position x, y.
- • identify_region(self, x, y)
For the given coordinator (x, y) of a point related to the widget, it returns a string indicating one of the following: nothing (not within any functional part of the widget), heading (a column heading), separator (a separator between columns), tree (the icon column), or cell (a data cell within an item row).
- • identify_row(self, y)
It returns the item ID of the item at position y.
- • index(self, item)
It returns the integer index of an item within its parent’s list of children.
- • insert(self, parent, index, iid = None, **kw)
It creates a new item and returns the item identifier of the newly created item, where parent is the item ID of the parent item or the empty string to create a new top-level item and index is an integer or the value end, specifying where in the list of parent’s children to insert the new item. If index is less than or equal to 0, the new node is inserted at the beginning; if index is greater than or equal to the current number of children, it is inserted at the end. If iid is specified, it is used as the item identifier, but iid must not already exist in the tree. Otherwise, a new unique identifier is generated.
- • item(self, item, option = None, **kw)
It queries or modifies the options for a specified item. If no options are given, a dict with options/values for the item is returned. If an option is specified, then the value for that option is returned. Otherwise, it sets the options to the corresponding values, as given by kw.
- • move(self, item, parent, index)
It moves item to position index in parent’s list of children. It is illegal to move an item under one of its descendants. If an index is less than or equal to 0, the item is moved to the beginning; if greater than or equal to the number of children, it is moved to the end. If the item was detached, it is reattached.
- • next(self, item)
It returns the identifier of an item’s next sibling, or '' if the item is the last child of its parent.
- • parent(self, item)
It returns the ID of the parent of an item, or '' if the item is at the top level of the hierarchy.
- • prev(self, item)
It returns the identifier of an item’s previous sibling, or '' if the item is the first child of its parent.
- • see(self, item)
It ensures that the item is visible and sets all of the item’s ancestors’ open options to True and scrolls the widget if necessary so that the item is within the visible portion of the tree.
- • selection(self, selop = <object object at 0x000002122111D7F0>, items=None)
It returns the tuple of the selected items.
- • selection_add(self, *items)
It adds all of the specified items to the selection.
- • selection_remove(self, *items)
It removes all of the specified items from the selection.
- • selection_set(self, *items)
It makes the specified items become the new selection.
- • selection_toggle(self, *items)
It toggles the selection state of each specified item.
- • set(self, item, column = None, value = None)
It queries or sets the value of a given item.
- • set_children(self, item, *newchildren)
It replaces an item’s child with newchildren.
- • tag_bind(self, tagname, sequence = None, callback = None)
It binds a callback for the given event sequence to the tag tagname. When an event is delivered to an item, the callbacks for each tag option of the item are called.
- • tag_configure(self, tagname, option = None, **kw)
It queries or modifies the options for the specified tagname.
- • tag_has(self, tagname, item = None)
If an item is specified, it returns 1 or 0 depending on whether the specified item has the given tagname. Otherwise, it returns a list of all items that have the specified tag.
The Treeview widget provides a way to use tree-like structures to visualize and manipulate data and information. The methods available for manipulating trees are versatile.
Among all the widgets provided in themed tkinter, the newly added Treeview, Progressbar, and Notebook are very powerful and can be very useful in developing today’s GUI applications, such as those in the exercises, and projects below.
The content above Ttk and Treeview in particular are mostly taken from the official documentation of Tkinter, for the purpose to prepare readers for the projects at the end of this chapter.
For details on how Ttk can be used to develop GUI applications, please read the Ttk documentation at https://docs.python.org/3/library/tkinter.ttk.html and tutorials online such as the one at https://www.pythontutorial.net/tkinter/tkinter-ttk/.
Instead of giving code samples for each widget like we previously did, we conclude this chapter with the following sample program to show how Ttk and Treeview can be used in GUI application development:
import tkinter as tk
from tkinter import ttk
class FileManager:
def __init__(self):
self.root = tk.Tk()
self.tree = ttk.Treeview(self.root)
self.tree.pack()
self.tree["columns"] = ("one", "two", "three", "four")
self.tree.heading("one", text="Path")
self.tree.heading("two", text="File name")
self.tree.heading("three", text="File size")
self.tree.heading("four", text="Last modified")
self.tree.insert("", "end", text="1", values=("/home/james/", "a.txt","213","June 3, 2023" ))
self.tree.insert("", "end", text="2", values=("/home/james/", "b.txt","215","June 5, 2023" ))
self.tree.insert("", "end", text="3", values=("/home/james/", "c.txt","217","June 7, 2023" ))
self.root.mainloop()
FileManager()
Chapter Summary
- • Terminal-based applications are those started and rendered within a terminal.
- • A terminal is a system command-line-based application in which you can interact with a computer.
- • On the Windows platform, Windows terminal, Windows PowerShell, and command prompt are examples of terminals.
- • Within a terminal-based application, pointing devices such as a mouse cannot be used to interact with the application.
- • A graphical user interface is a two-dimensional graphic area in which graphic objects or widgets can be created, placed, located, and accessed with mouse and keyboard.
- • GUI-based applications look nicer and are much more user-friendly.
- • Python has some very well-developed library modules for the development of applications with graphical user interface.
- • The Tk and Themed Tk (Ttk) are the modules covered in this text; both come with the Tkinter package.
- • The Tk module provides the fundamental widgets and operations needed for a graphic interface.
- • To use the Tk module, use import tkinter, import tkinter as tk, or from tkinter import. *.
- • The Themed Tk (Ttk) module provides programmers with more styled widgets to develop applications with a nicer graphical user interface.
- • To ensure you are using the Ttk module instead of Tk module, override Tk by running statements from tkinter import * and from tkinter.ttk import * in order.
- • To build a graphical user interface, create a main frame or window first.
- • Other widgets can be created and added to the main frame/window as needed.
- • Each widget has certain properties/attributes such as size, colour, and more.
- • The properties of a widget can be set when created and changed later.
- • A widget can be placed at particular location within the main frame or subframe.
- • A function/method can be bound to widgets, such as a button, to help users interact with the graphical user interface.
- • A graphical user interface needs to be rendered by calling the mainloop() method of main frame object.
Exercises
- 1. Explore the relationship between Tk and Ttk, and explain what the following code does:
- from tkinter import *
- from tkinter.ttk import *
- 2. Write a script that will render a window as shown in Figure 9-9.
Figure 9-9: Required GUI interface for the exercise
- 3. Write a script that will render a page for login or registration, as shown in Figure 9-10.
Figure 9-10: Required GUI interface for the project
Projects
- 1. For this project, develop a GUI-based music player with the module mixer.music as well as the os and os.path modules for file navigation. The player should have a panel for the navigation and selection of music files, as well as buttons to control play, stop, and pause.
- 2. For this project, develop a course management system with a graphical user interface that meets the following requirements:
- a. Define a student class modelling a student, including their name, student id, and start date in the class, as well as the name of the tutor assigned to them and a list of their assessment records. Each assessment record will be a tuple containing a number to identify the assessment, the weight of the assessment, and the mark, which should be 0 for a newly added instance to a course.
- b. Define a course class modelling a course, including its course number (such as comp218), title, and revision number, as well as the date of its initial offering and a list of its students, professor(s). Additionally, include an assessment schedule as a list of assessment items where each assessment item is represented as a tuple of (id, name, weight) in which the id is the assessment item id, the name is the assessment name such as assignment 1 or final exam, and the weight is the percentage of the assessment that will go toward the final grade.
- c. The GUI program should include and do all of the following:
- • There should be a button for adding a new course to the system, which will open a form for input and save the basic course info (previously mentioned), with the list of students as empty. Note that when saving the basic course info, the system should be able to check whether the weight of all the assessment items makes up 100%.
- • When a new course is added to the system, a unique binary file will be created as permanent storage of the course data.
- • At the start of the system, it should automatically load all courses from their respective binary files to restore their internal object representation.
- • There should be a button to get a list of courses being offered to students.
- • A user should be able to select a course from the list.
- • A user should be able to add students to the selected course.
- • A user should be able to see a list of students in the course.
- • A user should be able to select a student from the list.
- • A user should be able to record an assessment for the selected student.
- • The system should be able to automatically calculate and display the final grade of the student for the course.
- • A user should be able to see a list of assessments, including the calculated final grade for the selected student.
- • There should be a button to shut down the system, but before shutting down the application, the system must save/pickle each piece of course data back to its binary file.
- d. Your analysis and design of the system should be well documented in your assignment report.
- e. Within each of your program files, there should be a docstring at the beginning stating the name and purpose of the file, as well as its ownership and revision history. One docstring is required for each class and function/method class. An end-of-line comment is desired when deemed necessary.
- 3. In Project 1 of Chapter 7, you developed a terminal-based quiz system. For this project, you are required to develop a GUI-based quiz system also using the Quiz_item and Quiz classes you wrote in Chapter 7’s Exercises 7 and 8. The system should have controls/widgets on the GUI that will allow a user to do the following:
- a. Create a quiz.
- b. Select a quiz and add new quiz items.
- c. Select a quiz and preview all the quiz items.
- d. Select a quiz and execute the quiz by presenting the quiz items one by one.
- 4. Modify the quiz system developed for Project 3 so that after the quiz, it will present to the user the score as a percentage and the correct answers to incorrectly answered questions. The quiz items should be displayed to the user one by one during the quiz. Add a timer to the quiz so that the entire quiz must be done within a given time. To make sense of the timer function, you will need to show the total number of quiz items, the number of items left to be answered, the total amount of time allocated for the entire quiz, and the amount of time left for the remaining quiz items.
- 5. Further modify the quiz system developed for Projects 3 and 4, so that not only is the quiz timed, but each quiz item is also timed too, meaning that the user must answer each quiz question within a given time. For simplicity, we can assume that the time allocated to each quiz item is the same and equal to the total time allocated to the quiz divided by the total number of questions in the quiz. To make better sense of both timers now, the time (number of seconds) left for a quiz question also needs to be displayed, and the quiz will move to the next question as soon as the question is answered or the timer for the question has run out.
We use cookies to analyze our traffic. Please decide if you are willing to accept cookies from our website. You can change this setting anytime in Privacy Settings.