GUI Development 2
GUI Development 2
www.dbooks.org
2 CREATE GRAPHICAL USER INTERFACES WITH PYTHON
CREATE GRAPHICAL USER INTERFACES WITH PYTHON
ISBN: 978-1-912047-91-8
3
www.dbooks.org
About the authors...
Martin O'Hanlon
Martin works in the learning team at the Raspberry
Pi Foundation, where he creates online courses,
projects, and learning resources. He contributes
to the development of many open-source projects
and Python libraries, including guizero. As a child,
he wanted to be a computer scientist, astronaut,
or snowboard instructor.
Laura Sach
Laura leads the A Level team at the Raspberry
Pi Foundation, creating resources for students
to learn about Computer Science. She somehow
also manages to make cakes, hug cats, and
wrangle a toddler.
Welcome!
T
his book will show you how to use Python to create some fun graphical user
interfaces (GUIs) using the guizero library. The guizero library started with the belief
that there must be an easier way for students in school to create Python GUIs. The
library itself was born one day on a long train journey from Cambridge, as the side project of a
secondary school teacher.
Guizero has grown significantly in terms of features, yet remained true to its original aim of
being simple but flexible. It is a library for all beginners to create with, for teachers to scaffold
learning with and for experts to save time with.
We hope that these projects and guizero brings you that little spark of excitement to
your Python programs. That spark might be anything from a button that does something
when you click it, to colours in your otherwise black and white Python programming, to a
full multicoloured Waffle.
It turns out that with open-source software, even if you don't know how to get the whole way
there, if you start, someone will help you. We are grateful to the many contributors who have
put time and effort into creating guizero, and to the thousands of people who have used it in
their projects. Enjoy your journey and be proud of your creations.
5
www.dbooks.org
Contents
Chapter 1: Introduction to GUIs 008
How to install guizero and create your first app
7
www.dbooks.org
Chapter 1
Introduction to GUIs
How to install guizero and create your first app
A
graphical user interface (GUI,
WHAT YOU'LL NEED
pronounced ‘gooey’) is a way of
You will need a computer (e.g. Raspberry making your Python programs
Pi, Apple Mac, Windows or Linux PC) and easier to use and more exciting. You can add
an internet connection for the software different components called ‘widgets’ to your
installation. You will also need the interface, allowing lots of different ways for
following software installed: information to be entered in to the program
and displayed as output. You might want
• Python 3 (python.org) – see Appendix A
to allow people to push a button, to display
• An IDE (code editor), e.g.: a piece of text, or even let them choose an
IDLE (installed with Python 3), Thonny option from a menu. In this book we will use
(thonny.org), Mu (codewith.mu), the guizero library, which has been developed
PyCharm (jetbrains.com/pycharm) with the aim of helping beginners to easily
create GUIs.
• The guizero Python library
Python’s standard GUI package is called
(lawsie.github.io/guizero)
tkinter, and is already installed with Python
Installing guizero
You will need to install the guizero
(lawsie.github.io/guizero) Python library An alternative way to install guizero is to
to create the programs in this book. It is download the zip file from GitHub
available as a Python package, which is
reusable code you can download, install, and then use in your programs.
How you install of guizero will depend on your operating system and the permissions you
have to control your computer.
If you have access to the command line / terminal, you can use the following command:
Hello World
Now that you have guizero installed, let’s check that it’s working and write a small ‘hello
world’ app which is traditional for programmers to write as their first program when using a
new tool or language.
AIMS OF GUIZERO
• Able to be used without installation • Accessible to young children, but able be used
for advanced projects
• Remove unnecessary code new learners find
difficult to understand • Good-quality documentation with examples
Now save and run your code. You should see a GUI window with the title ‘Hello world’ (Figure
1). Congratulations, you’ve just created your first guizero app!
Adding widgets
Widgets are the things which appear on the GUI, such as text boxes, buttons, sliders, and
even plain old pieces of text.
All widgets go between the line of code to create the App and the app.display() line.
Here is the app you just made, but in this example we have added a Text widget:
Did you notice that there are two changes (Figure 2)? There is now an extra line of code to
add the Text widget, and we have also added Text to the list of widgets to import on the very
first line.
Let’s look at the Text widget code in a bit more detail:
Wanted Poster
Use styled text and an image to create a poster
N
ow that you can create a basic GUI, let’s make it look a bit more exciting. You can
add text in different fonts, sizes and colours, change the background colour, and
add pictures too. To practise all of this, let’s create a ‘Wanted’ poster.
First of all, you need to start off by creating an app. In your editor, add this code to create
the most basic app window:
app = App("Wanted!")
app.display()
Save and run your code and you should see an app that
looks like a plain grey square with the title ‘Wanted!’ at
the top (Figure 1).
Figure 1 The basic app
Background colours
Let's make the background of the app a bit different.
Traditionally, wanted posters look like they are made of
parchment, so let’s add a pale yellow colour instead as
the background.
Find the line of code where you create the app.
Immediately after this line of code, add one more line
of code to modify the bg property of the window. In
this case, bg is short for ‘background’ and will let us
change the colour of the background. Now your code
should look like this: Figure 2 Background colour
app = App("Wanted!")
app.bg = "yellow"
app.display()
This is called editing a property. In the code, you need to specify the widget you are talking
about (app), the property you want to change (bg) and the value you want to change it to.
You might think this colour (Figure 2) is a bit too yellow, so let's look up the hex code of
a different yellow colour. There are lots of websites where you can search for colours, for
example you could try htmlcolorcodes.com (Figure 3).
app.bg = "#FBFBD0"
app.bg = (251, 251, 208)
Figure 4 Pale background
You need to import Text to be able to create a piece of text, so add it to the end of the list.
Now the line looks like this:
Every time you want to use a new type of widget, add its name to the end of the list. There is
no need to keep adding whole new lines of code: just stick with one list so that your program
doesn’t get too confusing.
Now that you can use text, let's add a piece of text. Remember that all widgets on the
GUI must be added between the line of code where you create the App and the line of code
where you display it. Your code should now look like this:
app = App("Wanted!")
app.bg = "#FBFBD0"
app.display()
Let’s take a closer look at that line of code you just added.
Here, wanted_text is the name of the piece of text. This is so that we can talk about it later
on in the code – think of it like a person's name. (You could even call your piece of text Dave
if you want – the computer won’t care!)
Inside the brackets we have two things. The second one, "WANTED", is straightforward as
it is the text we would like to display on the screen. The first is the container which controls
this piece of text, which is called its ‘master’. In this case we are saying that this text should
be controlled by the app. When you first start creating GUIs, most of your widgets will have
the app as their master, but there are other containers that can store widgets that you will
learn about later on.
So, in this case you are going to specify the widget Figure 5 Text is too small
(wanted_text), the property to change (text_size)
and the new value (50). Add one new line of code immediately under the line where you
created the text, to change the property.
You now have larger text on your poster (Figure 6). See if you can now change the font
of this text to something different. Which fonts are available depends on which operating
system you are using, so here are some suggestions:
IMAGE MANIPULATION
Because guizero is a library for beginners and we wanted to make it as easy as possible to install,
it does not come with the fancier image manipulation functions as these require an extra library
called 'pillow'. You can always use non-animated GIF images on any platform, and PNG images on all
platforms except Mac, so if you're not sure whether you have installed the extra image manipulation
functions, stick to those image types.
Hopefully you’re now getting used to adding widgets. Remember that they must always be
imported at the top of the program, and then the widget created with a sensible name after
the line of code where you create the App, but before the final app.display() line.
Add 'Picture' to the list of widgets to import at the start of the program.
Now create a Picture widget with two parameters: the app and the file name of the picture.
This is the code we used because our picture was called tabitha.png.
The guizero documentation can be found at lawsie.github.io/guizero. Once you are there, click on the
widget you would like to change, and scroll down until you reach the properties section. For example, if
you select ‘Text’ under the heading of widgets, you will see all of the properties of a piece of Text that
you can possibly change. Documentation also often contains helpful snippets of code which show you
how to use a particular property or method, so don't be scared of having a look through – you never
know what you might learn!
app = App("Wanted!")
app.bg = "#FBFBD0"
app.display()
S
o far you've learnt how to
customise your GUI with a
variety of different options. It's
now time to get into the really interactive Figure 1 Displaying the text in a window
part and make a GUI application that
actually responds to input from the user. Who could resist pushing a big red button to
generate a super secret spy name?
Since you already know how to create an app, why not go ahead and create a basic window
and add some text if you like? Here is some code to get you started, and this code also
includes some comments (the lines that start with a #) to help you structure your program:
# Imports ---------------
from guizero import App, Text
# Functions -------------
# App -------------------
app = App("TOP SECRET")
# Widgets ---------------
title = Text(app, "Push the red button to find out your spy
name")
# Display ---------------
app.display()
Run this code and you should see a window with the text (Figure 1).
Add a button
Let's go ahead and add a button to the GUI. Add PushButton to your list of imports so that
you can use buttons. (Be careful to use a capital B!)
Underneath the Text widget, but before the app displays, add a line of code to create
a button.
Your code should now look like spy1.py (page 22). Run it and no button will appear, but you’ll
see an error in the shell window:
def choose_name():
print("Button was pressed")
Your code should now look like spy2.py. The button will now appear (Figure 2). If you press
the button, it may appear that nothing has happened, but if you look in your shell or output
window, you will see that some text has appeared there (Figure 3).
Instructing your function to first print out some dummy text is a useful way of confirming
that the button is activating its command function correctly when it is pressed. You can then
replace the print statement with the actual code for the task you would like your button
to perform.
Inside your choose_name function, type a # symbol in front of the line of code that prints
"Button was pressed". Programmers call this ‘commenting out’, and what you have done
here is told the computer to treat this line of code as if it were a comment, or in other words
you have instructed the computer to ignore it. The benefit of commenting a line of code out
instead of just deleting it is so that if you ever want to use that code again, you can easily
make it part of your program again by removing the # symbol.
Note that it may not bepossible to change the colour of a button on macOS, as some versions of the
operating system will not allow you to do so, but you should still be able to alter the text size.
Now you will need to add a way of choosing a random name from each list to form your spy
name. Your first job is to add a new import line in your imports section:
This tells the program that you would like to use a function called choice which chooses a
random item from a list. Someone else has written the code which does this for you, and it is
included with Python for you to use.
In your code for the choose_name function, just below your lists of names, add a line of
code to choose your spy's first name, and then concatenate it together with the last name,
with a space in between. Concatenate is a fancy word that means ‘join two strings together’
and the symbol in Python for concatenation is a plus (+).
Your code should now resemble spy3.py. Save and run it. When you press the button, you
should see that a randomly generated spy name appears in your console or shell, in the
same place where the original "Button was pressed" message showed up before (Figure 4).
When you create the widget, you don't want it to display any text at all as the person won't
have pressed the button yet, so you can set the text to "", which is called an ‘empty string’
and displays nothing. Inside your choose_name function, comment out the line of code
where you print out the spy name.
Now add a new line of code at the end of the function to set the value of the name Text
widget to the spy_name you just created. This will cause the Text widget to update itself and
display the name.
name.value = spy_name
Your final code should be as in 03-spy-name-chooser.py. Run it and press the button to see
your spy name displayed proudly on the GUI (Figure 5).
You can press the button again if you don't like the name you are given, and the program
will randomly generate another name for you.
# Functions -------------
# App -------------------
app = App("TOP SECRET")
# Widgets ---------------
title = Text(app, "Push the red button to find out your spy name")
button = PushButton(app, choose_name, text="Tell me!")
# Display ---------------
app.display()
spy2.py / Python 3
# Imports ---------------
from guizero import App, Text, PushButton
# Functions -------------
def choose_name():
print("Button was pressed")
# App -------------------
app = App("TOP SECRET")
# Widgets ---------------
title = Text(app, "Push the red button to find out your spy name")
button = PushButton(app, choose_name, text="Tell me!")
# Display ---------------
app.display()
spy3.py / Python 3
# Imports ---------------
from guizero import App, Text, PushButton
from random import choice
# Functions -------------
def choose_name():
#print("Button was pressed")
first_names = ["Barbara", "Woody", "Tiberius", "Smokey",
"Jennifer", "Ruby"]
last_names = ["Spindleshanks", "Mysterioso", "Dungeon",
"Catseye", "Darkmeyer", "Flamingobreath"]
spy_name = choice(first_names) + " " + choice(last_names)
print(spy_name)
# App -------------------
app = App("TOP SECRET")
# Widgets ---------------
title = Text(app, "Push the red button to find out your spy name")
button = PushButton(app, choose_name, text="Tell me!")
button.bg = "red"
button.text_size = 30
# Display ---------------
app.display()
# Functions -------------
def choose_name():
#print("Button was pressed")
first_names = ["Barbara", "Woody", "Tiberius", "Smokey",
"Jennifer", "Ruby"]
last_names = ["Spindleshanks", "Mysterioso", "Dungeon",
"Catseye", "Darkmeyer", "Flamingobreath"]
spy_name = choice(first_names) + " " + choice(last_names)
#print(spy_name)
name.value = spy_name
# App -------------------
# Widgets ---------------
title = Text(app, "Push the red button to find out your spy name")
button = PushButton(app, choose_name, text="Tell me!")
button.bg = "red"
button.text_size = 30
name = Text(app, text="")
# Display ---------------
app.display()
Meme Generator
Create a GUI application which draws memes
L
et's take the lessons you learnt from the previous chapters to create a GUI which
draws memes. You will input the text and image name and your GUI will combine them
into your own meme using the Drawing widget.
Start by creating a simple GUI with two text boxes for the top and bottom text. This is where
you will enter the text which will be inserted over your picture to create your meme. Add this
line to import the widgets needed.
app = App("meme")
app.display()
The meme will be created on a Drawing widget which will hold the image and text.
Create a meme
Add it to the GUI by inserting this code just before the app.display() line. The Drawing
widget’s height and width should be set to ‘fill’ the rest of the GUI.
The meme will be created when the text in the top and bottom text boxes changes. To do that,
we will need to create a function which draws the meme.
The function should clear the drawing, create an image (we're using a photo of a
woodpecker, but you can use any you want) and insert the text at the top and bottom of
the image.
Remember when you used name.value to set the value of the Text widget with the spy
name in Chapter 3? You can also use the value property to get the value of a Text widget, so in
this case top_text.value means ‘please get the value that is typed in the top_text box’.
def draw_meme():
meme.clear()
meme.image(0, 0, "woodpecker.png")
meme.text(20, 20, top_text.value)
meme.text(20, 320, bottom_text.value)
draw_meme()
Your code should now look like meme1.py. Figure 1 Meme with unstyled text
Your code should now look like that in meme2.py. Run it and update your meme by changing
the top and bottom text.
You can then look of your meme by changing the color, size, and font parameters of the text.
For example:
meme.text(
TIP
20, 20, top_text.value,
color="orange", These lines of code were
size=28,
font="times new roman",
)
Your code should now look like meme3.py. Try different styles until you find something you
like (Figure 2).
First, modify your import statement to include the Combo and Slider widgets.
After you have created your TextBox widgets for the top and bottom text, create a new Combo
widget so the user can select a colour.
The options parameter sets what colours the user can select from the Combo. Each colour is
an element in a list. You can add any other colours you want to the list.
The options are displayed in the order in which you put them in the list. The first option is
the default, which is displayed first. If you want to have a different option as the default, you
can do it using the selected parameter, e.g. "blue".
color = Combo(app,
options=["black", "white", "red", "green", "blue", "orange"],
command=draw_meme,
selected="blue")
Now your user can select a colour. Next, you need to change the draw_meme function to use
Combo’s value when creating the text in your the meme. For example:
meme.text(
20, 20, top_text.value,
color=color.value,
size=40,
font="courier")
Do the same for the bottom-text block of code. Your program should now resemble meme4.py.
Following the steps above, add a second Combo to your application so the user can select a
font from this list of options: ["times new roman", "verdana", "courier", "impact"].
Remember to change the draw_meme function to use the font value when adding the text.
Create a new Slider widget to set the size of the text your user wants.
meme.text(
20, 20, top_text.value,
color=color.value,
size=size.value,
font=font.value)
DRAWING WIDGET
The Drawing widget is really versatile and can be used to display lots of different shapes, patterns,
and images.
To find out more about the Drawing widget, see Appendix C, or take a look at the online
documentation: lawsie.github.io/guizero/drawing.
# Functions -------------
def draw_meme():
meme.clear()
meme.image(0, 0, "woodpecker.png")
meme.text(20, 20, top_text.value)
meme.text(20, 320, bottom_text.value)
# App -------------------
app = App("meme")
draw_meme()
app.display()
meme2.py / Python 3
# Imports ---------------
# Functions -------------
def draw_meme():
meme.clear()
meme.image(0, 0, "woodpecker.png")
meme.text(20, 20, top_text.value)
meme.text(20, 320, bottom_text.value)
# App -------------------
app = App("meme")
draw_meme()
app.display()
meme3.py / Python 3
# Imports ---------------
# Functions -------------
def draw_meme():
meme.clear()
meme.image(0, 0, "woodpecker.png")
meme.text(
20, 20, top_text.value,
color="orange",
size=40,
font="courier")
meme.text(
20, 320, bottom_text.value,
color="blue",
size=28,
font="times new roman",
)
app = App("meme")
draw_meme()
app.display()
meme4.py / Python 3
# Imports ---------------
# Functions -------------
def draw_meme():
meme.clear()
meme.image(0, 0, "woodpecker.png")
meme.text(
20, 20, top_text.value,
color=color.value,
size=40,
font="courier")
meme.text(
20, 320, bottom_text.value,
color=color.value,
size=28,
font="times new roman",
)
# App -------------------
color = Combo(app,
options=["black", "white", "red", "green", "blue",
"orange"],
command=draw_meme, selected="blue")
draw_meme()
app.display()
04-meme-generator.py / Python 3
# Imports ---------------
# Functions -------------
def draw_meme():
meme.clear()
meme.image(0, 0, "woodpecker.png")
meme.text(
20, 20, top_text.value,
color=color.value,
size=size.value,
font=font.value)
meme.text(
20, 320, bottom_text.value,
color=color.value,
size=size.value,
font=font.value,
)
04-meme-generator.py / Python 3
# App -------------------
app = App("meme")
color = Combo(app,
options=["black", "white", "red", "green", "blue",
"orange"],
command=draw_meme, selected="blue")
font = Combo(app,
options=["times new roman", "verdana", "courier",
"impact"],
command=draw_meme)
draw_meme()
app.display()
#13A751
Well
Welldone!
done!
You Well done!
started
Well done! #EA5F10
You
Youstarted
Well done!
started
the
theapplication.
You started
application.
You started
the
theapplication. #289099
theapplication.
application.
Areyou
Are yousure?
sure?
Are you sure?
YES NO
YES NO
YES NO
I
ts time to really go to town with your GUIs and experiment with different widgets,
colours, fonts, and features. Like most experiments, it’s likely that you won’t get it right
first time! In fact, you are going to explore the wrong way to approach creating your GUI.
app.display()
Experiment by changing the colours, font, and text size (see worst1.py listing, page 41). My
choices are not the best!
It’s important that text on a GUI also stays around long enough to be read. It certainly shouldn't
disappear or start flashing.
All widgets in guizero can be made invisible (or visible again) using the hide() and show()
functions. Using the repeat function in guizero to run a function every second, you can make
your text hide and show itself and appear to flash.
Create a function which will hide the text if it’s visible and show it if it’s not:
def flash_text():
if title.visible:
title.hide()
else:
title.show()
Before the app is displayed, use repeat to make the flash_text function run every 1000
milliseconds (1 second).
app.repeat(1000, flash_text)
app.display()
Your code should now look like worst2.py. Test your app: the title text should flash, appearing
and disappearing once every second.
Using a Slider to set a date and time (Figure 1), as in the worst3.py code example, is not a
great idea, though.
The Slider widget returns a number between 0 and 999,999,999. This is the number of
seconds since 1 January 1970. The function ctime() is used to turn this number into a date
and time.
Getting text from your user is simple: a TextBox or a multi-line TextBox should fulfil all your
needs. Is it too simple, though. Does this require too much typing?
What about the user who just wants to use a mouse? Perhaps a series of Combos each
containing all the letters in the alphabet would be better (Figure 2)?
Start by importing the guizero widgets and ascii_letters.
ascii_letters is a list containing all the ‘printable’ ASCII characters which you can use as
the options for the Combo.
Create a single Combo which contains all the letters and displays the app.
app.display()
Your program should now resemble worst4.py. Running it, you will see a single Combo which
contains all the letters plus a space and is aligned to the left of the window.
To get a line of letters together, you could continually add Combo widgets to your app, e.g.:
Pop-ups
No terrible GUI would be complete without
a pop-up box. guizero contains a number of
pop-up boxes, which can be used to let users Figure 3 Pointless pop-up
know something important or gather useful
information. They can also be used to irritate and annoy users!
First, create an application which pops up a pointless box at the start to let you know the
application has started.
app.display()
Running your application, you will see that an ‘info’ box appears (Figure 3). The first parameter
passed to info is the title of the window; the second parameter is the message.
You can change the style of this simple pop-up by using warn or error instead of info.
Pop-up boxes can also be used to get information from the user. The simplest is a yesno
which will ask the user a question and get a True or False response. This is useful if you want
a user to confirm before doing something, such as deleting a file. Perhaps not every time they
press a button, though!
Import the PushButton widget into your application:
Create a function which uses the yesno pop-up to ask for confirmation.
Add the button to your GUI which calls the function when it is pressed.
WINDOW WIDGET
Pop-up boxes can be used to ask users You can control whether a Window is on screen
questions, but they are really simple. using the show() and hide() methods.
If you want to do show additional information
or ask for supplementary data, you could use the window.show()
Window widget to create multiple windows. window.hide()
Window is used in a similar way to App and
has many of the same functions. An app can be made to wait for a window to be
closed after it has been shown, by passing True
from guizero import App, Window to the wait parameter of show. For example:
# App -------------------
app.display()
worst2.py / Python 3
# Imports ---------------
# Functions -------------
def flash_text():
if title.visible:
title.hide()
else:
title.show()
# App -------------------
app.repeat(1000, flash_text)
app.display()
# Functions -------------
def update_date():
the_date.value = ctime(date_slider.value)
# App -------------------
app.display()
worst4.py / Python 3
# Imports ---------------
from guizero import App, Combo
from string import ascii_letters
# App -------------------
app.display()