. .. : Swf.hu 1.0 archívum : Swf.hu főoldal >>> : .. .


 
 
SEGÉDLETEK Effektus-trükk

Részecskerendszer (particle-system) segédlet
  feltöltve: 2003.12.10 | szerző: Newone | olvasva: 14429 alkalommal

           
 

Eseményalapú vezérlés az ActionScript-ben?

Ha valaki feltenné a kérdést, hogy milyen ActionScript parancsok támogatják az eseményvezérlést, akkor azt kellene válaszolnom: nem dokumentált parancsok.

A fenti mondattal előre szaladtam, mert ez így nem teljesen igaz. A Flash 6 új eseményalapú modelljében már a MovieClip-ek és Button-ok onEnterFrame, onPress, onData, stb.: eseménykezelői már ezt az elvet követik. Azaz közvetlenül az adott MC vagy Button-hoz tudod rendelni az eseményt és az esemény bekövetkezte szerint eljárni.

Ám szemléletesebb, ha a TextField osztály onChanged eseménykezelőjét nézzük. Amennyiben az adott TextField-hez az addListener() használatával Figyelőt rendelsz (feliratod a listára), akkor a TextField módosításakor (pl.: egy látogató beír valamit a szövegmezőbe, akkor az adott szövegmező (TextField) üzenetet küld a listáján szereplő Figyelőknek, hogy változás történt, valaki beírt valamit!

Az igazán nagy kérdés, az, hogy, hogyan lehetséges új, nem standard eseménykezelőket definiálni egy objektumhoz, akár olyanhoz is, amelynek semmilyen, még előre definiált eseménykezelője sincs?

Nos, itt már valóban a nem dokumentált ActionScript parancsoknál kell keresgélnünk. Nézzük meg ezt közelebbről.

Saját eseménykezelők definiálása

Vegyünk egy olyan objektumot, amelynek van már saját eseménykezelője és vegyünk egy olyat, amelynek nincs.

Az egyik legyen a már felhozott TextField, míg a másik legyen egy új, sima Object típusú Object.

Hozzuk létre:

var SzovegMezo:TextField = new TextField();
var valamiObjektum:Object = new Object();

(A segédletben mindenhol az AS2 által megkövetelt ún. erős típusos változó deklarációt fogom használni. Ennek lényege, hogy mindig meg kell adni, hogy az adott változó milyen típusú értéket vehet fel. A Flash-ben eddig nem kellett erre ügyelni, az AS2 szerint már igen. Bár csak az osztályok deklarációjánál veszi komolyan. A pontosabb magyarázatra jelen segédlet nem tér ki.)

Létezik egy szintén nem dokumentált metódus, amely segítségével megnézhetjük egy Object rejtett metódusait, tulajdonságait. Ennek segítségével megnézzük, hogy mi a különbség a két Object között.

Elsőnek fussunk neki a TextField típusú SzovegMezo-nek:

ASSetPropFlags(SzovegMezo, null, 8, 1); // ez az a bizonyos nem dokumentált funkció, amellyel megjeleníthetjük a rejtett tulajdonságokat, metódusokat is.
trace("****** SzovegMezo Object tulajdonságai, metódusai *******");
for ( SZMtest in SzovegMezo ){
// for.in ciklus segítségével végigmegyünk az adott Object-en
     trace(SZMtest);
// kiírjuk az object tulajdonságait, metódusait
};
trace("**********************************************************");


A futtatás eredménye:

****** SzovegMezo Object tulajdonságai, metódusai *******

styleSheet
mouseWheelEnabled
condenseWhite
restrict
textHeight
textWidth
bottomScroll
length
selectable
multiline
password
wordWrap
background
border
html
embedFonts
maxChars
maxhscroll
hscroll
variable
htmlText
type
text
autoSize
tabIndex
textColor
backgroundColor
borderColor
maxscroll
scroll
_listeners
__constructor__
__proto__

**********************************************************

Most nézzük meg ugyan ezt a valamiObjektum-on:

ASSetPropFlags(valamiObjektum, null, 8, 1);
trace("****** valamiObjektum Object tulajdonságai, metódusai *******");
for ( VOtest in valamiObjektum ){
     trace(VOtest);
};
trace("**********************************************************");


A futtatás eredménye:

****** valamiObjektum Object tulajdonságai, metódusai *******

__constructor__
__proto__

**********************************************************

Most vegyük le a SzovegMezo eredményéből azokat a tulajdonságokat, illetve metódusokat amelyeket ismerünk (dokumentálva vannak az ActionScript Dictionary-ban).

Az eredmény így néz ki:

****** SzovegMezo Object tulajdonságai, metódusai *******

_listeners
__constructor__
__proto__

**********************************************************

Látható, hogy a két Object típus között egy apró, de lényegi különbség van: _listeners.
(A másik kettő szintén érdekes, de most nem foglalkozunk velük.)

Nézzük meg, hogy ez a _listeners tulajdonság micsoda. A micsoda alatt azt értem, hogy milyen a típusa? Ez egy függvény, egy object?

A kérdések további gyűjtése helyett rövidre zárom a kört.

A _listeners tulajdonság egy tömb, amely az Üzenő tömbje, azaz listája, ahová a Figyelők feliratkozhatnak.

Valósítsuk meg a példát. Legyen a SzovegMezo egy valóságos beviteli mező. Ő lesz az Üzenő. Az Üzenőnek az onChanged eseménykezelőjét fogjuk használni. Azaz beírunk egy szöveget, vagyis megváltoztatjuk a SzovegMezo tartalmát, amely kiváltja az onChanged eseményt, amely kezelője üzen az összes Figyelőnek, hogy változás történt. Lesz három Figyelő!

Textfield.fla

Töltsük be a letölthető forrsáfile-ok közül a /helperFlas/textfield.fla-t.

Látható, hogy a színpadon elhelyeztem a SzovegMezo TextFieldet, majd alatta három Figyelőt, instance nevük rendre FigyeloTXT_1, FigyeloTXT_2 és FigyeloTXT_3.

A Control layer-en található kód a következő:

FigyeloTXT_1.onChanged = function(){
     _root.FigyeloTXT_1.text = _root.SzovegMezo.text;
};

FigyeloTXT_2.onChanged = function(){
     _root.FigyeloTXT_2.text = _root.SzovegMezo.text;
};

FigyeloTXT_3.onChanged = function(){
     _root.FigyeloTXT_3.text = _root.SzovegMezo.text;
};
//
this.SzovegMezo.addListener(FigyeloTXT_1);
this.SzovegMezo.addListener(FigyeloTXT_2);
this.SzovegMezo.addListener(FigyeloTXT_3);
//
stop();


Amikor egy Üzenőben bekövetkezik egy esemény, amely az eseménykezelőt beindítja (azaz megüzeni az eseményt a Figyelőknek), akkor gyakorlatilag az eseménykezelő nevét küldi el, üzeni meg a Figyelőknek. Innentől kezdve az a dolgunk, hogy az adott eseménykezelő érkezésére felkészítsük az adott Figyelőt.

Példánkban a SzovegMezo Object, mivel TextField típus, rendelkezik az onChanged eseménykezelővel, amely akkor kell életre (szépen mondva üzenődik meg a Figyelőknek), ha az adott TextFiled megváltozik.

Következő lépés, hogy a Figyelőket felkészítsük az eseményüzenetre. Ezt úgy érjük el, hogy az adott figyelőnél definiálunk egy, az eseménykezelő nevét viselő függvényt. Jelen esetben onChanged-et.

FigyeloTXT_1.onChanged = function(){
     _root.FigyeloTXT_1.text = _root.SzovegMezo.text;
};


Amikor a SzovegMezo kihírdeti az onChanged eseményt, akkor a Figyelőnk azt elkapja és végrehajtja a definiált függvényt.

Következő és egyben utolsó lépés, hogy a Figyelőket felíratjuk az Üzenő listájára:

this.SzovegMezo.addListener(FigyeloTXT_1);

Ezzel meg is volnánk. Próbáljuk ki! Amint beírtunk egy karaktert a SzovegMezobe, az azonnal megjelenik mind a három Figyelőben. Voálá! Nem kellett hozzá semmilyen ciklus!

Most már mindent tudunk az eseményalapúságról, kivéve azt, hogy hogyan definiálunk saját eseményeket, eseménykezelőket.

Az AsBroadcaster

Végre elérkeztünk a sokat emlegetett, de még meg nem nevezett, nem dokumentált ActionScript funkcióhoz, amely segít nekünk rábírni az objektumainkat, hogy váljanak Üzenőkké! Ez a funkció az AsBroadcaster. Pontosabban ez egy globális object, egy statikus osztály, de erről később!
Amikor objektumok között üzeneteket váltunk azt angolul broadcasting-nak is hívhatjuk. Az AsBroadcaster azt műveli az objektumunkkal, hogy felvértezi az üzenés képességével.

Vegyük górcső alá ezt az AsBroadcaster dolgot. Az előbbi módszert alkalmazva ezt is felderítjük:

trace("****** AsBroadcaster tulajdonságai, metódusai *******");
for ( Obj in AsBroadcaster ){
     trace(Obj);
};

trace("**********************************************************");


A futtatás eredménye:

****** AsBroadcaster tulajdonságai, metódusai *******

initialize
removeListener
addListener
broadcastMessage
prototype
__proto__
constructor

**********************************************************

Nagyon érdekes, amit találtunk! Hogy ne vesztegessük az időt le is írom, hogy, mi - mit jelent:

initialize -> Egy adott objektumot felruházza az Üzenés képességével. Használata: AsBroadcaster.initialize(valami objektum)

removeListener -> a figyelők listájából kitörli az adott Figyelőt. Használata: Uzeno.removeListener(figyelo)

addListener -> az adott Figyelőt a figyelők listájára teszi. Használata: Uzeno.addListener(Figyelo)

broadcastMessage -> eseményt üzeni metódus. Használata: broadcastMessage("eseménykezelő neve", paraméter 1, paraméter 2, paraméter n);

A prototype-pal most nem foglalkozunk! Nézzük meg az előbbi példát, amikor kilistáztuk egy objektum rejtett tulajdonságait, metódusait:

var valamiObjektum:Object = new Object();
ASSetPropFlags(valamiObjektum, null, 8, 1);
trace("****** valamiObjektum AsBroadcaster nélkül *******");
for ( var Obj in valamiObjektum ){
      trace(Obj);
};

trace("**********************************************************");

AsBroadcaster.initialize(valamiObjektum);
ASSetPropFlags(valamiObjektum, null, 8, 1);
trace("****** valamiObjektum AsBroadcaster-rel *******");
for ( var Obj in valamiObjektum ){
      trace(Obj);
};

trace("**********************************************************");


A futtatás eredménye:

****** valamiObjektum AsBroadcaster nélkül *******
__constructor__
__proto__

**********************************************************

****** valamiObjektum AsBroadcaster-rel *******
_listeners
removeListener
addListener
broadcastMessage
__constructor__
__proto__

**********************************************************

Látható, hogy objektumunk most már rendelkezik a kívánt funkcionalitással, de még nem küld üzenetet.

Futtassuk az alábbi kódot:

var valamiObjektum:Object = new Object();
// létrehozunk egy objektumot

var i:Number = 0;

// létrehozzuk ezt a változót teszt céljából

AsBroadcaster.initialize(valamiObjektum);

// a valamiObjektum Object-et ellátjuk eseményüzenő funkcionalitással.

var masikObj:Object = new Object;

// létrehozunk egy másik objektumot, ebből lesz a Figyelőnk

masikObj.onRetek = function(param){

// mivel az Üzenő eseménykezelőjének az onRetek nevet adtuk, ezért ezzel a névvel készítjük fel a figyelőt az eseményüzenet fogadására.

trace("Az i változó értéke: "+param);

// kiírjuk ezt a szöveget és az i értékét

};
valamiObjektum.addListener(masikObj);

// a valamiObjektum (Üzenő) listájára felíratjuk a masikObj-t, mint Figyelőt
_root.onEnterFrame = function(){
// ez a teszt szakasz! Elszámolunk 12-ig és az Üzenővel elküldetjük az onRetek eseményüzenetet

_root.i++;

//növeljük az i értékét mindig eggyel

if (_root.i == 12 ){

// ha i értéke egyenlő 12-vel, akkor
.
_root.valamiObjektum.broadcastMessage("onRetek", _root.i);

// kiküldjük az onRetek üzenetet, mégpedig az i értékével, mint paraméterrel

};
};


Azt gondolom ezzel már tényleg megalapoztuk tudásunkat, az eseményalapú életről. Tudunk Üzenőt kreálni olyan objektumból, amely nem volt arra képes, és tudjuk az eseményüzenetet fogadni, majd értelmezni.

Sok esetben ez sokkal jobb megoldás, mint a ciklusok használata.

Megjegyzés: Úgynevezett "nem dokumentált" funkciókat használni, nem tanácsos, mert senki és semmi sem garantálja, hogy a következő verziókban is benne lesznek. Például az itt tárgyalt nem dokumentált funkciót a Flash 6-os lejátszója ASBroadcaster-ként ismeri (vegyük észre, hogy a második betű nagy). Mindazonáltal nem tartom valószínűnek, hogy a Macromedia elhagyná ezt a globális objektumot, olyan sokan használják már. Bár elképzelhető, néhány cifraság, lásd előbbi név példa. Akik jobban aggódnak az ilyen dolgok felett, azoknak ajánlom a BroadcastMX osztály használatát, amely elérhető a Flash, en\First Run\Classes\mx\transitions könyvtárából.

 
           
 
 

© Devnet.hu. A segédletek semmilyen formában nem másolhatók, publikálhatók a Devnet.hu és a szerzők közös írásos engedélye nélkül.
 
. .. : Swf.hu 1.0 archívum : Swf.hu főoldal >>> : .. .