Listener di eventi

Flash Player 9 e versioni successive, Adobe AIR 1.0 e versioni successive

I listener di eventi, detti anche gestori di eventi, sono funzioni che Flash Player e AIR eseguono in risposta a eventi specifici. L'aggiunta di un listener di eventi è una procedura che si compone di due fasi. Create per prima cosa una funzione o un metodo di classe che Flash Player o AIR devono eseguire in risposta all'evento. Questa funzione viene talvolta definita come funzione listener o funzione gestore di eventi. In secondo luogo, usate il metodo addEventListener() per associare alla funzione listener il destinatario dell'evento o un oggetto dell'elenco di visualizzazione che appartiene al flusso di eventi appropriato.

Creazione di una funzione listener

La creazione di funzioni listener è un ambito in cui il modello eventi di ActionScript 3.0 si discosta dal modello eventi DOM. Nel modello eventi DOM, esiste una distinzione netta tra un listener di eventi e una funzione listener: un listener di eventi è un'istanza di una classe che implementa l'interfaccia EventListener, mentre la funzione listener è un metodo di quella classe definito handleEvent() . Nel modello eventi DOM è necessario registrare l'istanza della classe che contiene la funzione listener e non la funzione listener in sé.

Nel modello eventi di ActionScript 3.0 non esiste una distinzione tra un listener di eventi e una funzione listener. ActionScript 3.0 non dispone dell'interfaccia EventListener e le funzioni listener possono essere definite al di fuori di una classe o come parte di una classe. Inoltre, le funzioni listener non devono necessariamente chiamarsi handleEvent() in quanto possono essere definite tramite un qualsiasi identificatore valido. In ActionScript 3.0, è necessario registrare il nome della funzione listener.

Funzione listener definita al di fuori di una classe

L'esempio di codice seguente crea un file SWF semplice in cui viene visualizzato un quadrato rosso. La funzione listener clickHandler() , che non fa parte di una classe, monitora gli eventi click del mouse sul quadrato rosso.

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, clickHandler); 
    } 
} 
 
function clickHandler(event:MouseEvent):void 
{ 
    trace("clickHandler detected an event of type: " + event.type); 
    trace("the this keyword refers to: " + this); 
}

Quando un utente interagisce con il file SWF facendo clic sul quadrato, Flash Player o AIR generano il seguente output di traccia:

clickHandler detected an event of type: click 
the this keyword refers to: [object global]

Notate che l'oggetto evento viene passato come argomento a clickHandler() . Questo permette alla funzione listener di analizzare l'oggetto evento. In questo esempio, è necessario usare la proprietà type dell'oggetto evento per determinare se l'evento è un clic del mouse.

L'esempio verifica anche il valore della parola chiave this . In questo caso, this rappresenta l'oggetto globale; questo è opportuno perché la funzione è definita al di fuori di qualsiasi classe predefinita o oggetto.

Funzione listener definita come metodo di classe

L'esempio seguente è identico a quello precedente che definisce la classe ClickExample, con la sola eccezione che la funzione clickHandler() è definita come metodo della classe ChildSprite:

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, clickHandler); 
    } 
    private function clickHandler(event:MouseEvent):void 
    { 
        trace("clickHandler detected an event of type: " + event.type); 
        trace("the this keyword refers to: " + this); 
    } 
}

Quando un utente interagisce con il file SWF facendo clic sul quadrato rosso, Flash Player o AIR generano il seguente output di traccia:

clickHandler detected an event of type: click 
the this keyword refers to: [object ChildSprite]

Notate che la parola chiave this si riferisce all'istanza di ChildSprite denominata child . Questo rappresenta un cambiamento rispetto a quanto avviene in ActionScript 2.0. Chi ha dimestichezza con i componenti in ActionScript 2.0 ricorderà che quando un metodo di classe viene passato a UIEventDispatcher.addEventListener() , l'area di validità del metodo è legata al componente che ha trasmesso l'evento anziché alla classe in cui il metodo listener è stato definito. In altre parole, usando questa tecnica in ActionScript 2.0, la parola chiave this farebbe riferimento al componente che trasmette l'evento anziché all'istanza di ChildSprite.

Questo rappresenta un problema notevole per i programmatori perché significa che non possono accedere ad altri metodi e proprietà della classe che contiene il metodo listener. Per aggirare il problema, i programmatori di ActionScript 2.0 potevano usare la classe mx.util.Delegate per cambiare l'area di validità del metodo listener. Questo espediente non è tuttavia più necessario perché ActionScript 3.0 crea un metodo vincolato quando viene chiamato addEventListener() . Di conseguenza, la parola chiave this fa riferimento all'istanza di ChildSprite denominata child e il programmatore ha accesso agli altri metodi e alle proprietà della classe ChildSprite.

