AS3 Event Handling- part 4

Posted on April 8, 2009


In the previous part we discussed about the event propagation. In this part we will look for creating a custom event class

The need of creating a custom event class comes when you have to put your event system more systematic and comprehensive. Let me give one example where you might need to have your won event class where you can define your event names, customize it to get values of the event related objects and use it with simplicity similar to inbuilt event classes. We are going to build a confirmation control box where we will have three buttons with labels ‘”Yes” , “No”, “Cancel”.  We might have other type of utility boxes that have either of these three kind of controls or combination of two or a single control( alert windows). 

For the above example let’s create a small project with flex builder and create a small custom component called ConfirmationBox. Put three buttons labeled as per required. And here is the similar code. that you may write for your self.

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="100">
  3.         <mx:Button x="175" y="68" label="Yes" click="yes()"/>
  4.         <mx:Button x="248" y="68" label="No" click="no()"/>
  5.         <mx:Button x="321" y="68" label="Cancel" click="cancel()"/>
  6.         <mx:HRule x="10" y="54" width="380" height="1"/>
  7.         <mx:Text x="31" y="10" text="Are you sure you want to quit?" width="359" height="41" fontSize="17" fontFamily="Arial" fontWeight="bold"/>
  8.         <mx:Script>
  9.                 <![CDATA[
  10.                        
  11.                         private function cancel():void{
  12.                                 //TODO
  13.                         }
  14.                         private function no():void{
  15.                                 //TODO
  16.                         }
  17.                         private function yes():void{
  18.                                 //TODO
  19.                         }
  20.                                                
  21.                 ]]>
  22.         </mx:Script>
  23. </mx:Canvas>

Each button has separate click handlers and we shall write some code so that our component can dispatch some custom event that we are soon going to create. Generally we subclass the already existing flash.events.Event class to readily avail all the basic methods and properties of an event class. Now we shall create a event class called “WindowControlEvent” which will extends Event class of flash.events package. Add three string constants to denote the event names before the constructor. And your class will look like below.

  1. package
  2. {
  3.         import flash.events.Event;
  4.  
  5.         public class WindowControlEvent extends Event
  6.         {
  7.                 public static const YES:String="yes";
  8.                 public static const NO:String="no";
  9.                 public static const CANCEL:String="cancel";
  10.  
  11.                 public function WindowControlEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
  12.                 {
  13.                         //TODO: implement function
  14.                         super(type, bubbles, cancelable);
  15.                 }
  16.  
  17.         }
  18. }

Declaring the constants with uppercase makes it clearer to avoid typing error. We can now attach this event class to some object with addEventListener method. Ex: objectName.addEventListener(WindowControlEvent.YES, eventHandler).That’s it for a very basic custom event class. Now let’s use it.

In the small application that we wrote before lets dispatch the events in the three event handlers.We have to dispatch a new WindowControlEvent and pass the event name (”cancel”, “no” or “yes”) by the constants defined for them.

  1. <mx:Script>
  2.         <![CDATA[
  3.                 public function cancel():void{
  4.                         dispatchEvent(new WindowControlEvent(WindowControlEvent.CANCEL));
  5.                 }
  6.                 public function no():void{
  7.                         dispatchEvent(new WindowControlEvent(WindowControlEvent.NO));
  8.                 }
  9.                 public function yes():void{
  10.                         dispatchEvent(new WindowControlEvent(WindowControlEvent.YES));
  11.                 }
  12.         ]]>
  13. </mx:Script>

