Detektory zdarzeń

Flash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje

Detektory zdarzeń, które nazywane są również modułami obsługi zdarzeń, to funkcje wykonywane przez programy Flash Player i AIR w odpowiedzi na określone zdarzenia. Dodawanie detektora zdarzeń jest procesem dwuetapowym. Najpierw należy utworzyć funkcję lub metodę klasy (dla programu Flash Player albo AIR), która zostanie wywołana w odpowiedzi na zdarzenie. Ta funkcja jest czasami nazywana funkcją detektora lub funkcją modułu obsługi zdarzeń. Następnie należy użyć metody addEventListener() w celu zarejestrowania funkcji detektora w celu zdarzenia lub w dowolnym obiekcie listy wyświetlania, który znajduje się w odpowiednim strumieniu zdarzenia.

Tworzenie funkcji detektora

Tworzenie funkcji detektora to jedyny aspekt, który odróżnia model zdarzeń języka ActionScript 3.0 od modelu zdarzeń DOM. Model zdarzeń DOM wyraźnie odróżnia detektor zdarzeń od funkcji detektora: detektor jest instancją klasy, która implementuje interfejs EventListener, a funkcja detektora jest metodą tej klasy, o nazwie handleEvent() . W modelu zdarzeń DOM należy zarejestrować instancję klasy, która będzie zawierała funkcję detektora zamiast rzeczywistego detektora.

W języku ActionScript 3.0 detektor zdarzenia nie jest odróżniany od funkcji detektora. Język ActionScript 3.0 nie udostępnia interfejsu EventListener, a funkcje detektora mogą być definiowane poza klasą lub jako część klasy. Ponadto funkcje detektora nie muszą mieć nazwy handleEvent() — nazwą może być dowolny poprawny identyfikator. W języku ActionScript 3.0 rejestrowana jest nazwa rzeczywistej funkcji detektora.

Funkcja detektora zdefiniowana poza klasą

Poniższy kod tworzy prosty plik SWF, który powoduje wyświetlenie czerwonego kwadratu. Funkcja detektora o nazwie clickHandler() , która nie jest częścią klasy, wykrywa kliknięcia czerwonego kwadratu.

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); 
}

Gdy użytkownik oddziałuje na wynikowy plik SWF, klikając kwadrat, program Flash Player lub AIR generuje następujący wynik śledzenia:

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

Należy zauważyć, że obiekt zdarzenia został wprowadzony jako argument do clickHandler() . Dzięki temu funkcja detektora może sprawdzić obiekt zdarzenia. W tym przykładzie właściwość type obiektu zdarzenia służy do sprawdzenia, czy zdarzenie jest kliknięciem.

W przykładzie sprawdzana jest także wartość słowa kluczowego this . W tym przypadku this reprezentuje globalny obiekt, co ma sens, ponieważ funkcja jest zdefiniowana poza wszystkimi niestandardowymi klasami i obiektami.

Funkcja detektora zdefiniowana jako metoda klasy

Poniższy przykład jest taki sam, jak poprzedni, który definiował klasę ClickExample, ale różni się tym, że funkcja clickHandler() jest zdefiniowana jako metoda klasy 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); 
    } 
}

Gdy użytkownik oddziałuje na wynikowy plik SWF, klikając czerwony kwadrat, program Flash Player lub AIR generuje następujący wynik śledzenia:

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

Należy zauważyć, że słowo kluczowe this odwołuje się do instancji ChildSprite o nazwie child . Jest to zmiana w porównaniu z wersją ActionScript 2.0. Użytkownicy, którzy korzystali ze składników w wersji ActionScript 2.0, mogą pamiętać, że wprowadzenie metody klasy do UIEventDispatcher.addEventListener() powodowało ograniczenie zakresu metody do składnika, który rozgłaszał zdarzenie, a nie do klasy, w której zdefiniowano metodę detektora. Innymi słowy: jeśli ta technika była używana w wersji ActionScript 2.0, słowo kluczowe this odwoływało się do składnika rozgłaszającego zdarzenie, a nie do instancji ChildSprite.

Dla niektórych programistów takie rozwiązanie stanowiło problem, ponieważ oznaczało to, że nie mogli uzyskać dostępu do innych metod i właściwości klasy zawierającej metodę detektora. W celu obejścia tego problemu programiści korzystający z ActionScript 2.0 mogli użyć klasy mx.util.Delegate w celu zmiany zakresu metody detektora. Nie jest to już konieczne, ponieważ język ActionScript 3.0 tworzy metodę ograniczenia po wywołaniu metody addEventListener() . W rezultacie słowo kluczowe this odwołuje się do instancji ChildSprite o nazwie child , a programista ma dostęp do innych metod i właściwości klasy ChildSprite.

