Tuesday 5 June 2012

Custom Events

After a while I return to a subject that you certainly come over, again and again... at least I do.

Almost a year ago I made an article on how to make functions callbacks. You can read the article here.

Although I took too long to make a new article on this issue, I prefer this method to the callbacks. The reasons: efficiency and simplicity.

A big difference from normal events in AS3 like Events or MouseEvents is that you have several types of events in these two classes, but you cannot send anything else than... the event itself.

When you make a custom event, you can make it send any type of event defined by you... and as an extra, you can send data too.

So to start, define a new class. I name it CustomEvent (you can make a new folder to separate the classes in your application, just don't forget about the package), and it will extend the Event class in AS3:

package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
        }
    }
}

This is the base skeleton for the class. This will have the same behaviour as the base class Event. The 'type' of event will be determined  by just a unique string constant. You notice that I have included a 'data' parameter in the main constructor, and that this parameter is type '*' which means that it can hold any type of data.
So, the next is the same class with a bit more information:


package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
             super(type, bubbles, cancelable);
             this.data=data;
        }
    }
}

To make this class fully usable by Flash you need to override the clone method. This makes this listener to be forwarded to another listener. The clone method makes a direct copy of the object and returns it.
So, the class with the clone method:


package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
             super(type, bubbles, cancelable);
             this.data=data;
        }


        public override function clone():Event {
return new CustomEvent(type, data, bubbles, cancelable);
}
    }
}

The only thing missing is defining the events names. This can be any name, and are defined as public static strings, like this:


package{
    import flash.events.Event;
 
    public class CustomEvent extends Event{
        public static const EVENT_FIRED:String="Event_Fired";


        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false):void{
             super(type, bubbles, cancelable);
             this.data=data;
        }


        public override function clone():Event {
return new CustomEvent(type, data, bubbles, cancelable);
}
    }
}


That's it. Our Custom Event class is done. Now, how do I fire this?

As an example the next class will add a button to the display list. Once the user clicks in it, it will fire the 'EVENT_FIRED' event.


package{
    import flash.display.MovieClip;
    import flash.events.MouseEvents;
    import CustomEvent;
 
    public class AddButton extends MovieClip{
        private var myButton:MovieClip=new MovieClip();


        public function AddButton():void{
             this.addChild(myButton);
             myButton.addEventListener(MouseEvent.CLICK, onClick);
        }


        private function onClick(evt:MouseEvent):void {
dispatchEvent(new CustomEvent(CustomEvent.EVENT_FIRED);
}
    }
}


To caught this event you just listen this event as you normally would with any event.

One that is missing explanation is 'how do I send data with this, and how do I get it?'.

Glad you asked.

From the previous example imagine that when you click the button you want to send the string "custom event dispatched".

Replace the dispatchEvent to include this string, like this:
dispatchEvent(new CustomEvent(CustomEvent.EVENT_FIRED, "custom event dispatched");

When you listen to this listener you have to process the event for any data, like this:
...
public var anotherButton:AddButton=new AddButton();
...
anotherButton.addEventListener(CustomEvent.EVENT_FIRED, onAnotherClick);
...
private function onAnotherClick(evt:CustomEvent):void{
     trace(evt.data); //This will trace the string
}

It mihght feel confusing at the beggining but once you get the hang of this you'll throw the function callbacks... your back :)

Cheers.