Listener di eventi da evitare

Esiste una terza possibilità, sconsigliata, che consiste nel creare un oggetto generico dotato di una proprietà che punta a una funzione listener assegnata in modo dinamico. Questa tecnica viene comunque presentata qui perché era usata comunemente in ActionScript 2.0, ma se ne sconsiglia l'impiego in ActionScript 3.0, in quanto la parola chiave this farebbe riferimento all'oggetto globale e non all'oggetto listener.

L'esempio che segue è identico all'esempio precedente della classe ClickExample, con l'eccezione che qui la funzione listener è definita come parte di un oggetto generico denominato myListenerObj :

package 
{ 
    import flash.display.Sprite; 
 
    public class ClickExample extends Sprite 
    { 
        public function ClickExample() 
        { 
            var child:ChildSprite = new ChildSprite(); 
            addChild(child); 
        } 
    } 
} 
 
import flash.display.Sprite; 
import flash.events.MouseEvent; 
 
class ChildSprite extends Sprite 
{ 
    public function ChildSprite() 
    { 
        graphics.beginFill(0xFF0000); 
        graphics.drawRect(0,0,100,100); 
        graphics.endFill(); 
        addEventListener(MouseEvent.CLICK, myListenerObj.clickHandler); 
    } 
} 
 
var myListenerObj:Object = new Object(); 
myListenerObj.clickHandler = function (event:MouseEvent):void 
{ 
        trace("clickHandler detected an event of type: " + event.type); 
        trace("the this keyword refers to: " + this); 
}

Il risultato dell'output di traccia è il seguente:

clickHandler detected an event of type: click 
the this keyword refers to: [object global]

In questo caso this fa riferimento all'oggetto globale e non a myListenerObj e l'output di traccia non è [object Object] . Quando passate il nome di una proprietà dinamica come argomento a addEventListener() , Flash Player o AIR non è in grado di creare un metodo vincolato perché il parametro passato come listener non è altro che l'indirizzo di memoria della funzione listener e Flash Player e AIR non hanno modo di collegare quell'indirizzo all'istanza di myListenerObj .

Gestione dei listener di eventi

È possibile gestire le funzioni listener usando i metodi dell'interfaccia IEventDispatcher. IEventDispatcher è la versione di ActionScript 3.0 dell'interfaccia EventTarget del modello eventi DOM. Nonostante il nome IEventDispatcher sembri sottintendere che il suo scopo principale sia inviare (in inglese “dispatch”) oggetti evento, in realtà, i metodi di questa classe sono usati in prevalenza per registrare i listener di eventi, verificare la presenza di listener di eventi e rimuovere i listener di eventi. L'interfaccia IEventDispatcher definisce cinque metodi, come illustrato nel codice seguente:

package flash.events 
{ 
    public interface IEventDispatcher 
    { 
        function addEventListener(eventName:String,  
                        listener:Object, 
                        useCapture:Boolean=false, 
                        priority:Integer=0, 
                        useWeakReference:Boolean=false):Boolean; 
 
        function removeEventListener(eventName:String,  
                    listener:Object, 
                    useCapture:Boolean=false):Boolean; 
 
        function dispatchEvent(eventObject:Event):Boolean; 
 
        function hasEventListener(eventName:String):Boolean; 
        function willTrigger(eventName:String):Boolean; 
    } 
}

L'API Flash Player implementa l'interfaccia IEventDispatcher con la classe EventDispatcher, che funge da classe base per tutte le classi suscettibili di essere destinatarie di eventi o parte del flusso di eventi. La classe DisplayObject, ad esempio, eredita dalla classe EventDispatcher. Ciò significa che qualsiasi oggetto dell'elenco di visualizzazione ha accesso ai metodi dell'interfaccia IEventDispatcher.

Aggiunta dei listener di eventi

Il metodo addEventListener() è il pezzo forte dell'interfaccia IEventDispatcher e consente di registrare le funzioni listener. I due parametri obbligatori sono type e listener . Con il parametro type specificate il tipo di evento, mentre con il parametro listener specificate la funzione listener da eseguire quando si verifica l'evento. Il parametro listener può essere un riferimento a una funzione o a un metodo di classe.

non utilizzate le parentesi per specificare il parametro listener . La funzione clickHandler() , ad esempio, è specificata senza parentesi nella seguente chiamata al metodo addEventListener() :
addEventListener(MouseEvent.CLICK, clickHandler)

Il parametro useCapture del metodo addEventListener() consente di controllare la fase del flusso di eventi in cui il listener sarà attivo. Se useCapture è impostato su true , il listener sarà attivo durante la fase di cattura del flusso di eventi. Se useCapture è impostato su false , il listener sarà attivo durante la fase target e di bubbling del flusso di eventi. Per monitorare un evento durante tutte le fasi del flusso di eventi, chiamate addEventListener() due volte, una volta con useCapture impostato su true e una seconda volta con useCapture impostato su false .

