Warning - This site is moving to https://getthecodingbug.anvil.app
Topics covered
GUI - Graphical User Interface
guizero
widgets: App, PushButton, TextBox, Text
Tic-Tac-Toe game
GUIs
Python has a huge number of GUI frameworks (or toolkits) available for it, as you can see here: https://wiki.python.org/moin/GuiProgramming
Some are easier to use than others. To start you off I am going to introduce you to 'guizero'
Here is the website, where you can learn more about it and how to install the library, if it is not found in your edition of Python: https://lawsie.github.io/guizero
Guizero is a wrapper for the standard Tkinter library (included by default when Python3 is installed)
Let's get started with a simple "Hello World" program using guizero.
# app1.py
from guizero import *
app = App(title="Hello World")
app.display()
When run, it should produce a window like this:
It does not look like much but the App widget is the base on which you can place any of the other guizero widgets, such as: PushButtons,
Text (labels),
TextBoxes,
Comboboxes,
Sliders,
Checkboxes,
Menu bars and Pictures etc.
Here is how to place a button:
# but1.py
from guizero import *
def clicked():
app.title = 'You Clicked Me'
app = App(title="Hello World", layout="grid")
but1 = PushButton(app, grid=[0,0], text='Click Me', command=clicked)
app.display()
Note, PushButton references 'app' the name we gave to the base widget.
We have introduced another feature, layout in the App widget, which controls how the other widgets are to be placed on the App window, in this case the 'grid' layout.
The grid element specifies the row and column where the widget is to appear.
When the button is pushed or clicked, the program will branch to the 'clicked' function, defined above, and change the window title to "You Clicked Me!".
You can also have images instead of text on your buttons, here is how to do that.
First right-click the buttons, below, and select 'save image as'. Save the first as 'purple-button.png' and the second as 'gold-button.png' in the same folder as your other 'guizero' programs.
Then copy and paste this as a new program and save as 'pb2.py' in the same folder as the button images.
# pb2.py from guizero import App, PushButton def buttonAction(): if mybut.image == "gold-button.png": mybut.image = "purple-button.png" else: mybut.image = "gold-button.png" app = App(height=200, width=200, layout="grid") mybut = PushButton(app, image="purple-button.png", grid=[0,0], command=buttonAction) app.display()
You can find many more free images like these at: https://www.fg-a.com/buttons.htm
The TextBox widget allows a user to enter some text, here is an example:
# tbox0.py
from guizero import *
app = App(title="Hello World", layout="grid")
tbox1 = TextBox(app, grid=[0,0])
app.display()
Now let us combine a TextBox and a PushButton, here is an example:
# tboxbut2.py
from guizero import *
def clicked():
app.title = tbox1.value
app = App(title="Hello World", layout="grid")
tbox1 = TextBox(app, grid=[0,0])
but1 = PushButton(app, grid=[0,1], text='Enter text in box and press me', command=clicked)
app.display()
Notice how the 'but1' widget is placed on the row below the TextBox using the 'grid=[0,1]' attribute.
The '0' was the column and '1' was the row.
Now let us change to text on a PushButton:
# pb1.py
from guizero import App, PushButton
def changebut():
if mybut.text == "X":
mybut.text = "O"
else:
mybut.text = "X"
app = App(height=200, width=200, layout="grid")
mybut = PushButton(app, grid=[0,0], command=changebut, text="O")
app.display()
This next example is the basis of a game of Tic-Tac-Toe (or Noughts and Crosses).
The code for the computer's turn is in the computersTurn() function.
It currently only chooses a random empty square (button) so it is not very clever.
See if you can change the code to make the computer make its own intelligent choice for its next move.
Can you make the computer always win?
# TickTacToe.py from guizero import * import time import random def winnerIs(text): app.title = text + ' Wins' global gameOver, X_wins, O_wins if text == 'X': X_wins += 1 else: O_wins += 1 gameOver = True return def checkLine(b1, b2, b3): if not buttonlist[b1].text == empty: if buttonlist[b1].text == buttonlist[b2].text: if buttonlist[b2].text == buttonlist[b3].text: winnerIs(buttonlist[b1].text) return True return False def winningLine(): # button positions: # 0 3 6 # 1 4 7 # 2 5 8 # check the 8 possible winning lines if checkLine(0, 1, 2): return True if checkLine(0, 4, 8): return True if checkLine(0, 3, 6): return True if checkLine(1, 4, 7): return True if checkLine(2, 5, 8): return True if checkLine(3, 4, 5): return True if checkLine(6, 7, 8): return True if checkLine(6, 4, 2): return True # no winning lines found, check for draw if emptySquares < 1: app.title = 'Draw' global gameOver gameOver = True return True return False def computersTurn(): global gameOver, emptySquares if gameOver: return while emptySquares > 0: # Completely random choice of empty squares n = random.randint(0,8) if buttonlist[n].text == empty: buttonlist[n].text = computer emptySquares -= 1 if winningLine(): return break return def clicked(b): if gameOver: return button = buttonlist[int(b)] # Get the PushButton which was clicked global empty, player if button.text != empty: pass # Do nothing if button already occupied else: # Mark button with user's symbol button.text = player global emptySquares emptySquares -= 1 if winningLine(): return else: time.sleep(0.1) computersTurn() return def main(): global turn if turn == 0: computersTurn() turn = 1 else: turn = 0 # alternate between player and computer to make first move app.display() if not gameOver: quit() games = 0 turn = 0 X_wins = 0 O_wins = 0 while True: empty = ' ' player = "X" computer = "O" emptySquares = 9 gameOver = False if games == 0: title = 'Tic Tac Toe' else: title = 'Wins X:' + str(X_wins) + ' O:' + str(O_wins) app = App(title=title, layout="grid", width=254, height=291) # Create nine PushButtons, in three rows of three buttonlist = [] # Empty list to contain a list of PushButton objects for y in range(3): for x in range(3): z = (3*y) + x buttonlist.append(PushButton(app, text=empty, args=str(z), grid=[y, x], command=clicked)) buttonlist[-1].font="Helvetica" buttonlist[-1].text_size=30 games +=1 main()
The game will continue until a player wins or it is a draw.
When you close the window and new window appears for a new game.
If you close the window before there is a winner or a draw, the program terminates.