La gestione degli eventi
Antonio Cisternino
Programmazione ad Eventi
Come abbiamo visto dagli esempi esiste
un pattern comune ai vari sistemi per la
gestione degli eventi
La gestione degli eventi nelle interfacce si
articola in:
Gestione degli eventi all’interno
dell’applicazione
Gestione degli eventi del gestore
dell’interfaccia grafica
Delegate Event Model
Questo modello, inizialmente introdotto da
Java 1.1, è ormai quello più diffuso nei
framework di programmazione di GUI
Il modello prevede:
Una sorgente degli eventi (es. il bottone)
I consumatori degli eventi
Delle interfacce (un modo di comunicazione
concordato tra il produttore e il consumatore)
Schema di funzionamento
Consumatori registrati
Sorgente Eventi
(es. Button)
Listeners
(interfaccia richiesta dalla sorgente)
Il pattern in Java
Il delegate event model può essere
implementato in vari linguaggi
In Java è realizzato utilizzando:
Convenzione sui nomi dei metodi per
registrare consumatori presso la sorgente
(addXXXListener(XXXListener l))
Interfaccia che la sorgente usa per
comunicare l’evento (XXXListener)
Invocazione dell’evento: la sorgente invoca
uno dei metodi dell’interfaccia XXXListener
Chi fa cosa
Produttore di eventi:
addXXXListener
removeXXXListener
Definisce una classe XXXEvent
Definisce l’interfaccia XXXListener
Consumatore di eventi
Implementa l’interfaccia XXXListener
Si registra presso il produttore
Il punto di vista dei controlli
Il delegate event model, ideale per chi usa
controlli, presenta problemi nella gestione
degli eventi dei controlli
Come si fa a rendere “trasparente”un
controllo ad un evento?
Ad esempio: il click su una label potrebbe
convenire che sia notificato alla finestra
che lo contiene
Propagazione degli eventi
Il bubbling di un evento si
ha quando viene passato
al contenitore di chi lo ha
ricevuto
In questo modo si
possono implementare i
comportamenti di default
Si possono anche gestire
in modo centralizzato
eventi di un controllo
composto da finestre
Tunneling
Framework come WPF (aka Avalon) supportano
anche il flusso in direzione inversa al bubbling
degli eventi: il tunneling
Questo flusso (solitamente seguito dal bubbling)
offre la possibilità al contenitore di un controllo
di gestire un evento prima che arrivi al figlio
Il gestore dell’interfaccia decide, per ogni tipo
evento, se è diretto, se fa uso di bubbling, o
tunneling e bubbling
Implementiamo il bubbling
Nei linguaggi orientati ad oggetti il bubbling
viene facilmente scaricato sulla gerarchia
dell’ereditarietà
Nei framework OO normalmente tutti I
componenti grafici ereditano da una classe base,
ad esempio Component
Dalla classe base tutti i componenti ereditano
(direttamente o meno) un metodo deputato alla
gestione degli eventi
Il componente vede passare tutti gli eventi a lui
diretti, e può gestirli localmente o delegare
Un esempio
Java, nella sua prima versione (fino alla versione
1.0.2) aveva un modello di gestione degli eventi
come OWL (Borland) e MFC (Microsoft) basato
su bubbling
La possibilità di invocare il metodo della
superclasse consente di delegare la gestione di
un evento non gestito (o solo parzialmente
gestito)
Il dispatch e la classificazione degli eventi viene
tipicamente incapsulato da metodi invocati dal
metodo che gestisce gli eventi, inclusa la delega
Java AWT Event Model
class Component {
int x, y;
bool handleEvent(Event e);
}
class Button extends Component {
String text;
bool handleEvent() { }
…
}
class Window extends Component
class Frame extends Window
Event handling
class MyButton extends Button {
boolean handleEvent(Event e) {
switch (e.type) {
case Event.MOUSE_UP: …
return true; // Event handled!
}
default:
return super.handleEvent(e);
}}
Dal bubbling alla delegation
I controlli, nella gestione degli eventi,
possono implementare l’interfaccia
necessaria per essere una sorgente di
eventi
Per fare questo si possono intercettare gli
eventi, ed invocare il metodo dei
consumatori registrati
La delegation migliora le performance: la
gestione degli eventi non necessita
l’introduzione di nuove classi
L’event loop
Chi invoca gli event handler?
Un thread dell’applicazione spende una
porzione significativa del suo tempo
nell’event loop
L’event loop ha la seguente struttura:
while (m=PickMessage())
DispatchMessage(m)
Un qualche metodo (più o meno nascosto)
esegue questo ciclo
L’event loop
Normalmente l’event-loop viene incapsulato in
qualche classe (Application.Run per .NET,
SwingUtilities.invokeLater in Java)
La funzione di dispatch del messaggio si occupa
di inoltrare il messaggio al componente
dell’applicazione interessato
Questo innesca il meccanismo di chiamate che
poi va a chiamare gli event handler definiti
dall’applicazione
Thread or threads?
Quanti thread gestiscono l’event loop?
A dispetto dell’apparente concorrenza degli
eventi il thread della UI è uno
Se un event handler lo blocca l’intera interfaccia
dell’applicazione smette di funzionare
Se quindi è necessario intraprendere un qualche
lavoro significativo è bene avviare un thread
nell’event handler a cui delegare il compito
Troviamo il colpevole
Come fa il gestore dell’interfaccia a individuare il
destinatario di un evento?
Input da tastiera: il controllo che ha il focus
riceve il messaggio
Spesso il focus si ottiene evidenziando il controllo
Usando il tab è possibile spostare il focus su altri
controlli
La pick correlation consiste nell’associare un
evento del puntatore con il controllo a cui è
diretto
Pick Correlation
Come facciamo a sapere quale controllo deve
ricevere gli eventi del puntatore?
Abbiamo a disposizione le coordinate del punto
(x, y), ma non sono sufficienti!
Siamo tutti abituati a sovrapporre finestre:
qual’è quella visibile?
Il gestore dell’interfaccia organizza in modo
appropriato le finestre e per ciascuna ricorda lo
z-index ovvero un indice che indica
l’ordinamento lungo l’asse Z
Finestre e Z-Ordering
La struttura dati primitiva delle interfacce
grafiche (fino ad oggi…) è la finestra: un’area
rettangolare dello schermo
Tutti i controlli non sono altro che finestre
specializzate
Per trovare a quale finestra corrisponde un
punto (x, y) sullo schermo è necessario
trovare tutte le finestre che lo contengono
tra queste prendere quella con z-index più alto
Le finestre sono organizzate in un albero che
consenta l’implementazione della ricerca in
modo più efficiente (sfruttando il contenimento)
Usare Spy++
Spy++ è un tool
Microsoft (ne esistono
analoghi per XWindows) che
consente di
monitorare gli eventi
diretti a finestre
È anche possibile
analizzare la struttura
di un’applicazione in
termini di finestre
Osserviamo gli eventi
Se abilitiamo il log degli eventi su un
bottone della calcolatrice notiamo che:
Gli eventi di paint arrivano in momenti inattesi
Ci sono molti tipi di eventi
Se invece facciamo il log della finestra
vediamo in azione il bubbling: alcuni
eventi sui figli sono inviati anche al padre