← Python functions and events

Build a button

Turtle has no buttons, so build one from a rectangle and a click check.

Frameworks give you a button in one line. Underneath, it is a rectangle, a label and a check that a click landed inside. You are about to build all three.

A button is not magic. It is a rectangle, a label, and a check that asks: did the click land inside the rectangle?

Click the picture once before you use it, and press Stop when you are done.

PredictRead the code and say what it will do before you run anything. A wrong guess is fine: it shows you what to look for.

Predict

buttons.py
from turtle import *

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

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("Press me")


def clicked(x, y):
    if x > bx and x < bx + bw and y > by and y < by + bh:
        print("button pressed")
    else:
        print("missed")


onscreenclick(clicked)
listen()
mainloop()

The button's corner is at (bx, by). It is bw wide and bh high. A click at (x, y) is inside when x is between bx and bx + bw, and y is between by and by + bh.

You click the very centre of the picture, at (0, 0). What does the program print?

RunRun it and compare the result with your prediction.

Run

Run it, click inside the button and outside it, then press Stop.

buttons.py
from turtle import *

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

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("Press me")


def clicked(x, y):
    if x > bx and x < bx + bw and y > by and y < by + bh:
        print("button pressed")
    else:
        print("missed")


onscreenclick(clicked)
listen()
mainloop()
Try it yourselfYour edits are saved in this browser.

InvestigateTrace how each line of code connects to what you see.

Investigate

The program above counts presses. draw_scene redraws everything, and clicked checks the click.

buttons.py
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 + 1
        draw_scene()


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

Work out which clicks are inside the button.

Use the numbers to find an edge.

Here is a version where something is wrong.

The button runs from x = -60 to 60 and y = -25 to 25. Fill in whether each click is inside.

click xclick yinside?
00yes
800
-3020
1040

A button has bx = -60 and bw = 120. What is the largest x that counts as the right edge?

Every click counts as a press, even one far from the button. Click the wrong line.

ModifyChange the code on purpose and check the result.

Modify

Make the button bigger and move it to a new place.

Need a hint?

Change bx, by, bw and bh at the top. The click check uses the same names, so it follows.

Make each click add 5 instead of 1.

Need a hint?

Change the line inside clicked that adds to count.

Another hint

To add 5, use count = count + 5.

Try it yourselfYour edits are saved in this browser.

Change what a click does, and keep the counter.

    Run your program. This ticks when your code does all of the above.

    InvestigateTrace how each line of code connects to what you see.

    Mix it up

    Work this out on paper first.

    # the button covers x from 0 to 100
    def clicked(x, y):
        if x >= 0 and x <= 100:
            print("pressed")
    

    The student clicks at x = 120. How many times does "pressed" appear?

    MakeBuild something new using what you have learned. Expect a few tries; that is normal.

    Make

    Build a counter with two buttons: +1 on the left and -1 on the right, with the number shown above.

    Try it yourselfYour edits are saved in this browser.
    Need a hint?

    Write one function that draws a button at a given place, and call it twice.

    Another hint

    In clicked, use two separate if statements, one for each button. Change count by +1 or -1.

    Build a two-button counter.

      Run your program. This ticks when your code does all of the above.

      ModifyChange the code on purpose and check the result.

      Pick a background colour

      A control panel is a list of buttons. This program keeps the button names in a list, draws one button for each with a loop, and uses a loop in clicked to find which one was pressed. Add "lightgreen" to the list and see a fifth button appear. Then change the panel so the buttons sit in two rows.

      Try it yourselfYour edits are saved in this browser.
      ModifyChange the code on purpose and check the result.

      Use your toolkit

      You wrote the drawing and the click check by hand. Real programs keep them in a module. ui holds both as functions: draw_button and inside. Use them to add a second button that takes one away. Compare how many lines this took with your hand-built version.

      Try it yourselfYour edits are saved in this browser.

      For teachers

      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. About 55 minutes.

      Open the teacher guide: answers, solutions, slides and a worksheet.

      Students will be able to

      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

      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.

      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.

      What each step is for

      Now you can
      Next lesson9. Catch the turtleBuild a game that uses everything so far. The turtle hops along a path; catch it before it hides.