Python Pygame事件监控:键盘事件和鼠标事件

我们在前面已经介绍过,任何时候,当用户做了诸如按下一个按键或者移动鼠标等动作,Pygame 库都会创建一个 pygame.event.Event 对象来记录这个动作,这就是“事件”。

我们可以调用 pygame.event.get() 函数来搞清楚发生了什么事件,例如,本章前面用到了检测关闭事件的功能来关闭 Pygame 窗口。接下来,我们学习一下如何监控键盘事件和鼠标事件。

键盘事件

我们希望程序能够监控键盘,这样一旦按下某个键,程序就可以做相对应的事情。在 Pygame 中,按下某个键盘的事件就是 KEYDOWN,释放某个键盘的事件就是 KEYUP。

在前面的学习中,我们知道 pygame.event.get() 函数可以获取一个事件列表。for 循环迭代处理这个列表中的每一个事件,当看到 QUIT 事件,它会将变量 Running 设置为 False,这会导致 while 循环结束,并结束程序。

现在,我们要检测另一种类型的事件,也就是 KEYDOWN 和 KEYUP 事件,并且通过事件对象的 key 属性来识别按下的是键盘上的哪个键。

我们把上一节的示例稍作修改,以便可以通过方向键来移动文本 "Hello World!",还可以通过 Esc 键来关闭窗口,代码如下。
import pygame
pygame.init()
windowSurface=pygame.display.set_mode((800,600))

BLACK=(0,0,0)
WHITE=(255,255,255)
myString="Hello World!"
font = pygame.font.SysFont("Times New Roman", 48)
text = font.render(myString, True, WHITE)

picX=0
picY=0
speed=1

moveLeft = False
moveRight = False
moveUp = False
moveDown = False

Running=True
while Running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Running=False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                Running=False
            if event.key == pygame.K_LEFT:
                moveLeft = True
            if event.key == pygame.K_RIGHT:
                moveRight = True
            if event.key == pygame.K_UP:
                moveUp = True
            if event.key == pygame.K_DOWN:
                moveDown = True
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                moveLeft = False
            if event.key == pygame.K_RIGHT:
                moveRight = False
            if event.key == pygame.K_UP:
                moveUp = False
            if event.key == pygame.K_DOWN:
                moveDown = False
    if moveDown and text.get_height()+picY < 600:
        picY+=speed
    if moveUp and picY > 0:
        picY -= speed
    if moveLeft and picX > 0:
        picX -= speed
    if moveRight and text.get_width()+picX < 800:
        picX += speed
    windowSurface.fill(BLACK)
    windowSurface.blit(text, (picX,picY))
    pygame.display.update()
pygame.quit()

我们对新增的代码(突出显示的)给出一些说明。下面的代码创建了在每个方向上移动的变量,这 4 个布尔值变量用来记录按下的是哪个方向的键。例如,当用户按下键盘上向左的方向键时,把 moveLeft 设置为 True。当松开这个键时,把 moveLeft 设置为 False。
moveLeft = False
moveRight = False
moveUp = False
moveDown = False

然后在事件循环中判断事件类型,如果是 KEYDOWN,那么事件对象将有一个 key 属性来识别按下的是哪个键。
  • 如果 key 属性等于 K_ESCAPE,表示用户按下的是 Esc 键,意味着玩家希望结束程序,那么处理方式和检测到点击关闭窗口事件一样,也是将变量 Running 设置为 False,从而导致 while 循环结束,并结束程序。
  • 如果 key 属性等于 K_LEFT,表示用户按下的是向左方向键,那就把向左的移动变量 moveLeft 设置为 True。
  • 如果按下的是其他方向键,则把相应的移动变量设置为 True。

这段代码如下所示。
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                Running=False
            if event.key == pygame.K_LEFT:
                moveLeft = True
            if event.key == pygame.K_RIGHT:
                moveRight = True
            if event.key == pygame.K_UP:
                moveUp = True
            if event.key == pygame.K_DOWN:
                moveDown = True