Now let’s use this in our application and capture the events.

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*" applicationComplete="init()">
  3.         <local:ConfirmationBox id="confBox">
  4.                
  5.         </local:ConfirmationBox>
  6.         <mx:Script>
  7.                 <![CDATA[
  8.                         import mx.controls.Alert;
  9.                         private function init():void{
  10.                                 confBox.addEventListener(WindowControlEvent.YES, saveAndExit);
  11.                                 confBox.addEventListener(WindowControlEvent.NO, dontSaveAndExit);
  12.                                 confBox.addEventListener(WindowControlEvent.CANCEL, stayBack);
  13.                         }
  14.                        
  15.                         private function stayBack(evt:WindowControlEvent):void{
  16.                                 Alert.show("stayback");
  17.                         }
  18.                        
  19.                         private function dontSaveAndExit(evt:WindowControlEvent):void{
  20.                                 Alert.show("dontSaveAndExit");
  21.                         }
  22.                        
  23.                         private function saveAndExit(evt:WindowControlEvent):void{
  24.                                 Alert.show("saveAndExit");
  25.                         }
  26.                        
  27.                 ]]>
  28.         </mx:Script>
  29. </mx:WindowedApplication>
  30.  

Filed Under AS3, Flex 3.0 | 1 Comment »

Multiple tweening problem

Posted on April 4, 2009


While developing a multi player poker game I got strange problems with tweening using fl.transition.Tween class. There were 18 cards to be distributed among 9 players in sequence and with 100ms interval. I put them in a timer and fired tweens at each timer event. I was writing the tweening code inside a method and adding event listeners to capture the finish event of the tween event. Problems that raised by this process were:

Problems:

1. Sometimes cards hangup while distribution.

2. Cards could not reach the exact location specified.

In other words the tween freezes on the way. 

This kind of problem arises mostly in the following cases:

1. Tweening multiple objects either synchronously or asynchronously by using local variables to handle tween events.

2. Tweening multiple properties of an object and adding event to one of them. ex:

  1. var tweenObj:Tween=new Tween(targetClip, "x",….other params…);
  2. new Tween(targetClip,"y",…..other params…);
  3. tweenObj.addEventListener(TweenEvent.MOTION_FINISH, eventHandler);

Note: I have added event listener to the tweenObj  which modifies the ‘x’ property of the targetClip.

Reason:

The first problem arises because of garbage collection of the tween objects as because they are declared as local variables(variables declared within a method). So in the way of transition/transformation the tween is dumped to garbage area and tween stops. This case is not a regular case so can not be reproducible every time(or I might not have understand it well enough the exact time after which tween object looses its status).

For the second problem when event handlers are created for the tween object that is declared first, other properties may not be able to finish their motion when MOTION_FINISH is fired by the tween object. If the object is disabled by this event, then other properties may not complete their transformations and freeze.

Solutions:

To prevent objects from garbage collection we need to declare the tween objects in some global variables and apply them inside methods. Here is the example:

  1. private var _tween:Tween;
  2.  
  3. private function createTween():void{
  4.       _tween=new Tween(clip, "x", Elastic.easeOut, 0, 300, 3, true);
  5.       _tween.addEventListener(TweenEvent.MOTION_FINISH, eventHandler);
  6. }

This solution is wise to use when you have small no of tweens. But if you have to create more no of tweens or tween that are created at run-time based on iterations, it’s not a good solution.

Using a dictionary object to reference the tween objects is often helpful to overcome the situations of tweening by iterations. And it’s easy to handle the dictionary objects for effective control in garbage collection. Here is the example:

  1. private var _tweenDC:Dictionary=new Dictionary;
  2.  
  3. private function createTween():void{
  4.       var clipXTween:Tween=new Tween(clip, "x", Elastic.easeOut, 0, 300, 3, true);
  5.        _tweenDC[clip]=clipXTween;
  6.        // if you have more than one property to tween you may use
  7.        // _tweenDC[clipXTween]=clipXTween;
  8.       clipXTween.addEventListener(TweenEvent.MOTION_FINISH, eventHandler);
  9. }
  10. // clear all the collected tweens
  11. private function eventHandler(evt:TweenEvent):void{
  12.     _tweenDC=new Dictionary;// Indeed not a good option. why?
  13.     // or you can do as follows for the second case discussed above.
  14.     // _tweenDC[evt.currentTarget]=null;
  15.     //  delete  _tweenDC[evt.currentTarget];
  16. }

