Skip to main content

Section 10.7 Event Handlers

An event handler is a function that you write that will get called automatically by the Python interpreter when the operating system (Windows, MacOS, Android, Linux, iOS, etc.) tells Python that an event happened in the window of a running Python program. If the end user clicks in the window where your Python program is running, that window gets the operating system focus. If the user then clicks on a user interface widget in that window, the operating system tells Python where the click happened and Python figures out if the click happened on a widget. If you have registered an event handler for mouse clicks on that widget, then that function is called.
We can generally think about two types of handlers. First there are widget handlers. These are functions you write that run code in response to the user interacting with the graphical user interface widgets you have put on screen. This may be clicking on a button, selecting an item from a drop-down menu, moving a slider, checking or unchecking a checkbox, entering text into an input field, or moving a scrollbar. The second type of handler is a more general mouse or keyboard handler. These handlers get called when the user performs actions with an input device, while your program is the program in focus. So, if the user has opened your Python program, but then switched over to type up a letter in MS Word, your Python program will not get the user’s mouse input or keyboard input while they are working in MS Word. But, when the user switches back to your Python program, then your handlers will get their input actions and execute.

Subsection 10.7.1 UI Widget Event Handlers

Widget event handlers get called in response to the end user interacting with a user interface widget/control that you have programmed to be displayed on screen. Some widget event handlers will have input parameters. You saw this in the previous section with the input text box: the handler for that widget needed a parameter, and that’s how the text the user types can be accessed. The list below gives a sense of the types of information that would be passed automatically to an event handler for different types of user interface controls:
  • text input box - the text the user enters (string)
  • checkbox - whether the user checked or unchecked it (boolean)
  • drop down menu - the item the user selected (string)
  • slider - the value selected by the slider (integer or floating point number)
  • scrollbar - the location of the scrollbar tab as a percent of the length of the scrollbar
Some inputs, like simple buttons, don’t require any information to be passed, other than the fact that they were pressed, and so the event handler doesn’t need any parameters.

Subsection 10.7.2 Window-Based Input Event Handlers

Window-based input event handlers are called when the user types keys on the keyboard or uses their pointing device to click or drag in a work area of the window, such as on a drawing canvas or on text document. GUI toolkits use ‘mouse’ event terminology, even though in many cases the user is using something like a touchpad or touch screen gestures on a touch-sensitive tablet or laptop.
The operating system will notify the Python interpreter of any such events while your program is in focus on screen, but you must tell Python what type of events you want to respond to. This is done by registering an event handler. If you don’t register a handler for an event your program won’t respond to that event.
When you create input event handlers, you need to decide exactly what you want to respond to. Do you want to respond to a user when they press down the button on their pointing devices or when they lift up their finger off that button? Below is a list of common input events, along with the information that would likely be passed along to the handler function as parameters:
  • mouse click - x and y coordinates, and which button (left, middle, right)
  • mouse double-click - x and y coordinates, and which button (left, middle, right)
  • mouse drag - x and y coordinates of current drag position
  • mouse button down - x and y coordinates, and which button (left, middle, right)
  • mouse button up - x and y coordinates, and which button (left, middle, right)
  • mouse scroll wheel - x and y coordinates, scroll speed, scroll direction (up/down)
  • mouse hover - x and y coordinates
  • keypress - which key, and which modifier keys (SHIFT, CTRL, etc.)
  • key up - which key, and which modifier keys (SHIFT, CTRL, etc.)
  • key down - which key, and which modifier keys (SHIFT, CTRL, etc.)
Different GUI toolkits will handle events slightly differently. For example, some toolkits will allow you to register events for specific keys, while other toolkits will only allow you to register general key events and then pass you the information about what key was pressed. In this latter case, you need to use conditional statements inside the key event listeners to specify what code executes depending on what key was activated. The SimpleGUI module we are working with in this chapter only handles mouse click and drag and key up and down events.
It is fairly typical that event handler functions are really short. They often contain only one or two lines of code, and these lines just call some other functions. Remember than we never call handler functions directly, they only get called by the system. Think about a turtle program that has a function that draws a square in a random location on a canvas. This function can be written once, and then it can be called from a keyboard handler when the user presses ‘s’ and from a mouse handler when the user clicks on the canvas. Each of these handlers would just have one line of code - the call to the random square drawing function. This organization gives us more flexibility, and allows us to not have repeated code (it would be bad to have the same square drawing code in both the keyboard handler for key s, and in the mouse click handler).

Subsection 10.7.3 Registering Event Handlers

