PDA

View Full Version : custom events between siblings


kakino
07-28-2009, 01:37 PM
Hello, I guess this is a fairly classical problem but I can't find the solution.
Starting from the example :
I a Flex appl, there are one component "myCompImage", one button "myButton", and a Label to display the results. The component contains only an image. "myCompImage" and "myButton" are siblings.

What I want :
button "myButton" listens to a click MouseEvent.
component "myCompImage" listens to the custom event DeplaceEvent
when the button is clicked, a custom event "DeplaceEvent.DEPLACE" is dispatched. The component must react and move down.

I have written this without success, the component does'nt move down...

1. Custom Event

package com.events
{
import flash.events.Event;

public class DeplaceEvent extends Event
{
public static const DEPLACE:String="deplace";
public function DeplaceEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
//TODO: implement function
super(type, bubbles, cancelable);
}
override public function clone():Event
{
return new DeplaceEvent(type, bubbles, cancelable);
}
}
}

2. A component with an image "test_compImage.mxml"

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="234" height="180">
<mx:Image x="10" y="10" width="214" height="160" id="monimage" source="../bin-debug/images/nenuphars.jpg"/>
</mx:Canvas>


3. The Flex application

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="456" height="340" creationComplete="initEvents()" xmlns:ns1="com.images.*" xmlns:ns2="*">

<mx:Script>
<![CDATA[
import com.events.DeplaceEvent;
import mx.controls.Alert;
import flash.events.*;
private function initEvents():void {
monTexte.text = "init ";
myCompImage.addEventListener(DeplaceEvent.DEPLACE, onDeplace);
myButton.addEventListener(MouseEvent.CLICK, onClick);
//addEventListener(DeplaceEvent.DEPLACE,onDeplace);
}
private function onClick(evt:MouseEvent):void {

var myEvent:DeplaceEvent= new DeplaceEvent(DeplaceEvent.DEPLACE);
monTexte.text = " clic " + myEvent.type;
dispatchEvent (myEvent);
}
private function onDeplace(evt:Event):void {
monTexte.text = " -- " + evt.type + " compris";
evt.target.y += 5;
}
]]>
</mx:Script>
<mx:Button x="275" y="139" label="déplace" width="104" id="myButton"/>
<mx:Label x="10" y="301" text="Label" width="266" id="monTexte"/>
<ns2:test_compImage x="10" y="67" id="myCompImage">
</ns2:test_compImage>
</mx:Application>


Notice : The custom event is well formed because when I uncomment the line :
addEventListener(DeplaceEvent.DEPLACE,onDeplace)

and then, when I click on the button, the whole application moves down...
But what about my small component ? Definitively deaf...

Can you help me please ? I've been looking for days.. Thanks.

senocular
07-28-2009, 01:54 PM
I think you're getting a little confused by the roles within event dispatching.

When it comes to events, there is one object that basically does it all. It has the API (EventDispatcher; addEventListener, removeEventListener, etc.) and dispatches the events. Any other object involved simply throws in some methods to that object to allow it to call those methods when a specific event occurs for that object. They do this through addEventListener.

The button case is easy to understand. A user clicks on a button, the button dispatches an event, and some object you have listens for that event through addEventListener allowing the button to call the method that it was given through that function. So when myButton is clicked onClick gets called.

With the DeplaceEvent, you're confusing the roles. What you're doing is adding the event listener to myCompImage, but dispatching the event through the current application. If you're listening to myCompImage, myCompImage should be doing the dispatching. This is why just using addEventListener works, because you're listening to the same object you're dispatching from.

The problem in that case is, however, that you're referencing the event.target which references the entire application. (Normally you'd also rather use event.currentTarget but it doesn't really matter here).

But with this example, the biggest issue is that a custom event isn't needed. You want something to react to a click. That makes click the responsible event, not some other custom event. Your application sets up the listener for click and in that listener tells the myImageComp to move.

kakino
07-28-2009, 03:17 PM
I think you're getting a little confused by the roles within event dispatching.
Yes, probably.

When it comes to events, there is one object that basically does it all. It has the API (EventDispatcher; addEventListener, removeEventListener, etc.) and dispatches the events. Any other object involved simply throws in some methods to that object to allow it to call those methods when a specific event occurs for that object. They do this through addEventListener.

So, a kind of notifier, a singleton available to everybody, is missing ? (A singleton of EventDispatcher ) ?


But with this example, the biggest issue is that a custom event isn't needed. You want something to react to a click. That makes click the responsible event, not some other custom event. Your application sets up the listener for click and in that listener tells the myImageComp to move.
Remember that the goal is that I want components communicate by events, whatever their names. The example I left here is too simple, perhaps. Is is obvious that I could have performed it by the way you suggest, telling directly myImageComp to do this or that. But what if components are created on the fly, like objects in a game ? You don't know in advance how many they are, if they really exist a this time, etc....

Thanks for your answer, however.

senocular
07-28-2009, 03:27 PM
If you have a bunch of objects that all need to listen to the same events, then they'll need that centralized notifier/event dispatcher. This would typically be the manager of those instances. The instances "register" themselves with the manager and receieve events from that manager as they exist under its control. For a game, you might have a manager for players that manages their positions and can send messages to each player when they're near or are in contact with another player. It can do this through events or through direct callbacks from the manager interfacing with each player's APIs. If through events, each player would need to have listeners added to the manager object since it is the object in control of all the overall interaction (this would be through the register phase)

kakino
07-29-2009, 08:16 AM
Thanks, I've got the response in a very good book : ActionScript3 with Design Patterns. Here are the good practices.