Another way of handling multiple tweening by iterations is to reference the tweens by creating dynamic
properties of a movie clip which should be declared inside the class scope. This is specially for animating multiple properties of a same clip with iterations.

  1. private var _tweenCollector:MovieClip=new MovieClip;
  2.  
  3. private function createTween():void{
  4.       for(var i:int=0;i<=23; i++){
  5.           var _mc:Clip=new Clip;//clip is some custom class
  6.           addChild(_mc);
  7.           _tweenCollector["scalexn"+i]=new Tween(_mc, "scaleX", Strong.easeOut, 1, 1.3, .4, true);
  8.           _tweenCollector["scaleyn"+i]=new Tween(_mc, "scaleY", Strong.easeOut, 1, 1.3, .4, true);
  9.           _tweenCollector["xn"+i]=new Tween(_mc, "x", Strong.easeOut, 200, 280, .4, true);
  10.           _tweenCollector["yn" + i] = new Tween(_mc, "y", Strong.easeOut, 200,200, .4, true);
  11.           _tweenCollector["yn" + i].addEventListener(TweenEvent.MOTION_FINISH, eventHandler);
  12.       }
  13. }
  14. // clear all the collected tweens
  15. private function eventHandler(evt:TweenEvent):void{
  16.      _tweenCollector=new MovieClip;
  17. }

At some cases the above method may be risky, yet this concept worked fine for me in some of my projects.

Let’s see if any other good way exists.


Filed Under AS3, Flash | 1 Comment »

AS3 Event handling- Part 3

Posted on March 30, 2009


In previous post we got familiarized with some key words that are commonly used. Now let’s grab an example and try to understand the basic concepts.

Create a movieclip instance on the stage and give it an instance name clip_mc . Now you can either write your code in an external file or in the frame. For more simplicity let’s write the code in the first frame. Here goes the code.

  1. clip_mc.addEventListener(MouseEvent.CLICK, clickEventHandler);
  2. function clickEventHandler(event:MouseEvent){
  3.      trace("Hello Mr. X, you have clicked me");
  4. }

Test the movie. Click on the clip_mc and you will find the string which we traced  in the output panel. This tells us that our program is correct. click_mc dispatches a click event when ever mouse is being clicked on it and our program is an listener to that event. Hence clickEventHandler is being called so that we can perform necesssary actions when this event occures.

Event flow:

The event flow describes how an event object moves through the display list. when we have more than one nested displayobjects inside a movieclip, event object makes a ‘U’ turn through the stage and the actual target object. So we have three stages(phases) of event flow. In the first stage it moves from the top-most parentobject(usually the stage) to the parent of the target object. The penitration phase is called Capture Phase, when event reaches the target it’s called Target Phase, and the returning phase is called Bubbling Phase. Here is the image that shows these phases ( I took this image from the help files of flash cs3).

 

This flow of event can be controlled by actionscript. You can stop the propagation at any point of time or not let the event reach the target phase also. Which makes it easier to get work done by the parent elements when some event on the inner most child node is fired. 

It’s note worthy to remember that there are exceptions to this event flowing. Some events like init & enterFrame do not have capture or bubbling phase. They have only target phase. So other objects are not affected by these events. Event’s that are not attached to any display objects are also in the stream of the above kind of events. For example netStatus , metadata event etc.


Filed Under AS3 | Leave a Comment »

AS3 Event handling- Part 2

Posted on March 10, 2009


In the previous post we checked out some issues with AS2 event handling mechanism. In this post we will look at some well known words used  in AS3 event handling. AS3 has radical changes compared to AS2 version of action script. In terms of event handling, it provides you more control over event propagation( hey, I will tell you about this term latter, wait for this) . Here are the list of some keyword that are used in the event handling codes.

EventDispatcher: It’s the object of a class that is able to dispatch some event. Internally this class has a base class EventDispatcher  which enables the class object dispatch event and keep the track of it’s listeners by a method called addEventListener. It dispatches any event by dispatchEvent method. An example is given below.

  1. dispatchEvent(new Event(Event.CLOSE));

