what's diffrance between Event and EventDispacher
when I create Custom Event class how I create it and extend it to Event or eventDispacher ?
package
{
import flash.events.Event;
that's how you can extend a event :
public class CustomEvent extends Event
{
public static const CUSTOM_EVENT:String = "customEvent";
public var param:Object;
public function BannerEvent( type:String, param:Object = null, bubbles:Boolean = false, cancelable:Boolean = false )
{
super( type, bubbles, cancelable );
this.param = param?param: { };
}
}
}
EventDispatcher will, as it says in the name dispatch an event.
For example if your custom component implements IEventDispatcher, it will be able to dispatch events.
In Flash, all DisplayObjects can dispatch events by default.
In Flex, all UIComponents can dispatch events by default.
To create a custom event, you can do the following:
package{
import flash.events.Event;
public class MyCustomEvent extends Event
{
private var _test:String;
public function MyCustomEvent(test:String)
{
super("MyCustomEvent", false, false);
this.test = test;
}
public function set test(value:String):void{
_test = value;
}
public function get test():String{
return test;
}
}}
Then to dispatch it, you either dispatch an event from a Display Object or you create a custom component that implements IEventDispatcher
and do this:
dispatchEvent(new MyCustomEvent("This is a test event"));
Cheers
Related
I know how to use addEventListener for one class to react to another class's button being clicked on. What if you want to use it for a more general purpose than that? What if you want to use it to react to one of the member functions of the other class being called? Is there a syntax for that? Thanks!
Edit: Please note that I have already Googled for the answer.
If you want to listen for another class' member function call, you need that function call to dispatch an Event. This is as simple as...
Listener Class
addEventListener("customEvent", listenerFunc);
Dispatcher Class (extends EventDispatcher / implements IEventDispatcher)
dispatchEvent(new Event("customEvent"));
As long as the listener class is above the dispatcher class in the object hierarchy, this will work perfectly. If not, you may want to use some sort of Global EventDispatcher class and register all listeners on that.
You can create your own events and dispatch them from the other class and listen to them in your listening class. Here is some code
In class A (assuming it inherits EventDispatcher)
public function classAMethod():void
{
dispatchEvent(new Event("someCustomTypeForEvent"));
}
In class B (assuming it has a reference to Class A)
public function classBMethod():void
{
classA.addEventListener("someCustomTypeForEvent",customHandler);
}
public function customHandler(e:Event):void
{
trace("handle event");
}
It's like in JAVA for java.awt.Component instances and all Objects that extends java.awt.Component; in AS3 you may add Listeners to all Objects that extends flash.display.Sprite instances which implements methods of IEventDispatcher for you...
So, If you have a class which do not extends flash.display.Sprite, you'll have to extend EventDispatcher in order to add Listeners to your instances and handle Events...
If the class may not extend EventDispatcher, you'll have to implement the IEventDispatcher.
Here is a [class MainClass] that extends [class MovieClip]
This MainClass instance, creates :
An instance of [class ObjectA] which extends [class Object] and implements IEventDispatcher,
An instance of [class ObjectB] which extends [class EventDispatcher]
Here is the code that use the extension method and the implementation method :
I hope this quick done example will help you...
(And sorry for my English, this is not my native language.)
in MainClass.as :
package com
{
import flash.utils.getDefinitionByName;
import flash.display.MovieClip;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
import com.classes.ObjectA;
import com.classes.ObjectB;
import flash.events.Event;
public class MainClass extends flash.display.MovieClip
{
private static const DEBUG:Boolean = true;
private static var instance:MainClass;
private static var instanceOfA:ObjectA;
private static var instanceOfB:ObjectB;
public function MainClass()
{
MainClass.debug("MainClass constructor called");
MainClass.debug(getClassInformations(MainClass));
MainClass.debug(getClassInformations(ObjectA));
MainClass.debug(getClassInformations(ObjectB));
instanceOfA = new ObjectA();
instanceOfB = new ObjectB();
instanceOfA.addEventListener(ObjectA.DO_SOMETHING_EVENT,onInstanceOfA_doSomething,false,0,false);
instanceOfB.addEventListener(ObjectB.DO_SOMETHING_EVENT,onInstanceOfB_doSomething,false,0,false);
instanceOfA.doSomething();
instanceOfB.doSomething();
}
public static function onInstanceOfA_doSomething(e:Event):void
{
trace("An ObjectA has Dispatched An Event of type \"" + e.type + "\"" + " on " + e.target);
}
public static function onInstanceOfB_doSomething(e:Event):void
{
trace("An ObjectB has Dispatched An Event of type \"" + e.type + "\"" + " on " + e.target);
}
public static function getDebugMode():Boolean
{
return DEBUG;
}
public static function debug(string:String)
{
if (getDebugMode())
{
trace(string);
}
}
public static function getClassInformations(someClass:Class):String
{
var clss:Object = null;
var supClss:Object = null;
clss = getDefinitionByName(getQualifiedClassName(someClass));
try
{
supClss = getDefinitionByName(getQualifiedSuperclassName(someClass));
}
catch (e:ArgumentError)
{
// Has no superClass (ex:Object)
}
if (supClss != null)
{
return ("class " + clss + " extends " + supClss);
}
else
{
return ("class " + clss);
}
}
}
}
in ObjectB.as (simplest way):
package com.classes{
import com.MainClass;
import flash.events.EventDispatcher;
import flash.events.Event;
public class ObjectB extends EventDispatcher {
public static var DO_SOMETHING_EVENT:String = "do_something_event";
private var onDoSomethingEvent:Event = new Event(DO_SOMETHING_EVENT,false,false);
public function ObjectB() {
MainClass.debug("constructor ObjectB called");
}
public function doSomething():void{
this.dispatchEvent(onDoSomethingEvent);
}
}
}
in ObjectA.as (there you must implement all the methods of the interface IEventDispatcher):
package com.classes
{
import com.MainClass;
import flash.events.IEventDispatcher;
import flash.events.EventDispatcher;
import flash.events.Event;
public class ObjectA implements IEventDispatcher
{
public static var DO_SOMETHING_EVENT:String = "do_something_event";
private var onDoSomethingEvent:Event = new Event(DO_SOMETHING_EVENT,false,false);
private var dispatcher:EventDispatcher;
public function ObjectA()
{
dispatcher = new EventDispatcher(this);
MainClass.debug("constructor ObjectA called");
}
public function doSomething():void
{
this.dispatchEvent(onDoSomethingEvent);
}
public function addEventListener(
event_type:String,
event_listener:Function,
use_capture:Boolean = false,
priority:int = 0,
weakRef:Boolean = false
):void
{
// implements addEventListener here
dispatcher.addEventListener(event_type, event_listener, use_capture, priority, weakRef);
}
public function dispatchEvent(e:Event):Boolean
{
// implements dispatchEvent here
return dispatcher.dispatchEvent(e);
}
public function removeEventListener(
event_type:String,
event_listener:Function,
use_capture:Boolean = false
):void
{
// implements removeEventListener here
dispatcher.removeEventListener(event_type, event_listener, use_capture);
}
public function hasEventListener(type:String):Boolean
{
// implements hasEventListener here
return dispatcher.hasEventListener(type);
}
public function willTrigger(type:String):Boolean
{
// implements willTrigger here
return dispatcher.willTrigger(type);
}
}
}
Note that if you extend an EventDispatcher, you may also want to override some methods.
In this case, you must use the "override keyword as :
public override function dispatchEvent (e:Event):Boolean {
// a method of EventDispatcher may be overridden if needed !
// do what you need HERE...
return dispatchEvent(e);
}
In AS3 you must specify the override keyword or you'll get an Error 1024:
"Overriding a function that is not marked for override."
When you create a new EventDispatcher through implement or extend, you may also specify additional arguments and methods to this object as:
public function ListenerObject (v:View,m:Main) {
dispatcher = new EventDispatcher(this);
view = v;
master = m;
}
public function getView ():View {
return view;
}
public function getMain ():Main {
return master;
}
then use those methods in the callback method as :
public function callback(e:Event):void{
e.target.getView ();
//...
}
I have created a Custom Event, that is fired from a custom component. It should be catched in the main application to change the selectedindex of the viewstack.
But this doesn't work, and I can't figure out why.
This is my Custom Event:
package events
{
import flash.events.Event;
public class ChangeSelectedIndex extends Event
{
public static var index_passed:String = "Index passed";
private var index:int;
public function ChangeSelectedIndex(i:int, type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type,bubbles, cancelable);
index = i;
}
public function get getIndex():int
{
return index;
}
}
}
This is how I fire the event:
protected function checkUsernameExistsDbSucces(event:ResultEvent):void
{
dispatchEvent( new ChangeSelectedIndex(1,ChangeSelectedIndex.index_passed,false,false));
}
And this is my function to catch the event:
private function changeSelectedIndexHandler(event:ChangeSelectedIndex):void
{
mainViewStack.selectedIndex = event.getIndex;
}
In order for your handler to be called when the event is dispatched, you need to add an event listener to your custom component.
myCustomComponent.addEventListener ( ChangeSelectedIndex.index_passed, changeSelectedIndexHandler);
Make sure this line is within the same scope as both your handler function and myCustomComponent, otherwise there will be an error.
I've been looking into custom event (listeners) for quite some time, but never succeeded in making one. There are so many different methods, extending the Event class, but also Extending the EventDispatcher class, very confusing!
I want to settle with this once and for all and learn the appropriate technique.
package{
import flash.events.Event;
public class CustomEvent extends Event{
public static const TEST:String = 'test'; //what exac is the purpose of the value in the string?
public var data:Object;
public function CustomEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false, data:Object = null):void
{
this.data = data;
super();
}
}
}
As far as I know a custom class where you set the requirements for the event to be dispatched has to be made:
package
{
import flash.display.MovieClip;
public class TestClass extends MovieClip
{
public function TestClass():void {
if (ConditionForHoldToComplete == true) {
dispatchEvent(new Event(CustomEvent.TEST));
}
}
}
}
I'm not sure if this is correct, but it should be something along the lines of this.
Now What I want is something like a mouseevent, which can be applied to a target and does not require a specific class.
It would have to work something like this:
package com.op_pad._events{
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.EventDispatcher;
import flash.events.Event;
public class HoldEvent extends Event
{
public static const HOLD_COMPLETE:String = "hold completed";
var timer:Timer;
public function SpriteEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super( type, bubbles, cancelable );
timer = new Timer(1000, 1);
//somehow find the target where is event is placed upon -> target.addEventlistener
target.addEventListener(MouseEvent.MOUSE_DOWN, startTimer);
target.addEventListener(MouseEvent.MOUSE_UP, stopTimer);
}
public override function clone():Event
{
return new SpriteEvent(type, bubbles, cancelable);
}
public override function toString():String
{
return formatToString("MovieEvent", "type", "bubbles", "cancelable", "eventPhase");
}
//////////////////////////////////
///// c o n d i t i o n s /////
//////////////////////////////////
private function startTimer(e:MouseEvent):void
{
timer.start();
timer.addEventListener(TimerEvent.TIMER_COMPLETE, complete);
}
private function stopTimer(e:MouseEvent):void
{
timer.stop()
}
public function complete(e:TimerEvent):void {
dispatchEvent(new HoldEvent(HoldEvent.HOLD_COMPLETE));
}
}
}
This obviously won't work, but should give you an idea of what I want to achieve. This should be possible because mouseevent can be applied to about everything.The main problem is that I don't know where I should set the requirements for the event to be executed to be able to apply it to movieclips and sprites.
You are almost there actually, just for the last part, wouldn't this be more of an OOP related issue than stricly a confusion about the way of using custom events ?
Usually, Events in AS3 are value objects whose sole responsibility is to transport information from the event dispatcher to the listener(s). The dispatcher dispatches the event each time a defined momentum is reached, and the listener(s) may or may not react when this happens.
In the example above, I guess it is up to the listener to start a timer and so on when a mouse-down has been detected. In a more sophisticated context the Event could independently trigger more than one listeners actioning separate tasks which neither the Dispatcher nor the Event itself should have to bother about, that is probably why it's worth avoiding amending the dispatcher or the event itself with any soever logic.
For your very example, you could maybe create a handler checking if the mouse has been held down?
The following is just pseudocode, and there are obviously tons of other ways to get to the same result:
public class MouseDownHandler
{
// ...
public function( target:Sprite ) {
this.target = target;
start();
}
public function start():void{
// Listen for the target's mouseUp event
}
public function dispose():void{
// Stop listeners and eventually the timer
}
private function onMouseDown(e:MouseEvent):void{
// Start timer + listening for the stage's mouse up event (target.stage)
}
private function onMouseUp(e:Event):void{
// Cancel timer
}
private function onTimerComplete(e:TimerEvent):void {
dispatchEvent(new HoldEvent(HoldEvent.HOLD_COMPLETE));
}
}
Which could be reused for example this way:
var mc:MovieClip = new MovieClip(); ...
var mouseHandler:MouseDownHandler = new MouseDownHandler(mc);
mouseHandler.addEventListener(HoldEvent.HOLD_COMPLETE, onMcHoldComplete);
... or this way :
public class TestMovieClip extends MovieClip
{
private var mouseHandler:MouseDownHandler;
public function TestMovieClip() {
mouseHandler = new MouseDownHandler(this);
mouseHandler.addEventListener(HoldEvent.HOLD_COMPLETE, onMouseHoldComplete);
}
private function onMouseHoldComplete(e:HoldEvent):void {
// Do something
}
}
I just use robber penners signals. Very easy to use.
http://github.com/robertpenner/as3-signals
I have created a custom even class which is pretty basic. But when calling an event and then relaying that event to another class I have encountered the "cannot transform thisEvent into thisOtherEvent" error.
I realize this is because I needed to override the Clone function in my custom event like so:
package com
{
import flash.disply.*;
import flash.events.Event;
public class MyCustomEvents extends Event
{
public static const SOME_EVENT:String = "some_event";
public var info:Object;
public function MyCustomEvents($type:String, $info:Object,$bubbles:Boolean = false, $cancelable:Boolean = false)
{
super($type, $bubbles, $cancelable);
this.info = $info;
}
public override function clone():Event {
return new MyCustomEvents($type, $bubbles, $cancelable);
}
}
}
However I am still getting this error when I dispatch the event. Anything else I might be missing?
here is the error:
TypeError: Error #1034: Type Coercion failed: cannot convert com.greensock.events::TransformEvent#d8df709 to com.customEvents.MyCustomEvents.
I tried casting the event in the code like so:
var deleteImgEvent:MyCustomEvent = new MyCustomEvent(MyCustomEvents.IMAGE_DELETE, {imgData: getImg}, true, false); this.dispatchEvent(deleteImgEvent as MyCustomEvents);
Still no luck.
UPDATE:
Ok, seems like the problem is in the greensock Transform library. When the event handler for my custom event is called, I run a function of the TransformManager class.
_manager.deleteSelection();
Inside that class it dispatched a TransformEvent. Not sure why, but it is reading that delete event as a MyCustomEvent.
/**
* #usage
* var myEvent:CustomEvent = new CustomEvent(CustomEvent.EVENT_TYPE_A, { integerRelatedToEvent: 5, stringRelatedToEvent: 'easy' });
* addEventListener(CustomEvent.EVENT_TYPE_A, traceCustomEvent);
* dispatch(myEvent);
* function traceCustomEvent ($e:CustomEvent):void {
* trace($e.type);
* }
*/
package {
import flash.events.Event;
public class CustomEvent extends Event {
// Types:
public static const EVENT_TYPE_A:String = 'CustomEvent.EVENT_TYPE_A';
public static const EVENT_TYPE_B:String = 'CustomEvent.EVENT_TYPE_B';
// Components:
private var _customDatum:Object;
public function get customDatum ():Object { return _customDatum; }
public function CustomEvent ($type:String, $customDatum:Object) {
super($type);
_customDatum = $customDatum;
}
public override function clone ():Event {
return new CustomEvent(type, _customDatum);
}
}
}
"When creating your own custom Event
class, you must override the inherited
Event.clone() method in order for it
to duplicate the properties of your
custom class. If you do not set all
the properties that you add in your
event subclass, those properties will
not have the correct values when
listeners handle the redispatched
event."
package com.events;
{
import flash.events.Event;
public class XMLLoaderEvent extends Event
{
public static const XML_LOADED:String = "XML_Loaded";
public var data:*;
public var properties:Object;
public function XMLLoaderEvent( type:String,_data:*,bubbles:Boolean = false,cancelable:Boolean = false):void
{
super( type, bubbles, cancelable );
data = _data;
}
// Override clone
override public function clone():Event
{
return new XMLLoaderEvent( type, data, bubbles, cancelable);
}
}
}
Don't know if that's it but you have an extra parameter $info:Object into your custom event, but you don't pass it in your clone contructor.
return new MyCustomEvents(type, info, bubbles, cancelable);
I think you need the clone function to return a MyCustomEvents type. Not an Event type. And you need to add the info parameter as stated by the previous poster.
package com {
import flash.display.*;
import flash.events.Event;
public class MyCustomEvents extends Event {
public static const SOME_EVENT:String = "some_event";
public var info:Object;
public function MyCustomEvents($type:String, $info:Object,$bubbles:Boolean = false, $cancelable:Boolean = false) {
super($type, $bubbles, $cancelable);
this.info = $info;
}
public override function clone():MyCustomEvents {
return new MyCustomEvents(this.type, this.info, this.bubbles, this.cancelable);
}
}
}
So I want a way to set up events so that I can pass data without creating closures \ memory leaks. This is as far as I have got:
package com.events {
import flash.events.Event;
public class CustomEvent extends Event {
public static const REMOVED_FROM_STAGE:String = "removedFromStage";
public var data:*;
public function CustomEvent(type:String, customData:*=null, bubbles:Boolean=false, cancelable:Boolean=false) {
super(type, bubbles, cancelable);
this.data = customData;
}
public override function clone():Event {
return new CustomEvent(type, data, bubbles, cancelable);
}
public override function toString():String {
return formatToString("CustomEvent", "type", "data", "bubbles", "cancelable", "eventPhase");
}
}
}
This gets me the following behavior:
function testme(e:Event) {
trace(e);
}
test_mc.addEventListener(CustomEvent.REMOVED_FROM_STAGE, testme);
test_mc.dispatchEvent(new CustomEvent(CustomEvent.REMOVED_FROM_STAGE, 42));
//Traces [CustomEvent type="removedFromStage" data=42 bubbles=false cancelable=false eventPhase=2]
removeChild(test_mc);
//Traces [Event type="removedFromStage" bubbles=false cancelable=false eventPhase=2]
My goal is to get the custom data I want to pass to get passed from the event flash fires, not just the one that I fire. For example, what if I wanted to pass a movieclip along with a loader.COMPLETE event to put the resulting bitmap in?
You extended the Event class for it to dispatch with extra data, now if you want the Loader class to dispatch your custom event type, extend the Loader class to do that (or any other class you want to do this with). In this example I'll override URLLoader with this functionality (because Loader actually dispatches events from it's contentLoaderInfo, which needs two overridden classes, and I just want to keep it simple)
package com.net
{
import flash.net.URLLoader;
import flash.events.Event;
import com.events.CustomEvent;
public class CustomLoader extends URLLoader
{
// URLLoader already has a data property, so I used extraData
public var extraData:*;
override public function dispatchEvent(event: Event) : Boolean
{
var customEvent: CustomEvent = new CustomEvent(event.type, extraData, event.bubbles, event.cancelable);
return super.dispatchEvent(customEvent);
}
}
}
Now to use this with your CustomEvent class try this code in your .fla
import com.net.CustomLoader;
import com.events.CustomEvent;
var loader: CustomLoader = new CustomLoader();
loader.extraData = "Extra Data";
loader.load(new URLRequest("test.xml"));
loader.addEventListener(Event.COMPLETE, loadComplete);
function loadComplete(event: CustomEvent) : void
{
trace(event.data); // Extra Data
}
BAM! Custom data on your innately dispatched events!
The following shows the cleanest way to create a custom event. Typically event types have public static references typed in all capitol letters. When an event is dispatched, it passes an Event, or CustomEvent, object to the event handler method. This is where you can retrieve your passed value.
package com.hodgedev.events
{
import flash.events.Event;
public class CustomEvent extends Event
{
public static const VALUE_CHANGED:String = "VALUE_CHANGED";
public var value:Number;
public function CustomEvent(pValue:Number)
{
super(CustomEvent.VALUE_CHANGED);
value = pValue;
}
public override function clone():Event
{
return new CustomEvent(value);
}
}
}
When we dispatch events, we create a new instance of the event to be passed as such.
private var _someValue:int = 12;
dispatchEvent(new CustomEvent(_somevalue));