当用户释放按下的键时,会触发 KEYUP 事件。如果释放的是向左方向键,那就把向左的移动变量 moveLeft 设置为 False,从而使得移动停止。如果释放的是其他方向键,则把相应的移动变量设置为 False。

这段代码如下所示。
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                moveLeft = False
            if event.key == pygame.K_RIGHT:
                moveRight = False
            if event.key == pygame.K_UP:
                moveUp = False
            if event.key == pygame.K_DOWN:
                moveDown = False

我们已经根据用户的按键,设置了移动变量。现在,根据这些移动变量来相应地调整变量 picX 和 picY,从而修改文本的坐标。如果变量 moveDown 为 True,表示按下了向下键,并且如果文本的底部不低于窗口的底部,就将变量 picY 增加 speed。因为我们会将 picY 设置为文本的 Y 坐标,那么就意味着要将文本向下移动。针对其他 3 个方向做的事情基本上是相同的。

这段代码如下所示。
if moveDown and text.get_height()+picY < 600:
        picY+=speed   
    if moveUp and picY > 0:
        picY -= speed
    if moveLeft and picX > 0:
        picX -= speed
    if moveRight and text.get_width()+picX < 800:
        picX += speed

然后通过 windowSurface.fill(BLACK),表示每次循环都要重新填充屏幕。最后调用 blit() 函数,将像素从一个 Surface 复制到另一个 Surface 之上,并且将 text 绘制到 X 坐标为 picX、Y 坐标为 picY 的位置。
    windowSurface.fill(BLACK)       
    windowSurface.blit(text, (picX,picY))

运行这段代码,就可以使用方向键在窗口中移动文本 "Hello World",如图 1 所示。

Python 鼠标事件

鼠标事件

前面学习了如何处理键盘事件,现在我们来介绍如果处理鼠标事件以及如何使用鼠标位置信息。在 Pygame 中,当在窗口中按下鼠标时会触发 MOUSEBUTTONDOWN 事件,当释放鼠标时会触发 MOUSEBUTTONUP 事件,当鼠标移动经过窗口时会触发 MOUSEMOTION 事件。

来看一个示例,如果用户点击鼠标左键,就会在点击的地方画一个黄色的小圆点,如果点击鼠标右键,就会清空屏幕,代码如下。
import pygame
pygame.init()
windowSurface=pygame.display.set_mode((800,600))
YELLOW=(255,255,0)
BLACK=(0,0,0)
Running=True
while Running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Running=False
        if event.type == pygame.MOUSEBUTTONDOWN:
             if pygame.mouse.get_pressed()[0]:
                point = event.pos
                pygame.draw.circle(windowSurface, YELLOW, point, 10)
             if pygame.mouse.get_pressed()[2]:
                 windowSurface.fill(BLACK)
    pygame.display.update()
pygame.quit()

其他代码在之前都已介绍过,这里不再赘述,我们重点介绍一下突出显示的新增代码。在迭代处理 pygame.event.get() 函数所获取的事件列表的 for 循环中,检测了 MOUSEBUTTONDOWN 事件,并且通过 mouse.get_pressed() 获取鼠标按键的情况:
  • 如果按下的是鼠标的第 1 个按钮,其索引为 0,表示按下的是左键;
  • 如果是第3个按钮,其索引是 2,表示按下的是右键。

如果按下左键,我们可以使用 event.pos 来获取鼠标点击事件的位置,并且将其赋值给变量 point。然后我们在 windowSurface 上绘制了一个位置在 point 的、半径为 10 的黄色实心圆。这样,就实现了点击鼠标左键,在点击的地方,绘制黄色的小圆点的功能。

如果按下的是鼠标右键,则调用 windowSurface.fill(BLACK),用黑色填充要绘制的 Surface,这相当于清空了之前绘制的所有内容。

运行代码,我们可以在屏幕上绘制一个钟表的形状,如图 2 所示。

Python 键盘事件
图 2