← Teacher guide

Build a button

Students build a working button from scratch (a rectangle, a label and a check that a click landed inside), and find out what every app's buttons are really doing.

Python functions and events · Interaction · about 55 minutes · Open the student lesson

Classroom resources

Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.

Students will be able to

Timing

Predict and Run 10 min · Investigate 15 min · Modify 10 min · Make 15 min · Panel and toolkit 5 min

Before class

Turtle has no buttons, which is the point: students build one. The key idea is the hit test: a click at (x, y) is inside the button when x is between the left and right edges and y is between the bottom and top edges. Four comparisons joined with and. Run the counter and click inside and outside the button.

Running the lesson

  1. Predict: draw the button on the board with its corners labelled, (bx, by) at the bottom left. Ask whether a click at the centre is inside.
  2. Investigate: students fill in the trace table by checking all four comparisons for each click. The bug (or instead of and) makes every click count.
  3. The 'iceberg' idea: the visible button is the small part. The rest is drawing it, checking the click, handling the event and updating what is shown.
  4. Modify: because the click check uses the same variables as the drawing, moving the button moves the check too.
  5. Make: two buttons means two separate if statements, one per button.
  6. Toolkit: the ui module holds draw_button and inside, the same code as students wrote. Compare the line counts.

The hard part (on purpose)

The hit test: four comparisons joined with and. Have them work out each comparison for one click on paper before fixing the code.

When students get stuck

What you will seeA question to askThe fix
Clicks far from the button still count.Are the four comparisons joined with and, or with or?Use and. A click is inside only when all four comparisons are true.
Clicks inside the button are missed near the top or right.What are the right and top edges, using bx, bw, by and bh?The right edge is bx + bw and the top edge is by + bh.
The number on screen does not change, or numbers pile up on top of each other.Does the click redraw the screen, and does the redraw clear the old drawing first?Call draw_scene() after changing the count, and start draw_scene with clear().

Answers to the checks

  1. Predict: You click the very centre of the picture, at (0, 0). What does the program print?
    button pressed. The button runs from x = -60 to 60 and from y = -25 to 25, and (0, 0) is inside it.
  2. Test some clicks: The button runs from x = -60 to 60 and y = -25 to 25. Fill in whether each click is inside.
    no, yes, no
    A click is inside only when all four comparisons are true. x = 80 is past the right edge, and y = 40 is above the top.
  3. Find the right edge: A button has bx = -60 and bw = 120. What is the largest x that counts as the right edge?
    60
    The right edge is bx + bw = -60 + 120 = 60.
  4. Spot the bug: Every click counts as a press, even one far from the button. Click the wrong line.
    line 7
    With or, one true comparison is enough, and x > bx alone is true for most clicks. A click is inside only when all four are true, so they are joined with and.
  5. Mix it up: The student clicks at x = 120. How many times does "pressed" appear?
    0
    120 is not between 0 and 100, so the condition is false and the print does not run. Zero times.

Solutions

One possible solution for each task. Other correct programs are fine.

Modify › Move and resize it

from turtle import *

speed(0)
hideturtle()
bx = -100
by = -80
bw = 200
bh = 70
count = 0


def draw_scene():
    clear()
    penup()
    goto(bx, by)
    pendown()
    for i in range(2):
        forward(bw)
        left(90)
        forward(bh)
        left(90)
    penup()
    goto(bx + 10, by + 25)
    write("Click me")
    goto(-20, 70)
    write(count, False, "left", ("Arial", 24, "normal"))


def clicked(x, y):
    global count
    if x > bx and x < bx + bw and y > by and y < by + bh:
        count = count + 1
        draw_scene()


draw_scene()
onscreenclick(clicked)
listen()
mainloop()

Modify › Change what a click does

from turtle import *

speed(0)
hideturtle()
bx = -60
by = -25
bw = 120
bh = 50
count = 0


def draw_scene():
    clear()
    penup()
    goto(bx, by)
    pendown()
    for i in range(2):
        forward(bw)
        left(90)
        forward(bh)
        left(90)
    penup()
    goto(bx + 10, by + 15)
    write("Click me")
    goto(-20, 70)
    write(count, False, "left", ("Arial", 24, "normal"))


def clicked(x, y):
    global count
    if x > bx and x < bx + bw and y > by and y < by + bh:
        count = count + 5
        draw_scene()


draw_scene()
onscreenclick(clicked)
listen()
mainloop()

Make

from turtle import *

speed(0)
hideturtle()
count = 0


def draw_button(bx, by, label):
    penup()
    goto(bx, by)
    pendown()
    for i in range(2):
        forward(100)
        left(90)
        forward(50)
        left(90)
    penup()
    goto(bx + 40, by + 18)
    write(label)


def draw_scene():
    clear()
    draw_button(-120, -25, "+1")
    draw_button(20, -25, "-1")
    goto(-10, 70)
    write(count, False, "left", ("Arial", 24, "normal"))


def clicked(x, y):
    global count
    if x > -120 and x < -20 and y > -25 and y < 25:
        count = count + 1
    if x > 20 and x < 120 and y > -25 and y < 25:
        count = count - 1
    draw_scene()


draw_scene()
onscreenclick(clicked)
listen()
mainloop()

Pick a background colour

from turtle import *

speed(0)
hideturtle()
names = ["white", "yellow", "lightblue", "pink", "lightgreen"]
# Where each button goes: three on the top row, two below.
bxs = [-170, -60, 50, -170, -60]
bys = [20, 20, 20, -40, -40]
bw = 100
bh = 40


def draw_button(bx, by, label):
    penup()
    goto(bx, by)
    pendown()
    for i in range(2):
        forward(bw)
        left(90)
        forward(bh)
        left(90)
    penup()
    goto(bx + 10, by + 12)
    write(label)


def clicked(x, y):
    for i in range(len(names)):
        if x > bxs[i] and x < bxs[i] + bw and y > bys[i] and y < bys[i] + bh:
            bgcolor(names[i])


for i in range(len(names)):
    draw_button(bxs[i], bys[i], names[i])

onscreenclick(clicked)
listen()
mainloop()

Use your toolkit

from turtle import *
from ui import draw_button, inside

speed(0)
hideturtle()
count = 0
draw_button(-140, -25, 120, 50, "Add one")
draw_button(20, -25, 120, 50, "Take one")


def clicked(x, y):
    global count
    if inside(x, y, -140, -25, 120, 50):
        count = count + 1
        print(count)
    if inside(x, y, 20, -25, 120, 50):
        count = count - 1
        print(count)


onscreenclick(clicked)
listen()
mainloop()

Stretch and support

Stretch: Add a third button that resets the count to 0, and draw the count in red when it goes below zero.

Support: Give students a printed grid with the button drawn and five click points marked, to decide inside or outside before coding.

Exit ticket

A button has bx = 0, by = 0, bw = 100, bh = 40. Is a click at (50, 50) inside? Why?

No. x = 50 is between 0 and 100, but y = 50 is above the top edge (0 + 40 = 40).

What each step is for

Where it leads

Next unit is the final challenge, a game that uses everything including these buttons. Gradio's Button and every phone app do this same work for you. Class ideas: a class control panel with different buttons; design a calculator keypad.