Detektor zdarzeń, który nie powinien być używany

Istnieje również trzecia technika, która służy do tworzenia obiektu ogólnego zawierającego właściwość, która wskazuje na dynamicznie przypisywaną funkcję detektora, ale jej używanie nie jest zalecane. Ta technika została omówiona w niniejszej sekcji, ponieważ była często stosowana w języku ActionScript 2.0 — w języku ActionScript 3.0 nie powinna być używana. Ta technika nie jest zalecana, ponieważ słowo kluczowe this będzie odwoływało się do obiektu globalnego zamiast do obiektu detektora.

Poniższy przykład jest taki sam, jak poprzedni przykład klasy ClickExample, ale różni się tym, że funkcja detektora jest zdefiniowana jako część obiektu ogólnego o nazwie 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); 
}

Wyniki będą następujące:

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

Można by oczekiwać, że słowo kluczowe this będzie odwoływało się do myListenerObj oraz że wynikiem będzie [object Object] , ale słowo kluczowe odwołuje się do obiektu globalnego. Gdy nazwa właściwości dynamicznej zostanie wprowadzona jako argument metody addEventListener() , program Flash Player lub AIR nie może utworzyć metody ograniczenia. Dzieje się tak dlatego, że element wprowadzany jako parametr listener jest tylko adresem funkcji detektora w pamięci, a program Flash Player i AIR nie może powiązać tego adresu z instancją myListenerObj .

Zarządzanie detektorami zdarzeń

Do zarządzania funkcjami detektora służą metody interfejsu IEventDispatcher. Interfejs IEventDispatcher jest wersją interfejsu EventTarget modelu zdarzeń DOM, jaka jest dostępna w języku ActionScript 3.0. Nazwa IEventDispatcher może wskazywać na to, że głównym celem jest wysyłanie (lub wywoływanie) obiektów zdarzeń, jednak metody tej klasy są używane znacznie częściej w celu rejestrowania detektorów zdarzeń, sprawdzania dostępności detektorów zdarzeń oraz usuwania detektorów zdarzeń. Interfejs IEventDispatcher definiuje pięć metod, co przedstawia poniższy kod:

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; 
    } 
}

API programu Flash Player API implementuje interfejs IEventDispatcher z klasą EventDispatcher, która służy jako klasa podstawowa dla wszystkich klas, które mogą być celami zdarzeń lub mogą stanowić część strumienia zdarzenia. Przykład: klasa DisplayObject dziedziczy od klasy EventDispatcher. Oznacza to, że każdy obiekt na liście wyświetlania ma dostęp do metod interfejsu IEventDispatcher.

Dodawanie detektorów zdarzeń

Metoda addEventListener() jest najważniejszą metodą roboczą interfejsu IEventDispatcher. Służy do rejestrowania funkcji detektorów. Ma dwa wymagane parametry: type i listener . Parametr type służy do określania typu detektora. Parametr listener służy do wybierania funkcji detektora, która będzie wywoływana, gdy wystąpi zdarzenie. Parametr listener może odwoływać się do funkcji lub metody klasy.

Do określania parametru listener nie należy używać nawiasów. Na przykład: funkcja clickHandler() jest określona bez nawiasów w poniższym wywołaniu metody addEventListener() :
addEventListener(MouseEvent.CLICK, clickHandler)

Parametr useCapture metody addEventListener() umożliwia kontrolowanie fazy strumienia zdarzenia, w której detektor będzie aktywny. Jeśli dla metody useCapture zostanie ustawiona wartość true , detektor będzie aktywny w fazie przechwytywania strumienia zdarzenia. Jeśli dla metody useCapture zostanie ustawiona wartość false , detektor będzie aktywny podczas fazy docelowej i fazy propagacji strumienia zdarzenia. Aby wykrywać zdarzenie podczas wszystkich faz strumienia zdarzenia, należy dwukrotnie wywołać metodę addEventListener() — jeden raz, ustawiając dla metody useCapture wartość true , i drugi raz, ustawiając dla metody useCapture wartość false .

Parametr priority metody addEventListener() nie jest oficjalną częścią modelu zdarzenia DOM Level 3. Jest to część języka ActionScript 3.0 i zapewnia większą elastyczność w organizowaniu detektorów zdarzeń. Po wywołaniu metody addEventListener() można ustawić priorytet dla detektora zdarzenia — w tym celu jako parametr priority należy wprowadzić wartość całkowitą. Wartością domyślną jest 0, ale można ustawić ujemną lub dodatnią wartość całkowitą. Im wyższa jest wartość, tym szybciej detektor zdarzenia zostanie uruchomiony. Detektory zdarzeń o tym samym priorytecie są uruchamiane w kolejności, w jakiej są dodawane, więc im wcześniej detektor zostanie dodany, tym szybciej zostanie uruchomiony.