EventObject: Event object is an instance of the event class or or it’s subclass which holds information about the event (occurrence, source of the event, event flow and other details). For example when we click by the help of the mouse on an sprite instance, it dispatches an mouse click event. This mouse click event object is an instance of the MouseEvent and provides details of the event.
Event Target: Target of an event is usually the object that is responsible for the event dispatch. In the above example the class containing the code is the default target. But not necessarily it’s always. If the object has some inner child objects then the event target changes to the innermost child( We will discuss about this complex thing latter in details).

Event Listeners: These are the methods we write how to handle the event when it occurred. An example might clarify this. So look below.

  1. private function eventHandler(eventObject:EventType):void
  2. {
  3.     trace(eventObject.target);// this would give you name of the class that dispatches the event.(e ventTarget name).
  4. }
  5.  
  6. eventTarget.addEventListener(EventType.EVENT_NAME, eventHandler);

In the next post we will create an example and study it to explore more about the AS3 events.


Filed Under AS3 | Leave a Comment »

AS3 Event handling- Part 1

Posted on March 5, 2009


Handling an event in AS3 is quite easy and controlling each phase of event propagation is a bit tricky for beginers. Handling methods in as2 were quite simple, yet they lacked flexibility. This series of event handling is aimed to cover all the stuff in details. This part of the series discusses the event handling process in AS2 & problems faced.

Flash back of event handling in AS2:

In this example let’s take home_mc as a movieclip upon which we will be having and mouse release event. Here is the simple code that we can write for it.

  1. home_mc.onRelease=function(){
  2.          //do what ever you like, I am tracing who is responsible for the event
  3.         trace(this._name);//home_mc
  4. }

onRelease is the mouse release event that home_mc dispatches when ever mouse is released. Well that is quite simple- isn’y it!. Now lets put another movieclip inside  home_mc and name is as window_mc. Add mouse release event on the window_mc.

  1. home_mc.onRelease=function(){
  2.          //do what ever you like, I am tracing who is responsible for the event
  3.         trace(this._name);//home_mc
  4. }
  5. home_mc.window_mc.onRelease=function(){
  6.          //do what ever you like, I am tracing who is responsible for the event
  7.         trace(this._name);//window_mc expected
  8. }

Notice that you will never be able get “window_mc” - in other words you are not able to click. I would not call this as inablity- I would call it a problem- and there are solutions for this. Before knowing the solution lets’ know the reason behind this inability. When ever there is some mouse event like onRollOver, onRelease, onReleaseOutside, onRollout applied on a parent object, its child object can not recieve the mouse events. Now let’s know the solution( this is not a better solution some times - ask me why?).
1.You need to avoid putting mouse events in the parent object
2. You have to create another background object and put action over it.
An example code is given below. For this example I named the background instance as home_back_mc.

  1. home_mc.window_mc.onRelease=function(){
  2.         trace(this._name);
  3. }
  4.  
  5. home_mc.home_back_mc.onPress=function(){
  6.         this._parent.startDrag(false);
  7. }
  8. home_mc.home_back_mc.onRelease=function(){
  9.         this._parent.stopDrag();
  10. }

 Explanation: when you have two different objects inside clip with same heirarchy they have separate events for each.
In most of the cases it works but creates problems in the following cases:
1.You want to drag the parent object by pressing mouse anywhere on the object.
2.After pressing mouse on a object ( let’s call it a) you moved your mouse on another and relased. ( let’s call it b) . There is no direct way to know if you have released your mouse on b. 

As a developer I can not still say that there is no solution for the above to problems. There are ways. Now let’s look at the second type of problem we some time face.

When ever onMouseMove, onMouseUp, onMouseDown events are invoked they are global to the flash player. Hence you may mess up if you write more than two functions for each type of event.

A very basic example demonstrates this.

  1. home_mc.onMouseDown=function(){
  2.                 trace("mouse down event");
  3.         }

In the above example you need not have to click on the home_mc to invoke onMouseDown  event.

Enough flashback, now lets move to AS3 event handling basics. We will cover it in next post.


Filed Under AS3, Flash | 1 Comment »

« go backkeep looking »