Il parametro priority del metodo addEventListener() non è un elemento ufficiale del modello eventi DOM Level 3, però è stato incluso in ActionScript 3.0 per rendere più flessibile l'organizzazione dei listener di eventi. Quando chiamate addEventListener() , potete impostare la priorità per quel listener di eventi passando un valore intero come parametro priority . Il valore predefinito è 0, ma è possibile modificarlo in un valore intero negativo o positivo. Più è alto il numero, prima verrà eseguito il listener di eventi. I listener di eventi con la stessa priorità vengono eseguiti nell'ordine in cui sono stati aggiunti, quindi prima è stato aggiunto un listener, prima viene eseguito.

Il parametro useWeakReference permette di specificare se il riferimento alla funzione listener è debole o normale. Impostando questo parametro su true è possibile evitare situazioni in cui le funzioni listener rimangono in memoria anche quando diventano superflue. Flash Player e AIR usano la tecnica garbage collection per eliminare dalla memoria gli oggetti inutilizzati. Un oggetto viene considerato inutilizzato quando non esistono più riferimenti ad esso. L'operazione di garbage collection non tiene in considerazione i riferimenti deboli, vale a dire che una funzione listener per cui esiste solo un riferimento debole diventa una candidata per la garbage collection.

Eliminazione dei listener di eventi

Per rimuovere i listener di eventi inutilizzati si può usare il metodo removeEventListener() . È buona norma rimuovere i listener diventati superflui. I parametri obbligatori sono eventName e listener , cioè gli stessi parametri del metodo addEventListener() . Ricordate che potete monitorare gli eventi durante tutte le fasi del flusso di eventi chiamando due volte addEventListener() : una con useCapture impostato su true e una seconda con il parametro impostato su false . Per eliminare entrambi i listener di eventi dovete chiamare removeEventListener() due volte: una prima volta con useCapture impostato su true e una seconda volta con il parametro impostato su false .

Invio degli eventi

I programmatori esperti possono usare il metodo dispatchEvent() per inviare un oggetto evento personalizzato nel flusso di eventi. L'unico parametro accettato da questo metodo è un riferimento a un oggetto evento, che deve essere un'istanza o una sottoclasse della classe Event. Una volta inviato l'evento, la proprietà target dell'oggetto evento viene impostata sull'oggetto su cui il metodo dispatchEvent() è stato chiamato.

Verifica della presenza di listener di eventi

Gli ultimi due metodi dell'interfaccia IEventDispatcher forniscono informazioni utili per individuare l'esistenza di listener di eventi. Il metodo hasEventListener() restituisce il valore true se individua un listener di eventi per un tipo di evento specifico su un particolare oggetto dell'elenco di visualizzazione. Anche il metodo willTrigger() restituisce il valore true se individua un listener per un oggetto specifico dell'elenco di visualizzazione, ma willTrigger() verifica la presenza di listener non solo sull'oggetto di visualizzazione in sé ma anche su tutti gli antenati dell'oggetto per tutte le fasi del flusso di eventi.

Eventi errore senza listener

Sono le eccezioni, e non gli eventi, il meccanismo principale per la gestione degli errori in ActionScript 3.0, ma la gestione delle eccezioni non prende in considerazione le operazioni asincrone come il caricamento dei file. Se si verifica un errore durante un'operazione asincrona di questo tipo, Flash Player e AIR inviano un oggetto evento errore. Se non create un listener per gli eventi errore, le versioni debugger di Flash Player e AIR chiamano una finestra di dialogo con alcune informazioni sull'errore. La versione del debugger di Flash Player, ad esempio, quando l'applicazione prova a caricare un file da un URL non valido visualizza le seguenti finestre di dialogo che descrivono l'errore:

La maggior parte degli eventi errore si basa sulla classe ErrorEvent e in quanto tali sono configurati con la proprietà text che viene utilizzata per memorizzare il messaggio di errore visualizzato da Flash Player o AIR. Le uniche due eccezioni sono costituite dalle classi StatusEvent e NetStatusEvent, che sono caratterizzate dalla proprietà level ( StatusEvent.level e NetStatusEvent.info.level ). Quando il valore della proprietà level è " error ", questi tipi di evento vengono considerati eventi errore.

Un evento errore non determina l'arresto della riproduzione di un file SWF e genera solo la visualizzazione di una finestra di dialogo nelle versioni debugger dei plug-in per browser e dei lettori autonomi, di un messaggio nel pannello Output nel player di creazione e l'aggiunta di una riga nel file di registro di Adobe Flash Builder. Non si manifesta affatto nelle versioni standard di Flash Player o AIR.