Parametr useWeakReference umożliwia określanie, czy odwołanie do funkcji detektora jest słabe czy normalne. Ustawienie dla parametru wartości true umożliwia uniknięcie sytuacji, w których funkcje detektora są przechowywane w pamięci, nawet gdy nie są już potrzebne. W programach Flash Player i AIR wykorzystywana jest technika o nazwie czyszczenie pamięci , która umożliwia usuwanie z pamięci obiektów nieużywanych. Obiekt jest traktowany jako nieużywany, jeśli nie istnieją żadne odwołania do tego obiektu. Moduł czyszczenia pamięci pomija słabe odwołania, co oznacza, że funkcja detektora, do której istnieje wyłącznie słabe odwołanie, jest odpowiednia do wyczyszczenia.

Usuwanie detektorów zdarzeń

Do usuwania zbędnych detektorów zdarzeń służy metoda removeEventListener() . Usuwanie detektorów, które nie będą używane, jest bardzo dobrym sposobem postępowania. Do wymaganych parametrów należą eventName i listener i są to te same parametry, jak parametry wymagane dla metody addEventListener() . Czytelnik z pewnością pamięta, że wykrywanie zdarzeń jest możliwe podczas wszystkich faz zdarzeń — w tym celu należy wywołać metodę addEventListener() dwukrotnie: raz, ustawiając dla useCapture wartość true , a następnie ponownie, ustawiając wartość false . W celu usunięcia obydwu detektorów zdarzeń należy wywołać metodę removeEventListener() dwukrotnie: raz, ustawiając dla useCapture wartość true , a następnie ponownie, ustawiając wartość false .

Wywoływanie zdarzeń

Metoda dispatchEvent() może być używana przez zaawansowanych programistów w celu wysyłania niestandardowych obiektów zdarzeń do strumienia zdarzeń. Jedynym parametrem akceptowanym przez tę metodę jest odwołanie do obiektu zdarzenia, które może być instancją klasy Event lub podklasą klasy Event. Po wywołaniu właściwość target obiektu zdarzenia jest ustawiana dla obiektu, dla którego wywołano metodę dispatchEvent() .

Sprawdzanie dostępności detektorów zdarzeń

Ostatnie dwie metody interfejsu IEventDispatcher udostępniają użyteczne informacje o istnieniu detektorów zdarzeń. Metoda hasEventListener() zwraca wartość true , jeśli istnieje detektor zdarzeń dla danego typu zdarzeń w konkretnym obiekcie listy wyświetlania. Metoda willTrigger() zwraca również wartość true , gdy detektor zdarzeń zostanie znaleziony dla konkretnego obiektu listy wyświetlania, ale metoda willTrigger() sprawdza dostępność detektorów nie tylko w obiekcie wyświetlanym, ale również we wszystkich przodkach obiektu listy wyświetlania, we wszystkich fazach strumienia zdarzenia.

Zdarzenia błędów bez detektorów

Głównym mechanizmem obsługi błędów w języku ActionScript 3.0 są wyjątki, a nie zdarzenia, ale obsługa wyjątków nie działa dla operacji asynchronicznych, takich jak ładowanie plików. Jeśli wystąpi błąd, taki jak operacja asynchroniczna, program Flash Player i AIR generuje obiekt zdarzenia błędu. Jeśli nie zostanie utworzony detektor dla zdarzenia błędu, w wersjach programów Flash Player i AIR, które obsługują debugowanie, zostaną wyświetlone okna dialogowe z informacjami o błędzie. Na przykład: w wersji programu Flash Player obsługującej debugowanie wyświetlane jest następujące okno dialogowe z opisem błędu, gdy w aplikacji wykonywana jest próba załadowania pliku z nieprawidłowego adresu URL:

Większość zdarzeń błędów jest oparta na klasie ErrorEvent i dlatego ma właściwość o nazwie text , która służy do zapisu komunikatu o błędzie, jaki jest wyświetlany w programie Flash Player lub AIR. Dwoma wyjątkami są klasy StatusEvent i NetStatusEvent. Obydwie te klasy mają właściwość level ( StatusEvent.level i NetStatusEvent.info.level ). Gdy wartość właściwości level jest równa " error ", te typy zdarzeń są traktowane jako zdarzenia błędów.

Zdarzenie błędu nie spowoduje zatrzymania działania pliku SWF. Użytkownik zostanie powiadomiony o błędzie tylko przez okno dialogowe w wersjach wtyczek przeglądarki, które obsługują debugowanie, jako komunikat w panelu Wyjście w odtwarzaczu do tworzenia oraz jako wpis w pliku dziennika Adobe Flash Builder. W wydanych wersjach programu Flash Player i AIR błąd nie będzie się objawiał.