AS3 Listener across object instances - possible / good or bad practice?
I have a question regarding as3 listeners, and instances of a class.
The main question: is there a way to dispatch an event from the button instance in such a way that the other button instances can listen (without the need for a listener in the document class)
Lets say i have a document class and a button class. The document will have several instances of the button class added to the display list. When a button is selected, the set method would be called to set the package variable of selected to that instance. It is from here i would like to dispatch an event to notify all other instances.
|document
|-button instance 1
|-button instance 2
|-button instance 3 (i want to send an event directly to instance 1 and 2...)
My current solution was to create a buttonGroup class, that instantiated the buttons, and the buttons would send an event call to the group parent.
|document
|-button group (catch the event and send an event to all instances within the group)
|---button instance 1
|---button instance 2
|---button instance 3 (dispatch the event)
But my problem remained - if i had multiple groups and i wanted to send an event to all of the group instance.. then i would need a buttonManager class to keep track of the groups (or at least, this is how i understand it?)
|document
|-button manager (catch the event and send an event to all group instances)
|
|---button group 1
|-----button instance 1
|-----button instance 2
|-----button instance 3 (dispatch the event)
|
|---button group 2
|-----button instance 1
|-----button instance 2
|-----button instance 3 (dispatch the event)
I am not adverse to these "solutions", i am just curious if there is another way, or if in fact my solutions are a good practice. The basis for my code sits below (minus the button manager and group classes)
I hope this was descriptive enough, and be gentle, i am new to OOP... Thanks in advance.
document.as
import flash.display.*;
import flash.events.*;
import myClasses.events.ButtonEvent;
public class Document extends MovieClip {
public function Document(){
trace("initialising Document...");
addEventListener(Event.ADDED_TO_STAGE, popStageVars);
}
private function popStageVars(e:Event){
trace("popping stage vars...")
var ob1:AbstractOBJ = new AbstractOBJ
var ob2:AbstractOBJ = new AbstractOBJ
var ob3:AbstractOBJ = new AbstractOBJ
addChild(ob1)
addChild(ob2)
addChild(ob3)
ob1.selected = ob1
ob2.selected = ob2
ob3.selected = ob3
}
}
The button class:
import flash.display.*;
import flash.events.*;
import myClasses.events.ButtonEvent;
public class ButtonOBJ extends MovieClip implements IEventDispatcher {
internal static var _selected:Object = null
public function ButtonOBJ(){
trace("initialising ButtonOBJ...");
addEventListener(Event.ADDED_TO_STAGE, popStageVars);
addEventListe开发者_JAVA技巧ner(AbstractEvent.SET_CUR, checkClip);
}
private function popStageVars(e:Event){
trace("popping stage vars..." + this.name)
}
private function checkClip(e:AbstractEvent){
trace("checking button registered... " + this.name)
}
public function get selected():Object{
return _selected
}
public function set selected(s:Object):void{
var sName:String
if(selected != null){
sName = selected.name
}else{
sName = null
}
trace(this.name + " is changing the current selected from: " + sName + " - to: " + s.name)
_selected = s
dispatchEvent(new AbstractEvent(AbstractEvent.SET_CUR, true));
}
}
and also the buttonEvent:
package myClasses.events{
import flash.events.Event;
public class ButtonEvent extends Event {
public static const SET_CUR:String = "setSelected";
public static const VERSION:Number = 1.0;
public function ButtonEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {
super(type, bubbles, cancelable);
}
public override function clone():Event {
return new ButtonEvent(this.type, this.bubbles, this.cancelable);
}
}
}
Your button class could add a listener to the stage. If your event bubbles, when the event is fired by the target, it'll bubble up to the stage. The button would "hear" the event and respond. I usually do what you are doing though and add the listener to a group. Then I loop through the buttons when the event is received and set "selected" if the event.target
is the same as the current button in the loop.
Also relatively new to AS3, but I've been doing a lot with event listeners lately. The problem with adding an event listener to the stage is that is will fire anytime that event hits the stage. Furthermore, if the event listener is part of a class, and you add 10 instances of that class, the stage is now going to have 10 event listeners all doing the same thing, and they are all going to fire. If you want differentiation (AKA each button does something different), you would have to loop through them anyway and that defeats the whole purpose of trying to add it to the stage.
What I have been doing is not using event listeners for anything but custom events in my lower level objects. Let's say I have three buttons that I want to do different things when they (and only they) are clicked. Well, in order to show up at all they are going to have to be added as children of something, right? I add a single event listener to whatever their parent is, then call the function I want to occur from the parent. Like so:
(Note: This is more pseudocode than actual code)
public class ParentObject extends Sprite{
public ParentObject(){
addchild(new ButtonObject1());
addchild(new ButtonObject2());
addchild(new ButtonObject3());
addEventListener(MouseEvent.CLICK, doButtonThing);
}
private doButtonThing(e:MouseEvent):void{
if(e.target is ButtonObject){
e.target.doStuff();
}
}
}
public ButtonObject1 extends ButtonObject{ //This works for 2 and 3. Also note that all three objects extend a parent class called ButtonObject. This is useful in checking the event target.
public ButtonObject1(){
//Create the Object here.
}
public doStuff():void{
//Whatever you want the button to do
}
}
When something is clicked, the parent object will catch the event. Then it will check to see if the object clicked was a ButtonObject (either 1, 2, or 3; we don't want something firing if it's not a button). If it is, it calls the doStuff function in the one that was clicked and not the others. You don't have to keep track of them explicitly since it is using the event.target to find object. You also prevent all the button from firing at once, and of course they can all do different things.
精彩评论