Skip to content

8 min read

American Corners

Event-driven basics

What is an event?

So far your programs have run from top to bottom and then stopped. They did exactly what you wrote, in the order you wrote it, without ever pausing to ask what you wanted next. Real programs are not like that. A game of Minesweeper does nothing until you click a square. Your phone sits quietly until you press a key. These programs spend most of their time waiting.

An event is an action that comes from outside the running program but changes what it does. You press a key, you click the mouse, you move the mouse: each of those is an event. The program is not in charge of when they happen. You are. Event-driven programming is simply writing code that waits for these actions and reacts to them.

Common events include:

  • pressing a key on the keyboard (an arrow key, a letter key)
  • clicking the mouse
  • moving the mouse
  • shortcuts like Ctrl+C to copy or Ctrl+V to paste

Think of your Turtle as a small robot on the screen. Up to now you told it every move in advance. Now you are going to let a person drive it live.

Listening for a key press

To react to a key, you need three things: a screen that can hear events, a function that says what to do, and a line that connects a key to that function. In Turtle it looks like this.

screen = turtle.Screen()

def my_function():
    # write code here
    pass

screen.onkey(my_function, "Up")
screen.listen()

Read it line by line. screen = turtle.Screen() creates the screen that will listen for events. The function is what runs when the event happens. screen.onkey(my_function, "Up") says: when the "Up" key is pressed, call my_function. The key name can be "Up", "Down", "Left", or "Right". Finally, screen.listen() tells the screen to start paying attention. Without that last line, nothing happens.

One thing catches everyone the first time. You pass my_function, not my_function(). With the brackets, Python would run the function right now and hand the screen its result. Without the brackets, you hand the screen the function itself, so it can call it later, each time the key is pressed.

Here is a small Etch-A-Sketch. The four arrow keys drive the turtle around the screen and it leaves a line behind it.

import turtle

screen = turtle.Screen()
pen = turtle.Turtle()

def go_up():
    pen.setheading(90)
    pen.forward(20)

def go_down():
    pen.setheading(270)
    pen.forward(20)

def go_left():
    pen.setheading(180)
    pen.forward(20)

def go_right():
    pen.setheading(0)
    pen.forward(20)

screen.onkey(go_up, "Up")
screen.onkey(go_down, "Down")
screen.onkey(go_left, "Left")
screen.onkey(go_right, "Right")
screen.listen()

turtle.done()

Notice there is no loop telling the turtle to move. It moves only when you press a key, twenty pixels at a time. The program is doing nothing in between, just waiting for the next event.

Listening for a mouse click

A mouse click works almost the same way, with one difference: a click happens at a place, so the function receives that place. The handler must take two arguments, x and y, in that order. They are the coordinates of the mouse at the moment you clicked.

screen = turtle.Screen()

def my_function(x, y):
    # write code here
    pass

screen.onclick(my_function)

This small program moves the pen to wherever you click and stamps a mark there.

import turtle

screen = turtle.Screen()
pen = turtle.Turtle()
pen.penup()

def go_to_click(x, y):
    pen.goto(x, y)
    pen.stamp()

screen.onclick(go_to_click)

turtle.done()

Because the function is given x and y, it always knows exactly where the click landed, so it can send the turtle straight there.

State machines

Once a program reacts to events, a useful question appears: what should the same event do at different moments? Pressing the same button on your phone does one thing when the screen is locked and another when it is unlocked. The button did not change. The state of the phone did.

A state machine is a system that is always in one of a few states, and events move it from one state to the next. A phone starts in a state you could call "Awaiting PIN". Enter the correct PIN and it moves to "Ready". Lock it and it moves to "Locked". Each arrow is an event.

A traffic light is the simplest example. It cycles through three states, which we can number 0, 1 and 2, and each "tick" moves it to the next one, wrapping back to 0 after 2.

state = 0  # 0 = green, 1 = yellow, 2 = red

def next_light():
    global state
    state = (state + 1) % 3
    print("State is now", state)

The % 3 keeps the number in the range 0, 1, 2 forever, so after red it returns to green. Connect next_light to a key press and you have a traffic light you can step through yourself. This pairing, an event on the outside and a small piece of remembered state on the inside, is the heart of nearly every app and game you use.

Lab

Try the "out of bounds" game. Keep a turtle moving forward a few pixels at a time inside a loop. Bind the left arrow to a function that turns it left, and the right arrow to one that turns it right. Then check t.xcor() and t.ycor() each step; when the turtle leaves the screen, set a game_over variable to True, stop, and have it write "Out of bounds!". As a stretch, add one to a score on every step and show it on screen.

Check yourself

  1. In your own words, what makes a program "event-driven", and how is that different from a program that runs top to bottom and stops?
  2. In screen.onkey(go_up, "Up"), why do we write go_up and not go_up()? What would go wrong with the brackets?
  3. A mouse-click handler is written def my_function(x, y): but a key handler is just def my_function():. Why does the click handler need two arguments and the key handler need none?

Where this lesson comes from

Built from

  • Programming in a Data World: Lecture 5 deck (Event Listener) and event-listener block in the Lecture Notebook

alphaPlan courses are built from taught programmes rather than invented for the web. Where a claim rests on an outside standard or a reported case, it is named above so you can check it rather than take our word for it.

This course was developed by alphaPlan Center from programs delivered in partnership with the American Corners network.

Found something unclear, outdated or improvable? Suggest an improvement