Graphical User Interfaces

CS 65: Introduction to Computer Science I

Graphical User Interfaces in Python

A Graphical User Interface (GUI) is a means for a user to interact with a program which uses graphical components like windows, buttons, and other components that are manipulated with a mouse or touch-input device.

There are several different Python packages that provide the ability to build GUIs (some are designed for desktop/laptop apps, mobile, web, etc.)

tkinter is a one of the most popular GUI toolkits, and it works on standard Windows, Mac, and Linux computers.

In [ ]:
import tkinter

class MinimalApp:
    
    def __init__(self):
        
        #create the main window
        self.main_window = tkinter.Tk()
        
        #enter the "main loop" to launch the window and interact with the user
        tkinter.mainloop()
        
my_gui = MinimalApp()

tkinter widgets

We’ll look at code for using the following tkinter widgets - GUI objects

  • Label: for displaying text to the user
  • Button: for triggering code when the user clicks it
  • Entry: a box that lets the user type short input

There are two things to do with every widget

  • create a new attribute for it in your class
  • call the widget's pack() method - which figures out where to put it and makes it visible
In [ ]:
import tkinter

class HelloApp:
    
    def __init__(self):
        
        #create the main window
        self.main_window = tkinter.Tk()
        
        #create an attribute for our label
        self.hello_label = tkinter.Label(self.main_window, text="Hello world!")
        
        #pack the label
        self.hello_label.pack()
        
        #enter the "main loop" to launch the window and interact with the user
        tkinter.mainloop()
        
my_gui = HelloApp()

We pass two arguments when creating the tkinter.Label object

  • the main window - the parent widget this widget will appear in
  • an optional argument, text="Hello world!" - the text that will appear on the label

A GUI with multiple labels

You can include as many labels as you want (and any number of other widgets)

Make a new attribute for each label

The labels will appear in the order they're packed

Here's an example with two labels

In [ ]:
import tkinter

class MultiLabelApp:
    
    def __init__(self):
        
        #create the main window
        self.main_window = tkinter.Tk()
        
        #create attributes for our label
        self.hello_label = tkinter.Label(self.main_window, text="Hello world!")
        self.description_label = tkinter.Label(self.main_window, text="This is my GUI program.")
        
        #pack the labels
        self.hello_label.pack()
        self.description_label.pack()
        
        
        #enter the "main loop" to launch the window and interact with the user
        tkinter.mainloop()
        
my_gui = MultiLabelApp()

Group Exercise

Searching for help on how to do things with tkinter can sometimes be difficult because there are different coding styles people use with it. However, it can be done.

We want to do the following things

  1. set the title of the window so it is something other than the default tk value
  2. change the initial size of the window to be something a little bit bigger

Do some Internet searching and see if you can figure out how to do this with the MultiLabelApp given above.

tkinter buttons

Creating a button widget in tkinter is similar to creating a label, except you have to set it up with an extra argument: the name of a function that should run when the button is clicked. This function is the callback function.

In [ ]:
self.my_button = tkinter.Button(self.main_window,
            text="This appears on the button",command=name_of_a_function)

A button example in context

In [ ]:
import tkinter


class SimpleButtonApp:
    def __init__(self):
        # Create the main window widget.
        self.main_window = tkinter.Tk()

        # Create a Button widget. The text 'Click Me!'
        # should appear on the face of the Button. The
        # do_something method should be executed when
        # the user clicks the Button.
        self.my_button = tkinter.Button(self.main_window,
            text='Click Me!',command=self.do_something)
        self.my_label = tkinter.Label(self.main_window,text="No click yet.")

        # Pack the Button.
        self.my_button.pack()
        self.my_label.pack()

        # Enter the tkinter main loop.
        tkinter.mainloop()

    # The do_something method is a callback function
    # for the Button widget.

    def do_something(self):
        #the label's config method lets you change the text on the label
        self.my_label.config(text="Good job! You clicked the button.")


# Create an instance of the MyGUI class.
my_gui = SimpleButtonApp()

Things to notice about this

  • the command is set to self.do_something, which is a method we define in the same class
  • when we pass the name of the function, we don't include parentheses - it's not command=self.do_something()
  • the self.do_something() function makes a change to the my_label attribute using the label'ss config method

Example: Turning the Magic 8 ball code into a GUI

We previously wrote a function like this which simulated a Magic 8 Ball. Let's look at how we would code this up as a GUI.

In [ ]:
import random

def magic_8_ball():
    rand_val = random.randint(1,3)
    
    if rand_val == 1:
        print("It is Certain.")
    elif rand_val == 2:
        print("Don't count on it.")
    else:
        print("Reply hazy, try again.")
In [ ]:
 
In [ ]:
import tkinter
import random

class Magic8BallApp:
    
    def __init__(self):
        
        self.main_window = tkinter.Tk()
        
        self.question_button = tkinter.Button(self.main_window,text="Press Me",command=self.generate_response)
        self.answer_label = tkinter.Label(self.main_window,text="Ask the 8 Ball a Question!")
        
        self.question_button.pack()
        self.answer_label.pack()
        tkinter.mainloop()
        
    def generate_response(self):
        rand_val = random.randint(1,3)
        if rand_val == 1:
            self.answer_label.config(text="It is certain.")
        elif rand_val ==2:
            self.answer_label.config(text="The answer is No.")
        else:
            self.answer_label.config(text="Reply hazy, try again.")
        
        
running_instance = Magic8BallApp()

Supporting multiple buttons

If you have multiple buttons, make sure to define multiple functions to handle their actions.

In [ ]:
import tkinter


class MultiButtonApp:
    def __init__(self):
        # Create the main window widget.
        self.main_window = tkinter.Tk()
        
        #Initialize the widgets
        self.question_label = tkinter.Label(self.main_window,text="Did you have a good day?")

        self.yes_button = tkinter.Button(self.main_window,
            text='Yes',command=self.yes_response)
        
        self.no_button = tkinter.Button(self.main_window,
            text='No',command=self.no_response)
        
        #leaving this empty initially, but we'll provide output to it in the callback functions
        self.reaction_label = tkinter.Label(self.main_window,text="")
        

        # Pack the widgets
        self.question_label.pack()
        self.yes_button.pack()
        self.no_button.pack()
        self.reaction_label.pack()

        # Enter the tkinter main loop.
        tkinter.mainloop()

    #callback function for responding to a "Yes" button click
    def yes_response(self):
        self.reaction_label.config(text="Hooray! That's great.")
        
    #callback function for responding to a "No" button click
    def no_response(self):
        self.reaction_label.config(text="Too bad, maybe tomorrow will be better.")


# Create an instance of the MyGUI class.
my_gui = MultiButtonApp()

Group Exercise

Create an application that has multiple buttons and multiple labels.