In addition to writing an event handler function, you also need to register the event handler, so that the Python interpreter knows that you want to receive such events. In some toolkits, you register the event on a separate line of code That is the case in the turtle examples seen in earlier chapters. In the SimpleGUI module, you register handlers in the same line of code that you use to create the user interface widget (for buttons and textboxes), but you have separate instructions to register the more general event handlers that respond to key presses and mouse clicks.
In all cases, once you have added GUI elements to the window, written the event handlers, and registered the event handlers, you need something to tell the Python interpreter to start listening for events (in the Turtle module it’s wn.listen(); in the SimpleGUI module it’s frame.start()).
Check your understanding

Checkpoint 10.7.1.

    import simplegui
    
    CANVAS_WIDTH = 400
    CANVAS_HEIGHT = 400
    circle_list = []
    canvas_col = "White"
    # GUI Control Handlers
    def draw(canvas):
        for index in range(len(circle_list)):
            canvas.draw_circle(circle_list[index], 10, 3, "Black", "Red")
    
    def clear_handler():
        clear_canvas()
        
    def drag(pos):
        add_circle(pos)
    
    def add_circle(pos):
        circle_list.append(pos) 
        
    def clear_canvas():
        circle_list.clear()
    # Frame
    frame = simplegui.create_frame("COMP 1000 Demo", CANVAS_WIDTH, CANVAS_HEIGHT)
    frame.set_canvas_background(canvas_col)
    # Register Keyboard and Mouse Event Handlers
    frame.set_draw_handler(draw)
    frame.set_mousedrag_handler(drag)
    frame.add_button('Clear', clear_handler)
    # Show the frame and start listening
    frame.start()
    
    What would happen if a user was running this code in CodeSkulptor3 and clicked on the canvas once?
  • A circle will be drawn where the user clicked.
  • It’s reasonable to expect this, but CodeSkulptor3 has unique handlers for both individual mouse clicks and for dragging the mouse click.
  • A circle is drawn where the user initially clicked, and continues to draw circles on the position of the mouse around the canvas.
  • Mouse drag handlers only register continuous dragging inputs and not individual clicks. Even if the mouse drag handler recognized the initial click, without dragging the mouse on the canvas there are no more inputs to keep drawing circles.
  • This code does not run, it contains an error.
  • Incorrect. Try running this code in CodeSkulptor3 to test what happens yourself.
  • Nothing happens.
  • Correct! Mouse drag handlers do not recieve inputs from individual clicks and so nothing is drawn on the canvas.

Checkpoint 10.7.2.

    import simplegui
    
    CANVAS_WIDTH = 400
    CANVAS_HEIGHT = 400
    circle_list = []
    canvas_col = "White"
    # GUI Control Handlers
    def draw(canvas):
        for index in range(len(circle_list)):
            canvas.draw_circle(circle_list[index], 10, 3, "Black", "Red")
    
    def clear_handler():
        clear_canvas()
        
    def drag(pos):
        add_circle(pos)
    
    def add_circle(pos):
        circle_list.append(pos) 
        
    def clear_canvas():
        circle_list.clear()
    # Frame
    frame = simplegui.create_frame("COMP 1000 Demo", CANVAS_WIDTH, CANVAS_HEIGHT)
    frame.set_canvas_background(canvas_col)
    # Register Keyboard and Mouse Event Handlers
    frame.set_draw_handler(draw)
    frame.set_mousedrag_handler(drag)
    frame.add_button('Clear', clear_handler)
    # Show the frame and start listening
    frame.start()
    
    What would happen if a user running this code in CodeSkulptor3 held their mouse click and dragged on the canvas?
  • Circles are drawn continously wherever the user drags their mouse on the canvas.
  • Correct! The Input Event handler adds the current position of the mouse to ’circle_list’ which is repeatedly drawn on the canvas.
  • A circle is drawn only where the user initially clicked.
  • Close! A circle will be drawn there, but not only there! Try running this example in CodeSkulptor3 to test it for yourself.
  • Nothing happens, this code contains an error.
  • Incorrect. Try running this example in CodeSkulptor3 to test what happens yourself.
  • Nothing happens.
  • Incorrect. Try running this example in CodeSkulptor3 to test what happens yourself.

