На этом занятии
мы с вами познакомимся с обработкой событий от мыши. Всего в PyGame существует четыре
их типа (значение атрибута type объекта Event):
-
pygame.MOUSEBUTTONDOWN
– нажатие кнопки мыши;
-
pygame.MOUSEBUTTONUP
– отпускание кнопки мыши;
-
pygame.MOUSEMOTION
– перемещение курсора мыши;
-
pygame.MOUSEWHEEL
– кручение колесика мыши.
Давайте для
начала рассмотрим пример обработки события pygame.MOUSEBUTTONDOWN:
import pygame
pygame.init()
W = 600
H = 400
sc = pygame.display.set_mode((W, H))
pygame.display.set_caption("События от мыши")
pygame.display.set_icon(pygame.image.load("app.bmp"))
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
FPS = 60 # число кадров в секунду
clock = pygame.time.Clock()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
print("Нажата кнопка: ", event.button)
clock.tick(FPS)
Здесь при
возникновении события pygame.MOUSEBUTTONDOWN в консоль
выводится информация о номере нажатой кнопки, используя свойство button объекта event. Причем, это
свойство существует только в событиях от мыши. Поэтому, мы сначала должны
проверить, что объект Event действительно соответствует одному из
событий мыши и только потом обращаться к свойству button. Иначе,
возникнет исключение, что такого атрибута не существует.
После запуска
этой программы мы видим, что кнопкам мыши присвоены следующие значения:
-
1
– левая кнопка;
-
2
– центральная;
-
3
– правая кнопка;
-
4
– для колесика.
Если в этой
программе добавить следующие две строчки:
elif event.type == pygame.MOUSEMOTION:
print("Позиция мыши: ", event.pos)
То в консоли мы
увидим кортеж из координат положения мыши относительно клиентской области окна.
То есть, свойство pos хранит координаты мыши и мы ими всегда можем
воспользоваться.
Если вместо
атрибута pos записать
атрибут rel:
print("Смещение мыши: ", event.rel)
то увидим
относительные смещения курсора мыши (относительно положения в предыдущем
событии MOUSEMOTION). Причем,
свойство rel существует
только для события pygame.MOUSEMOTION.
Давайте теперь
рассмотрим программу, которая позволяет рисовать в окне прямоугольник с помощью
мыши. Она будет следующей:
flStartDraw = False
sp = ep = None
sc.fill(WHITE)
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
flStartDraw = True
sp = event.pos
elif event.type == pygame.MOUSEMOTION:
if flStartDraw:
pos = event.pos
width = pos[0] - sp[0]
height = pos[1] - sp[1]
sc.fill(WHITE)
pygame.draw.rect(sc, RED, pygame.Rect(sp[0], sp[1], width, height))
pygame.display.update()
elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
flStartDraw = False
clock.tick(FPS)
Ее работа вполне
очевидна. При нажатии на левую кнопку мыши мы устанавливаем флаг flStartDraw в значение True, т.е. включаем
режим рисования при перемещении мыши. Соответственно, при событии MOUSEMOTION срабатывает
условие и рисуется прямоугольник от начальной координаты sp до текущей
позиции pos. При отпускании
левой кнопки мыши, переменная flStartDraw становится
равной False.
Однако, обратите
внимание, события MOUSEBUTTONDOWN и MOUSEBUTTONUP срабатывают
только один раз. То есть, если все время держать нажатой кнопку мыши, то
произойдет только одно событие MOUSEBUTTONDOWN. А вот событие MOUSEMOTION происходит постоянно
при каждом перемещении курсора мыши в клиентской области окна.
Если на каждой
итерации главного цикла нужно определять: нажата ли какая-либо кнопка мыши, то
следует использовать модуль
pygame.mouse
в котором, в
частности, имеется функция:
pygame.mouse.get_pressed()
Она работает
аналогично функции pygame.key.get_pressed() – определения
нажатия клавиш, о которой мы говорили на прошлом занятии. Здесь все то же
самое, только с кнопками мыши. На выходе pygame.mouse.get_pressed() выдает
кортеж с тремя значениями:
Единица
соответствует нажатой кнопке в соответствии с ее индексом:
-
0
– левая кнопка;
-
1
– центральная;
-
2
– правая кнопка.
Перепишем
предыдущую программу с использованием этой функции:
sp = None
sc.fill(WHITE)
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
pressed = pygame.mouse.get_pressed()
if pressed[0]:
pos = pygame.mouse.get_pos()
if sp is None:
sp = pos
width = pos[0] - sp[0]
height = pos[1] - sp[1]
sc.fill(WHITE)
pygame.draw.rect(sc, RED, pygame.Rect(sp[0], sp[1], width, height))
pygame.display.update()
else:
sp = None
clock.tick(FPS)
Смотрите, мы
здесь вначале проверяем нажатие левой кнопки мыши (индекс 0) и если величина sp равна None, то начальной
позиции для рисования прямоугольника еще нет и ее нужно приравнять текущей
позиции курсора. Текущая позиция определяется с помощью функции get_pos(). Затем,
удерживая нажатой левую кнопку и перемещая мышь, мы будем получать другие
значения pos, но начальная
позиция sp будет
неизменной. В результате выполняется рисование прямоугольника. При отпускании
левой кнопки, значение sp вновь становится
равным None.
Наконец, можно
скрыть курсор мыши с помощью функции:
pygame.mouse.set_visible(False)
И отобразить
свой собственный, например, так:
pygame.mouse.set_visible(False)
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
sc.fill(WHITE)
pos = pygame.mouse.get_pos()
if pygame.mouse.get_focused():
pygame.draw.circle(sc, BLUE, pos, 7)
pressed = pygame.mouse.get_pressed()
if pressed[0]:
if sp is None:
sp = pos
width = pos[0] - sp[0]
height = pos[1] - sp[1]
pygame.draw.rect(sc, RED, pygame.Rect(sp[0], sp[1], width, height))
else:
sp = None
pygame.display.update()
clock.tick(FPS)
Мы здесь в
каждой позиции скрытого курсора рисуем синий кружок радиусом 7. При этом
проверяем: находится ли курсор в области окна (иначе, его рисовать нет смысла).
Конечно, это не
все функции модуля pygame.mouse, подробнее
можно почитать на странице официальной документации:
https://www.pygame.org/docs/ref/mouse.html