Mouse Interactions in Python

Using mouse position and button presses is a basic form of communication with a computer. The use of the mouse position to activate some visual device on the screen like a button is familiar to everyone who uses a computer, although it is being gradually replaced by touch screens. When the user moves the mouse, a cursor or indicator moves correspondingly. The position of this cursor indicates a point on the screen that is active in some way, and if a graphical device is there, then it can be manipulated using the mouse buttons. The problem is that a mouse button press can occur at any time; it is unpredictable. This is what programmers call an event: something that happens at an unpredictable moment that must be dealt with. Some software someplace must be watching the mouse at all times, determining the x and y coordinates of the cursor on the screen and drawing the cursor in the correct place.

Pygame continually updates the position of the mouse, which means the loca­tion of the mouse cursor on the computer screen in x,y coordinates. which can be accessed using function getpos:

pygame.mouse.get pos()

which returns a tuple (mx, my) with the mouse coordinates. This is perfectly fine, but can be a bit awkward. The x position of the mouse is pygame.mouse. get_pos()[0], for example. It reads poorly. One suggestion would be to have func­tions mouseX() and mouseY(), which return the most recent x and y coordinates. It costs some execution time, but often looks better in the code.

Another suggestion is to place the following code at the beginning of the event loop:

mouseX, mouseY = pygame.mouse.get pos()

This would mean that the variables mouseX and mouseY would always hold the current mouse position.

Example: Draw a Circle at the Mouse Cursor

Drawing a circle at the current mouse position involves repeatedly determin­ing the mouse position and then drawing a circle at that set of coordinates. This should be done within a draw() function or the main loop. An example imple­mentation is as follows:

import pygame FPS = 30

screen = pygame.display.set mode((400, 400))

clock = pygame.time.Clock()

while True:

clock.tick(FPS)

mouseX, mouseY = pygame.mouse.get pos()

for event in pygame.event.get():

if event.type == pygame.QUIT:

quit()

screen.fill((200,200,200))

pygame.draw.circle (screen, (200,0,0),(mouseX, mouseY), 20, 2)

pygame.display.update()

The result is a red circle that follows the mouse. The screen.fill function sets the background color to a grey level of 200. The circle call draws the circle 30 times per second, every time the event loop executes. The most recent mouse po­sition is always found using the functions variables mouseX and mouseY, set at the top of the loop. It is necessary to call screen.fill() each time the loop executes because it erases the previous screen, drawing over it. If this were not done, then multiple circles would appear on the screen, one for each time the event loop executed (Figure 9.1).

Example: Change Background Color Using the Mouse

The idea here is to change the background color based on the mouse position. There are only two directions to move, horizontally or vertically, so one of the three colors remains constant; let that color be blue. The horizontal mouse posi­tion controls the red value, with the leftmost position representing no red and the rightmost representing full red (255). Similarly, the mouse at the bottom of the image represents no green, and at the top it represents full green. The background color will be changed during the event loop (using screen.fill).

Given that the position of the mouse on the screen is given by mouseX, the value of the red coordinate will be (mouseX/width*255). It may require a change in x coordinate of multiple pixels to shift the color by one unit. A similar expres­sion is used to change the green value.

The program is as follows:

import pygame

FPS = 30

width = 400

height = 400

screen = pygame.display.set mode((width, height))

clock = pygame.time.Clock()

while True:

clock.tick(FPS)

mouseX, mouseY = pygame.mouse.get pos()

for event in pygame.event.get():

if event.type == pygame.QUIT:

quit()

r = (mouseX/width) *255.0

g = (mouseY/height)*255.0

screen.fill ((r, g, 128))

pygame.display.update()

From now on only the key parts of the program will be shown, and not the entire initialization and event loop.

1. Mouse Buttons

Mouse button clicks, as they are called, can be retrieved by writing a func­tion that handles them. Each time a mouse button is pressed Pygame indicates an event that can be identified in the main event loop. Events can be ignored, of course.

All Pygame code so far contains the statements:

for event in pygame.event.get():

if event.type == pygame.QUIT:

quit()

The variable event is set by Pygame to some thing that happened. The pyg­ame.QUIT event refers to the end of the program, perhaps by the user clicking the “X” in the upper right corner or some other way. Mouse actions are also events. A mouse button can be pressed or released, and when both happens, we call that a mouse click. The mouse button pressed event is an event type named pygame.MOUSEBUTTONDOWN and can be handled in the same way as the QUIT event is handled:

if event.type == pygame.MOUSEBUTTONDOWN:

do something …

Similarly, when the mouse button is released, we can capture that event, too:

if event.type == pygame.MOUSEBUTTONUP:

do something .

If we write a function named mousePressed() that is called within the event loop when the mouse button is depressed and a corresponding function mouseRe- leased for when the mouse button is released, than the event loop does not get cluttered with the details of what the specific mouse operation is doing, only that it has happened. The details are left to the two functions. If the mouse button is pressed, then the mouse is moved, and then it is released, the coordinates of the press and the release point will be different, and both can be retrieved. For ex­ample, when the mouse button is pressed, the mouse coordinates could be saved as the beginning of a line, and when released, the coordinates could be the end of the line. Multiple lines could be drawn in this way.

Example: Draw Lines Using the Mouse

Using the scheme described above, the function mousePressed() will store the mouse position in global variables x0 and y0, and mouseReleased() will store the release coordinates at x1 and y1. mouseReleased() will also draw the line from (x0,y0) to (x1, y1):

def mousePressed ():

global x0, y0

x0 = mouseX

y0 = mouseY

def mouseReleased ():

global x1, y1

x1 = mouseX

y1 = mouseY

pygame.draw.line(screen, (0,0,0),   (x0, y0),  (x1,y1), 2)

Drawing is performed inside of mouseReleased(). Within the event loop, these functions are called when the mouse events occur:

for event in pygame.event.get():

if event.type == pygame.MOUSEBUTTONDOWN:

mousePressed()

if event.type == pygame.MOUSEBUTTONUP:

mouseReleased()

A mouse usually has more than one button. We’ll modify these functions later to accept a parameter, which will be an indicator of what button was pressed.

Example: A Button

This example program changes the background color of the drawing window when a graphical button is pressed. A button, in the user interface sense, is a rectangular region on the computer screen that responds to a mouse click with a specific action. It is a two-part process: when the mouse cursor enters the rect­angular region, the button is said to be activated. Sometimes it will be caused to change color at this point, or some other action will be performed that indicates that it is ready to function. When a mouse button is pressed while the button is activated, then some action occurs, usually as defined by a function being called. The basic idea is simple enough to implement, although some buttons can have complex actions such as sounds, images, and irregular shapes.

The cursor is within a rectangular region when its coordinates are greater than the upper left coordinate of the rectangle and smaller than the lower right co­ordinates. When that occurs, the button is ready to be pressed, and should change color. This does not require anything but knowledge of the mouse coordinates. It the left button is pressed in this state (activated) then the action defined by the button will occur; the background color will change, in this case. The program begins as normal, with imports and initialization. Here is a program that does this for a button at (100, 100) that is 60×20 pixels in size:

All of the software buttons everywhere work in basically this way.

Source: Parker James R. (2021), Python: An Introduction to Programming, Mercury Learning and Information; Second edition.

Leave a Reply

Your email address will not be published. Required fields are marked *