Checkpoint 10.7.3.

    import simplegui
    
    CANVAS_WIDTH = 400
    CANVAS_HEIGHT = 400
    circle_list = []
    canvas_col = "White"
    # GUI Control Handlers
    def draw(canvas):
        for index in range(len(circle_list)):
            canvas.draw_circle(circle_list[index], 10, 3, "Black", "Red")
    
    def clear_handler():
        clear_canvas()
        
    def drag(pos):
        add_circle(pos)
    
    def add_circle(pos):
        circle_list.append(pos) 
        
    def clear_canvas():
        circle_list.clear()
    # Frame
    frame = simplegui.create_frame("COMP 1000 Demo", CANVAS_WIDTH, CANVAS_HEIGHT)
    frame.set_canvas_background(canvas_col)
    # Register Keyboard and Mouse Event Handlers
    frame.set_draw_handler(draw)
    frame.set_mousedrag_handler(drag)
    frame.add_button('Clear', clear_handler)
    # Show the frame and start listening
    frame.start()
    
    Which line of code defines a Widget Event handler function?
  • add_circle(pos).
  • This function is called by an Input Event handler.
  • clear_handler().
  • This is correct! When a user presses the ’Clear’ button this handler calls on the ’clear_canvas’ function.
  • drag(pos).
  • So close! But this line defines an Input Handler function instead of a Widget Handler function.
  • None of the above.
  • There is a Widget Event handler defined in the code above. Try running this code in Codeskulptor3 and think about what line of code gets called when a user presses on the button widget.

Checkpoint 10.7.4.

    import simplegui
    
    CANVAS_WIDTH = 400
    CANVAS_HEIGHT = 400
    circle_list = []
    canvas_col = "White"
    # GUI Control Handlers
    def draw(canvas):
        for index in range(len(circle_list)):
            canvas.draw_circle(circle_list[index], 10, 3, "Black", "Red")
    
    def clear_handler():
        clear_canvas()
        
    def drag(pos):
        add_circle(pos)
    
    def add_circle(pos):
        circle_list.append(pos) 
        
    def clear_canvas():
        circle_list.clear()
    # Frame
    frame = simplegui.create_frame("COMP 1000 Demo", CANVAS_WIDTH, CANVAS_HEIGHT)
    frame.set_canvas_background(canvas_col)
    # Register Keyboard and Mouse Event Handlers
    frame.set_draw_handler(draw)
    frame.set_mousedrag_handler(drag)
    frame.add_button('Clear', clear_handler)
    # Show the frame and start listening
    frame.start()
    
    Which line of code defines an Input Event handler function?
  • drag(pos).
  • Correct! This function is called when the user holds down mouseclick and drags on the canvas.
  • clear_handler().
  • Close! This line defines a Widget Event handler.
  • add_circle(pos).
  • So close! This function does not define an Input Event handler, but is instead called by one when the user holds mouseclick and drags.
  • None of the above.
  • There is an Input Event handler defined in the code above. Try running this code in Codeskulptor3 and think about what line of code gets called when a user holds mouseclick and drags along the canvas.

Checkpoint 10.7.5.

    import simplegui
    
    CANVAS_WIDTH = 400
    CANVAS_HEIGHT = 400
    circle_list = []
    canvas_col = "White"
    # GUI Control Handlers
    def draw(canvas):
        for index in range(len(circle_list)):
            canvas.draw_circle(circle_list[index], 10, 3, "Black", "Red")
    
    def clear_handler():
        clear_canvas()
        
    def drag(pos):
        add_circle(pos)
    
    def add_circle(pos):
        circle_list.append(pos) 
        
    def clear_canvas():
        circle_list.clear()
    # Frame
    frame = simplegui.create_frame("COMP 1000 Demo", CANVAS_WIDTH, CANVAS_HEIGHT)
    frame.set_canvas_background(canvas_col)
    # Register Keyboard and Mouse Event Handlers
    frame.set_draw_handler(draw)
    frame.set_mousedrag_handler(drag)
    frame.add_button('Clear', clear_handler)
    # Show the frame and start listening
    frame.start()
    
    Two functions in this example use the same input data from the argument labeled (pos). Which data type does the argument (pos) require?
  • An X coordinate in the form of an integer.
  • The ’draw(canvas)’ function cannot draw anything if it only knows where to draw on one axis.
  • A Y coordinate in the form of an integer.
  • The ’draw(canvas)’ function cannot draw anything if it only knows where to draw on one axis.
  • An X coordinate and a Y coordinate in the form of a list.
  • So close! Because the value is provided by the location of the mouse on the canvas and cannot be altered it is not contained as a list.
  • An X and a Y coordinate in the form of a tuple.
  • Correct! Because the input comes from the location of the mouse the data cannot be altered by the code and must be a tuple instead of a list.
You have attempted of activities on this page.