Systém událostí
Obsah
Asynchronní událost
Událost, kterou spouští nezávislý vliv - například kliknutí, vypršení timeru nebo odpověď serveru. Po spuštění běží paralelně ke zbytku programu.
Event Framework AS2 popisuje stručně stránka Úvod do ActionScriptu a podrobněji Asynchronní události.
Tok události

V AS2 byla událost zachycena vždy nejbližším objektem s definovaným event-handlerem. Definovat kliknutí pro celý MovieClip tak znamenalo zablokování přístupu k tlačítkům v něm obsaženým.
AS3 zavádí event-flow
Událost protéká od místa svého vzniku směrem k cílovému objektu a po jeho dosažení se vrací zpět.
Obrázek vpravo ukazuje fáze toku při kliknutí na tlačítko uvnitř dvou úrovní MovieClipů.
Při kliknutí na tlačítko je jako cíl určen objekt pod kurzorem myši s největší hloubkou, tedy objekt Button. Události myši vysílá samotné jádro Flashe, počáteční pozicí toku je tedy samotná scéna. V první fázi událost klesá dovnitř objektové hierarchie k cíli. Cestou ji může zaznamenat listener na libovolné úrovni. Po dosažení cíle se pak stejným způsobem vrací zpět k povrchu.
Připojení listeneru k objektu
V AS3 je jeden jediný způsob připojení listeneru k objektu. Pomocí metody addEventListener.
objekt.addEventListener(MouseEvent.CLICK, clickListener); function clickListener(event:MouseEvent):void { trace('klik'); }
Vidíte, že metoda addEventListener má definovány dva argumenty, celkem jich může mít definováno pět, jak ukazuje následující tabulka.
type:String | Typ události. Přestože je možné použít běžný řetězec, například "click", používají se raději konstanty s touto hodnotou (MouseEvent.CLICK), jejich existenci totiž může kompliler zkontrolovat a hned upozornit na případný překlep. Také je hned vidět, jaký typ události bude listener očekávat. |
|---|---|
listener:Function | Metoda, která slouží jako listener. |
useCapture:Boolean | Určuje, zda se má zachytit událost už v první, capturing, fázi toku události. Implicitně vypnuto. |
priority:int | Priorita. Pokud má objekt více stejných listenerů, pomocí priority je možné určit jejich pořadí. |
useWeakReference:Boolean | Použít slabou vazbu objektu s listenerem. Implicitně vypnuto. Pokud volbu povolíte, nebude vytvořena vazba na listener a garbage-collector jej bude moci odstranit. Pokud byste takto použili lokální (vnitřní) funkci bez dalších vazeb, bude odstraněna ještě před vznikem události a tedy nebude fungovat. |
Objekt Event
Argument listeneru je vždy objekt typu flash.events.Event, nebo jeho odvozenina. Uvnitř tohoto objektu se nachází některé důležité vlastnosti.
Obecné vlastnosti objektu Event
type:String | Typ události |
|---|---|
bubbles:Boolean | Označuje, jestli událost má třetí fázi toku (bubbling). Většina ji má, některé ovšem ne, například Event.ACTIVATE. |
eventPhase:uint | Aktuální fáze toku události. Nabývá hodnot 1, 2 a 3. Tyto hodnoty jsou také uloženy v konstantách objektu flash.events.EventPhase. |
target:Object | Cílový objekt události |
currentTarget:Object | Nadřazený objekt cíle, který je schopen zpracovat událost připojeným listenerem. U složitějších celků, jako jsou komponenty, je cílem události interní objekt, ale listenery připojuje až některý z jeho rodičů. Například při kliknutí na tlačítko bude target události nejhlubší objekt pod kurzorem - například popisek nebo ikonka tlačítka, což je vcelku nepotřebná reference. Pak je třeba referenci hledat ve vlastnosti currentTarget. |
cancelable:Boolean | Flash má velké množství předdefinovaných akcí pro určité události. Vlastnost cancelable značí, že událost má u daného cíle definovány nějaké vnitřní akce, které mohou být potlačeny metodou preventDefault(). Ukážeme si dále. |
function clickListener(event:MouseEvent):void { var target:Button = event.currentTarget as Button; target.enabled = false; }
Toto jsou základní vlastnosti. Odvozené objekty pak doplňují velké množství dalších - souvisejících s daným typem události. Například MouseEvent obsahuje vlastnosti pro zjištění pozice myši, informace o stisknutých klávesách a tak dále.
Zastavení toku události
Někdy je třeba ukončit tok události a zabránit tak v aktivaci dalších listenerů po jeho cestě. Lze to provést ve kterékoliv fázi metodou stopPropagation respektive
stopImmediatePropagation.
function clickListener(event:MouseEvent):void { event.stopImmediatePropagation(); // okamžitě ukončí tok události }
stopPropagation je jemnější varianta, která dovolí události aktivovat ještě listenery aktuálního objektu, než ukončí tok.
Odpojení listeneru
Odpojení listeneru probíhá obdobně jako jeho připojení.
objekt.removeEventListener(MouseEvent.CLICK, clickListener);
Aby byl listener nalezen a odstraněn, je třeba dodržet shodnost všech parametrů.
Zrušení předdefinovaných akcí
Některé objekty mají implicitně definovány akce pro určité události. Vlastnost cancelable pak značí, že tyto akce můžou být potlačeny.
textfield.addEventListener(TextEvent.TEXT_INPUT, textfieldListener); function textfieldListener(event:TextEvent):void { if(event.cancelable){ event.preventDefault(); } }
Zde například potlačujeme předdefinovanou událost vkládání textu do textového pole. Při psaní tak textové pole nebude reagovat.
Ověření existence listeneru
Pro ověření existence listeneru se používají dvě metody: hasEventListener a willTrigger.
objekt.hasEventListener(MouseEvent.CLICK); // true
Zatímco hasEventListener kontroluje existenci listeneru dané události připojeného přímo k danému objektu, willTrigger ověřuje, jestli nedojde k aktivaci listeneru i u některého z hlubších potomků objektu.
Vlastní Event-dispatcher
Také vlastní třídy mohou používat události pro své interní potřeby. Aby mohla třída vysílat a spravovat události, musí rozšiřovat třídu flash.events.EventDispatcher.
Třída pak získá metody pro práci s událostmi, především pak dispatchEvent pro jejich vyslání a addEventListener pro připojení listeneru.
package { import flash.events.EventDispatcher; import flash.events.Event; public class storage extends EventDispatcher { public static const STORAGE_FULL:String = 'storage_full'; private var data:Array = []; public function addItem(item:*):void { data.push(item); if(this.data.length >= 5){ dispatchEvent(new Event(STORAGE_FULL)); } } } }
Všimněte si, že pro název události definujeme veřejnou statickou konstantu STORAGE_FULL. Je to stejný doporučený postup použití názvu, jako u předdefinovaných událostí.
var buffer:storage = new storage(); buffer.addEventListener(storage.STORAGE_FULL, function(e:Event):void { trace('buffer je plný'); }); buffer.addItem('a'); buffer.addItem('b'); buffer.addItem('c'); buffer.addItem(16); buffer.addItem('x'); // buffer je plný
Rozhraní IEventDispatcher pro upravený Event-dispatcher
Metody EventDispatcheru je někdy třeba upravit podle svých potřeb. Často se tak doplňují funkce pro lepší registraci událostí a jejich snazší hromadnou správu.
V takovém případě se třída nerozšiřuje, ale ručně se implementuje rozhraní IEventDispatcher.
package { import flash.events.IEventDispatcher; import flash.events.EventDispatcher; import flash.events.Event; class myDispatcher implements IEventDispatcher { private var dispatcher:EventDispatcher; public function myDispatcher() { dispatcher = new EventDispatcher(this); } public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void{ dispatcher.addEventListener(type, listener, useCapture, priority); } public function dispatchEvent(evt:Event):Boolean{ return dispatcher.dispatchEvent(evt); } public function hasEventListener(type:String):Boolean{ return dispatcher.hasEventListener(type); } public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void{ dispatcher.removeEventListener(type, listener, useCapture); } public function willTrigger(type:String):Boolean { return dispatcher.willTrigger(type); } }}
Vidíte, že zde definujeme všech pět metod sami. Třídu EventDispatcher používáme už jen jako instanci, jejíž metody zajistí základní funkčnost našeho dispatcheru. Použití rozhraní není nezbytné, ale zajistí kontrolu správné implementace metod.