Section 15.8 The Design of GUI Programs
For very simple GUI programs, no special program design is needed, as demonstrated in the previous “Hello World” example programs. However, any non-trivial GUI program will require extensive use of global variables if the structure of the code does not use a Python
class. You have learned in previous lessons that global variables are bad because they make debugging programs more difficult. Therefore we want a design for GUI programs that avoids global variables as much as possible.
To demonstrate this, let’s look at two versions of a simple program that increments a counter each time a user clicks a button. The first version of this code does not use a
classdefinition and requires that a global variable called my_counter be used. This is because the label that represents the counter is created in the
create_user_interfacefunction but it must be accessed in the event handler function
increment_counter. In fact, the event handlers of a GUI program almost always need access to multiple widgets in the program’s interface and the values can’t be passed as parameters because an
event handlerfunction receives no parameters and a
event handlerfunction receives exactly one parameter – an
event object. Study the following example and pay close attention to where the
my_counterglobal variable is used.
import tkinter as tk from tkinter import ttk global my_counter def create_user_interface(application_window): global my_counter my_counter = ttk.Label(application_window, text="0") my_counter.grid(row=0, column=0) increment_button = ttk.Button(application_window, text="Add 1 to counter") increment_button.grid(row=1, column=0) increment_button['command'] = increment_counter quit_button = ttk.Button(application_window, text="Quit") quit_button.grid(row=2, column=0) quit_button['command'] = window.destroy def increment_counter(): global my_counter my_counter['text'] = str(int(my_counter['text']) + 1) # Create the application window window = tk.Tk() create_user_interface(window) # Start the GUI event loop window.mainloop()
Let’s compare the above program to an identical application that is designed as a Python
classencapsulates all of the values needed for the GUI interface and the
event handlersand we don’t need global variables!
import tkinter as tk from tkinter import ttk def main(): # Create the entire GUI program program = CounterProgram() # Start the GUI event loop program.window.mainloop() class CounterProgram: def __init__(self): self.window = tk.Tk() self.my_counter = None # All attributes should be initialize in init self.create_widgets() def create_widgets(self): self.my_counter = ttk.Label(self.window, text="0") self.my_counter.grid(row=0, column=0) increment_button = ttk.Button(self.window, text="Add 1 to counter") increment_button.grid(row=1, column=0) increment_button['command'] = self.increment_counter quit_button = ttk.Button(self.window, text="Quit") quit_button.grid(row=2, column=0) quit_button['command'] = self.window.destroy def increment_counter(self): self.my_counter['text'] = str(int(self.my_counter['text']) + 1) if __name__ == "__main__": main()
Notice the following about this design:
- The application’s window is created in the constructor (
__init__) of the
CounterProgramclass and then the interface widgets are created by a call to
- The event handler,
increment_countercan access the label
self.my_counterusing the object’s attributes.
- The code creates an instance of the class
CounterProgramand starts the GUI event-loop.
It is recommended that you develop all of your GUI programs as Python Classes. For complex designs, a Python
Classcan help manage the complexity of the code and the scoping of variables.
You have attempted of activities on this page.