Abbiamo detto che, oltre all'attributo type
, l'oggetto Event contiene altri attributi (che variano secondo il tipo di
evento), che specificano meglio quello che è successo. La documentazione ufficiale non è molto chiara su di essi, e fornisce solo un
elenco sintetico di questi atributi; vediamone comunque alcuni che useremo spesso in seguito.
Un evento di tipo MOUSEBUTTONDOWN o MOUSEBUTTONUP ha, oltre al type
, altri due attributi:
pos |
una tuple con due elementi interi che contiene le coordinate del clic rispetto alla finestra principale di pygame; |
button |
un numero intero che indica quale bottone è stato premuto; anche qui pygame definisce una serie di costanti:
|
Quindi se ev
è una variabile di tipo Event (e ev.type == MOUSEBUTTONDOWN
o
ev.type == MOUSEBUTTONUP
) con ev.pos
otterrò la coppia (tuple) delle coordinate, con ev.pos[0]
la sola x (l'elemento della coppia di indice 0) e con ev.pos[1]
la sola y. Inoltre con ev.button
potrò
sapere quale bottone è stato premuto.
Anche l'evento MOUSEMOTION ha l'attributo pos
che funziona allo stesso modo.
Ricarichiamo il nostro programma prova_eventi.py, (qui), salviamolo come prova_clic.py e modifichiamolo in modo che scriva sulla finestra di IDLE le coordinate del nostro clic.
. . .
for ev in pygame.event.get():
if ev.type == QUIT: # chiusura della finestra
done = True
elif ev.type == MOUSEBUTTONDOWN: # click del mouse
mouse_x = ev.pos[0]
mouse_y = ev.pos[1]
print("Hai fatto click in", mouse_x, ",", mouse_y)
. . .
Nelle righe #16 e #17 assegniamo alla variabile mouse_x
la x del click
(che è l'elemento di indice 0 nella tuple ev.pos
) e a mouse_y
la y. Poi stampiamo il tutto con una
print()
. Notate che ho usato le due variabili mouse_x
e mouse_y
solo per rendere più chiaro il
codice, ma avrei potuto scrivere direttamente ev.pos[0]
e ev.pos[1]
tra gli argomenti della
print()
. Allenatevi a cliccare sulla finestra cercando di prevedere, più o meno, quali sono le coordinate del puntatore.
if ... elif
per ognuno dei possibili valori dell'attributo button
.elif
per il MOUSEBUTTONDOWN ed uno per il
MOUSEBUTTONUP).Un evento di tipo KEYDOWN e KEYUP ha invece degli attributi che ci dicono quale tasto è stato premuto.
unicode |
una string di Python. Se il tasto è un carattere stampabile i (lettera, numero, punteggiatura) la string contiene il carattere; se non è stampabile (es Invio, Alt, ecc.) essa è vuota. |
key |
un numero intero che determina quale tasto è stato premuto. Ad ogni tasto è assegnato un numero diverso, e per ricordarli tutti facilmente pygame fornisce un elenco di costanti in manera simile a quello che accade con gli eventi (ne parliamo tra poco). |
mod |
un altro numero intero per i "modificatori" (come Shift, Ctrl, Alt ...). Anche qui pygame fornisce un elenco di costanti per poter individuare facilmente il tasto. |
Ad esempio vediamo questo programma che controlla se l'attributo unicode
contiene effettivamente un carattere
e nel caso lo stampa:
import pygame
from pygame.locals import *
# inizializzazione
pygame.init()
screen = pygame.display.set_mode((800, 600))
# ciclo principale
done = False
while not done:
for ev in pygame.event.get():
if ev.type == QUIT: # chiusura della finestra
done = True
elif ev.type == KEYDOWN: # e' stato premuto un tasto
if (len(ev.unicode)) == 1: # se la string ev.unicode contiene un carattere ...
print(ev.unicode) # ... la stampa
else:
print("Carattere non stampabile")
# fine del ciclo e termine del programma
pygame.quit()
L'attributo key
, come abbiamo detto, non contiene invece un carattere stampabile, ma un numero diverso per
ogni possibile tasto della nostra tastiera. Come succede per gli eventi, pygame definisce nel sottomodulo locals una serie di costanti
(variabili scritte tutte in lettere maiuscole) per ricordare facilmente il tasto: ad esempio K_ESCAPE è il tasto Esc, K_TAB il Tab, ecc..
L'elenco completo è qui, nel riquadro giallo:
https://www.pygame.org/docs/ref/key.html.
Per accorgersi se abbiamo premuto Esc scriveremo quindi if ev.key == K_ESCAPE:
ecc. L'attributo key
ha il vantaggio,
rispetto all'unicode
, di poter rappresentare tutti i tasti della nostra tastiera. Provate a
modificare il programma in questo modo:
. . .
elif ev.type == KEYDOWN: # e' stato premuto un tasto
if ev.key == K_ESCAPE:
print("Hai premuto ESC")
elif ev.key == K_TAB:
print("Hai premuto TAB")
# fine del ciclo e termine del programma
pygame.quit()
Se però provate a stampare direttamente l'attributo ev.key
con print(ev.key)
vedrete che IDLE stamperà dei
numeri per voi senza senso.
input()
finale con il ciclo
degli eventi, facendoli finire come quelli mostrati.input()
dei vecchi programmi. In questo
modo, dopo aver disegnato sullo schermo, il programma entrerà nel ciclo principale e si metterà in attesa della nostra chiusura.Riprendiamo anche il programma due_quadrati.py (se avete svolto gli
esercizi della lezione precedente i quadrati potrebbero essere posizionati diversamente o avere altre dimensioni: per il momento
basta che non siano sovrapposti). Nel ciclo degli eventi verificheremo, per mezzo del metodo
collidepoint()
dell'oggetto Rect e dell'attributo pos
, se l'utente clicca all'interno di essi. Per comodità
vi riscrivo il programma completo.
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800, 600))
# creiamo la Surface surf1, la coloriamo di rosso e la posizioniamo sullo schermo
surf1 = pygame.Surface((200, 200))
surf1.fill("red")
rect1 = surf1.get_rect()
rect1.topleft = (50, 50)
screen.blit(surf1, rect1)
# stessa cosa con surf2 (blu)
surf2 = pygame.Surface((100, 100))
surf2.fill("blue")
rect2 = surf2.get_rect()
rect2.topleft = rect1.topright
screen.blit(surf2, rect2)
# aggiorniamo lo schermo
pygame.display.flip()
# ciclo principale
done = False
while not done:
for ev in pygame.event.get():
if ev.type == QUIT: # chiusura della finestra
done = True
elif ev.type == MOUSEBUTTONDOWN: # click del mouse
click = ev.pos
if rect1.collidepoint(click):
print("Hai cliccato il rettangolo rosso")
elif rect2.collidepoint(click):
print("Hai cliccato il rettangolo blu")
else:
print ("Hai cliccato fuori dalle superfici")
# fine del ciclo e termine del programma
pygame.quit()
Se avete ripreso il vostro vecchio programma ricordatevi di aggiungere la #2 o Python non riconoscerà i
nomi degli eventi. Fino alla #25 tutto è rimasto invariato: il programma crea due Surface
surf1
e surf2
ed i rispettivi Rect rect1
e rect2
. Vediamo ora il ciclo principale:
in #30 monitoriamo l'evento MOUSEBUTTONDOWN. In #31 ricaviamo le coordinate
del punto in cui è avvenuto il click e le assegnamo alla variabile click
(una tuple di due valori). In
#32 e nelle righe successive usiamo il metodo collidepoint()
(ricordate
questo) per verificare se il punto è all'interno di uno dei due rettangoli e scriviamo
un messaggio nella finestra di IDLE.
if . . . elif . . .
dovrebbe bastarvi una piccola modifica al programma
per riportare le cose a posto.Ecco un altro grazioso effetto grafico nel quale uniamo le nostre conoscenze sulle Surface (blit(), fill()
ecc.) alla
gestione degli eventi. Se ne avete bisogno ripassate la Lezione 4.
import pygame, random
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800, 600))
# creiamo la Surface surf
surf = pygame.Surface((100, 100))
# ciclo principale
done = False
while not done:
for ev in pygame.event.get():
if ev.type == QUIT: # chiusura della finestra
done = True
elif ev.type == MOUSEBUTTONDOWN: # click del mouse
r = random.randrange(256)
g = random.randrange(256)
b = random.randrange(256)
surf.fill((r, g, b))
screen.blit(surf, ev.pos)
pygame.display.flip()
# fine del ciclo e termine del programma
pygame.quit()
Fate partire il programma e provate a cliccare sulla finestra di pygame: ad ogni click verrà disegnato un quadrato di un colore diverso! Vediamo come abbiamo fatto.
Notate che nella riga #1 abbiamo importato anche il modulo random
, nel quale è definita
la funzione randrange()
che serve a creare dei numeri casuali; nella #8 creiamo una Surface
surf
100x100. Vediamo ora il ciclo principale, nel quale, alla riga #16, monitoriamo l'evento
MOUSEBUTTONDOWN: nelle righe dalla #17 alla #19 creiamo tre numeri casuali (da 0
a 255) e li usiamo nella #20 per colorare surf
con il colore indicato dalla tripla
(r, g, b)
. A questo punto, nella #21, disegniamo surf
sulla finestra principale
a partire dalla posizione del cursore (la tuple ev.pos
) e nella successiva aggiorniamo lo schermo con la
flip()
.
Possiamo infine realizzare l'effetto grafico di cui avevamo parlato all'inizio della lezione scorsa: un quadrato che cambia colore quando il mouse vi passa sopra.
surf
, coloratela
di rosso, ricavate da essa il Rect rect
e posizionate la Surface sullo schermo usando il Rect;flip()
;Nei suggerimenti che vi ho dato ho privilegiato la semplicità del programma a scapito dell'efficienza: infatti il programma ricolora il quadrato (di un colore o dell'altro) ogni volta che il mouse si muove, facendo molto lavoro inutile e sprecando potenza di calcolo. Sarebbe molto meglio se esso "ricordasse" di che colore è il quadrato, in modo da non ricolorarlo se è già del colore desiderato. Vi lascio un ultimo esercizio, avvertendovi che esso richiede già una certa abilità nella programmazione.
light
ponendola
uguale a Falselight
è
uguale a False (cioè il quadrato è scuro). In questo caso usate il colore chiaro e ponete light = True
per ricordare che ora il quadrato è chiarolight
è
uguale a True (cioè il quadrato è chiaro): agite in maniera simile al punto precedenteFine della lezione