as3 - dispatchEvent from a parent swf to a child swf

匿名 (未验证) 提交于 2019-12-03 08:52:47

问题:

I have one main "parent" swf that loads several other swfs. If something happens in the main swf I need to tell one of the child swfs about it.

This seems to work well the other way around. Any of the children can simply dispatchEvent(), and I can set up the main swf to listen for the event. However, I can't get the child swf to catch any events dispatched by the parent. How is it done?

回答1:

OK, so if you know most of this already, my apologies... but it seems a pretty common issue and isn't immediately obvious.

In AS3 events dispatched by objects on the display list can be listened for as they bubble up the display list hierarchy without needing to specify the originating object. (Assuming of course that the event has its bubbling property set to true). Hence the Document Class (the old concept of _root) can respond to mouse clicks from any display object, no matter how deeply nested, with

addEventListener(MouseEvent.CLICK, _onMouseClick)

In any other situation - e.g. bubbling is set to false, the broadcaster is not an InteractiveObject on the display list or, (as in your case) the listener is lower than the broadcaster in the display list hierarchy - the object broadcasting the event must be specifically listened to:

fooInstance.addEventListener(Event.BAR, _bazFunc)
as opposed to just
addEventListener(Event.BAR, _bazFunc)

Basically you need to pass a reference to the parent object to your child swf so that it can then attach event handlers to it.

One method is to dispatch an event from the child to the parent class via the display list (once the child has loaded and fully initialised). The parent uses the event.target property of this event to reference the child and set a parentClass variable on it. This can then be used to attach listeners:

package {       class ChildClass      {         private var __parentClass:ParentClass;          // EventID to listen for in ParentClass         public static const INITIALISED:String = "childInitialised";          // Constructor         function ChildClass()          {             // Do initialising stuff, then call:             _onInitialised();         }          private function _onInitialised():void         {             // Dispatch event via display hierarchy             // ParentClass instance listens for generic events of this type             // e.g. in ParentClass:             //     addEventListener(ChildClass.INITIALISED, _onChildInitialised);             //     function _onChildInitialised(event:Event):void {             //         event.target.parentClass = this;             //     }             // @see mutator method "set parentClass" below             dispatchEvent(new Event(ChildClass.INITIALISED, true);         }          public function set parentClass(value:ParentClass):void         {             __parentClass = value;              // Listen for the events you need to respond to             __parentClass.addEventListener(ParentClass.FOO, _onParentFoo, false, 0, true);             __parentClass.addEventListener(ParentClass.BAR, _onParentBar, false, 0, true);         }          private function _onParentFoo(event:Event):void         {             ...         }     } } 

Dispatching a custom ChildSWFEvent - i.e. instead of using a class-defined constant as above - will make this a more flexible solution since the ParentClass instance can listen for a common ChildSWFEvent.INITIALISED event broadcast by any child swf with contextually useful information passed as an additional parameter.



回答2:

When you load a child swf (Main.swf) in an parent swf (Index.swf), keep a reference in a field variable or class variable

fldMain = BulkLoader.getLoader("Index").getContent("Main.swf") as DisplayObject; this.addChild(fldMain); 

(i'm using BulkLoader to load any content)

It's a good practice to wait with dispatching events until the child is added (ADDED_TO_STAGE event)

When I want to dispatch an event to my child I just say:

fldMain.dispatchEvent(new CustomEvent(CustomEvent.INIT_CHILD,data)); 


回答3:

What I did was add a listener on the parent for changes after the child is added to the stage. Now anytime you want to have children deal with updating themselves, just dispatch the Event.CHANGE from the parent. Bubbling can be true or false.

I would think that if you attach the child;s listener to the Stage (stage.addEventListener...) any object that throws a Event.CHANGE could trigger the child to handle the event.

package {     import flash.display.*     import flash.events.*          public class Child extends Sprite         {              public function Child():void             {                 this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);             }              private function addedToStageHandler(pEvent:Event):void             {                 trace("CHILDADDED");                 this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);                 this.parent.addEventListener(Event.CHANGE, parent_changeEventHandler, false, 0, true);             }              private function parent_changeEventHandler(pEvent:Event):void             {                 trace("PARENT_CHANGED");             }         } } 


回答4:

IMO, it is almost never appropriate for a child to know or care about its parent. On the other hand, parents nearly always know everything about their children (since they have a direct reference to them). So, in this case, I would simply create a property or method on the child Class that could be set/called by the parent when needed.

This has the advantage of better performance, since creation and handling of an Event is more expensive than simply calling a method or setting a value.

HTH;

Amy



回答5:

I would listen in each child for

Event.ADDED_TO_STAGE 

once it has been added to the stage, you can then reference/listen to the stage for events.

Example

//Child if(stage) _init(); //Already added else addEventListener(Event.ADDED_TO_STAGE, _init); //waiting to be added  private function _init(e:Event = null):void {     stage.addEventListener(CustomEvent.CHANGED, _onStageChanged); { 

I didn't test this, but as long as you dispatch the events from the stage, it should work.

//stage dispatchEvent(new CustomEvent(CustomEvent.CHANGED)); 

if you setup your custom event class correctly you can also pass information accross.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!