Mouse events¶
In the “switch” example we have shown how we can react in a program when the user presses a mouse button. Although for the user a click seems like a single action, we have seen that for the computer it is a sequence of events that starts with an event of the type pg.MOUSEBUTTONDOWN.
In the following examples and tasks, we will use three types of mouse-generated events:
Pressing any mouse button (like in the example with the switch), in which case event.type has a value of pg.MOUSEBUTTONDOWN
Releasing a mouse button, in which case event.type has a value of pg.MOUSEBUTTONUP
Moving the mouse, in which case event.type has a value of pg.MOUSEMOTION. In fact, when moving the mouse multiple such events are generated (each of them describing a small mouse movement in a very short time interval, so each event of this kind usually describes a movement of only a few pixels).
Event objects whose type is pg.MOUSEBUTTONDOWN also contain some additional information, such as:
event.pos - the position of the mouse at the time of registering the event (already used in the switch example)
event.button - a number from 1 to 5 indicating which mouse button is pressed (1 - left, 2 - middle, 3 - right, 4 - scroll up, 5 - scroll down)
Some of the additional event data contained in pg.MOUSEMOTION event objects are:
event.pos - the position of the mouse after the mouse motion event
event.rel - an ordered pair that describes how much the mouse position has changed since the previous mouse motion event
event.buttons - a three-element list of logical values, which determine for each of the three mouse buttons (0 - left, 1 - middle, 2 - right) whether it was pressed during mouse movement.
Click processing - exercises¶
You may not have noticed that in the “switch” program from the previous lesson, the light can be turned on and off by clicking any mouse button. This is because the same type of event is generated for each mouse button, and we did not check which button was pressed when the event occurred.
Task - left button as a switch:
Copy the “switch” program here, then modify it so that the light can be switched on and off only with the left mouse button.
Hint: Use event.button data.
(PyGame__interact_switch_left_button_eng)
Task - three switches:
Use parts of the “switch” program and create a program that simulates the work of three switches, as shown in the example.






import pygame as pg, petljapg
(width, height) = (800, 500)
canvas = petljapg.open_window(width, height, "Switches")
schema_images = (pg.image.load('Shema3_Off.png'), pg.image.load('Shema3_On.png'))
switch_images = (pg.image.load('SwitchOff.png'), pg.image.load('SwitchOn.png'))
bulb_images = (pg.image.load('BulbOff.png'), pg.image.load('BulbOn.png'))
switch_on = [False, False, False]
switch_pos = [(100, 200), (300, 150), (300, 250)]
bulb_pos = (500, 100)
# finish the program
(PyGame__interact_switches_eng)
Other mouse events¶
As it was mentioned at the beginning of this lesson, a program can also respond to mouse button release and mouse motion events. To do that, it is necessary to compare the value of event.type with the constants pg.MOUSEBUTTONUP and pg.MOUSEMOTION. The following are tasks where you can try this out.
Task - drawing lines:
Complete the program so that it can draw straight lines, as in the example.
import pygame as pg, petljapg
(width, height) = (400, 400)
canvas = petljapg.open_window(400, 400, "Lines with mouse")
mosue_pos = (0, 0)
line_start = mosue_pos
line_is_being_drawn = False
previous_lines = []
def new_frame():
canvas.fill(pg.Color("white")) # paint canvas
if line_is_being_drawn:
pg.draw.line(canvas, pg.Color('black'), line_start, mosue_pos)
for a, b in previous_lines:
pg.draw.line(canvas, pg.Color('black'), a, b)
def handle_event(event):
global line_is_being_drawn, line_start, mosue_pos
# add statements here that work as follows:
# if the event type is "mouse button down":
# the line drawing mode is switched on
# we start the line at the current position of the mouse
# otherwise, if the event type is "mouse button going up":
# the line drawing mode is switched off
# the new line is from the memorized start of the line to the current position of the mouse
# add a new line to the list of previous lines
# otherwise, if the event type is "moving mouse":
# in the mouse_pos variable, remember the current position of the mouse
petljapg.frame_loop(30, new_frame, handle_event)
(PyGame__interact_mouse_lines1_eng)
Task - drawing lines with deletion:
Copy the program for drawing lines below, then add an ability to delete all lines with a right-click.
Hint: To distinguish between left and right mouse buttons in the program, the event.button data must be used again. The code in the handle_event function should now look something like this:
if the event type is "mouse button going down":
if button 1 (left button) is pressed
the line drawing mode is switched on
the new line is from the memorized start of the line to the current position of the mouse
if button 3 (right button) is pressed
empty the list of previous lines
otherwise, if the event type is "releasing mouse button":
if button 1 (left button) is pressed
the line drawing mode is switched off
the new line is from the memorized start of the line to the current position of the mouse
add a new line to the list of previous lines
otherwise, if the event type is "move mouse":
remember the current position of the mouse in the mouse_pos variable
(PyGame__interact_mouse_lines2_part_eng)
(PyGame__interact_mouse_lines2_eng)
Task - dragging:
The following program shows how to allow the user of the program to drag objects.
Try the program out (drag the apples into the basket) and try to understand it, then answer the questions below.



import pygame as pg, petljapg, random
(width, height) = (600, 400)
canvas = petljapg.open_window(width, height, "Dragging with mouse")
basket_image = pg.image.load("basket.png") # read the basket image
apple_image = pg.image.load("apple.png") # read the apple image
scene_image = pg.image.load("drag_scene.png") # read the scene image
apple_positions = []
for i in range(5):
apple_positions.append((random.randint(50, 200), random.randint(80, 130)))
basket_pos = (300, 200)
i_apple = -1 # which apple is currently being draged (-1 means none)
done = False
def mouse_is_on_image(mouse_pos, image_pos, image):
x, y = mouse_pos
x0, y0 = image_pos # upper left corner
dx, dy = image.get_width(), image.get_height() # image size
return x0 <= x and x <= x0 + dx and y0 <= y and y <= y0 + dy
def new_frame():
canvas.blit(scene_image, (0, 0)) # display scene
if not done:
canvas.blit(basket_image, basket_pos) # display the basket
for apple_pos in apple_positions: # display apples
canvas.blit(apple_image, apple_pos)
def handle_event(event):
global apple_positions, i_apple, done
if event.type == pg.MOUSEBUTTONDOWN: # pritisnuto je dugme miša
for i in range(len(apple_positions)):
# if mouse is on one of the apples
if mouse_is_on_image(event.pos, apple_positions[i], apple_image):
i_apple = i # start dragging
elif event.type == pg.MOUSEBUTTONUP: # mouse button released
if mouse_is_on_image(event.pos, basket_pos, basket_image):
del apple_positions[i_apple]
if len(apple_positions) == 0:
done = True
i_apple = -1 # finish dragging
elif event.type == pg.MOUSEMOTION: # mouse moved
if i_apple >= 0: # if dragging is in progress
# calculate the position of the apple (upper left corner of the image)
# so that the center of the apple is at the mouse
mouse_x, mouse_y = event.pos
x = mouse_x - apple_image.get_width() // 2
y = mouse_y - apple_image.get_height() // 2
apple_positions[i_apple] = (x, y)
petljapg.frame_loop(30, new_frame, handle_event)
(PyGame__interact_drag_eng)
Q-79: What is the i_apple variable in the program?
Q-80: How do we distinguish between dragging and plain mouse movement in a program?