Why isn't dispatchEvent firing? - actionscript-3

okay so here is my problem in my main project I'm trying to fire an event using dispatchEvent I've made a simple test class to test this and yet it still isn't working...
Here is the test class
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main() {
stage.addEventListener("pOver", rake);
dispatchEvent(new Event("pOver"));
}
public function rake(e:Event):void {
trace("working");
}
}
Why isn't it firing? or why is the listener not capturing that event?

You are dispatching the event on the Main, which is a child of Stage. If you want to specifically dispatch an event on the Stage then use:
stage.dispatchEvent(new Event("pOver"));
Now you may be wondering, "If it's a child, then my event handler should still be getting triggered!"
Well, yes and no.
Lets take a look at a simple diagram of the event life-cycle:
First, the event that you are dispatching is not a bubbling Event. Examining the Event constructor, its signature looks like this:
public function Event(type:String, bubbles:Boolean = false, cancelable:Boolean = false)
Notice that the second argument is by default false, which means this event does not perform the bubbling part of the event life-cycle.
Second, you have attached the event dispatcher on the bubbling side of the event life-cycle. If you look at the signature for .addEventListener() it looks like this:
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
Notice the third argument. Which is by default false again. This means that you are attaching on the "bubbling" side of the event.
This means that this event is getting to the targeted element, the instance of Main, and then stopping and not going anywhere else.
TL;DR: So what does that all mean?
So to trigger your event handler, and not change where the event gets dispatched, you need to change your event that you are triggering to:
this.dispatchEvent(new Event("pOver", true)); // this event will bubble
Then your event handler, since it is a child, will be triggered by this event.
Conversely, I think that non-bubbling events will also progress through the capturing side of the event life-cycle so you could also change your event listener to attach to that side of the event as well.
stage.addEventListener("pOver", rake, true); // attach to a capturing side
I believe that event will always flow through the capturing phase, even if they are marked as not bubbling. But I could be wrong on that. I just can't remember if "non-bubbling" events skip both capturing and bubbling phases and just trigger the target event phase and I don't have time to check it right now.
Edit
So, I wrote up a quick test on wonderfl:
package {
import flash.events.Event;
import flash.display.Sprite;
public class FlashTest extends Sprite {
private var debug:TextField;
public function FlashTest() {
stage.addEventListener("Foo", bubbleFooHandler);
stage.addEventListener("Foo", captureFooHandler, true);
trace("Ready");
trace("---------------");
trace("Trying a non-bubbling event");
this.dispatchEvent(new Event("Foo"));
trace("---------------");
trace("Trying a bubbling event");
this.dispatchEvent(new Event("Foo", true));
}
private function captureFooHandler(e:Event):void {
trace("Triggered \"Foo\" from capturing phase\n");
}
private function bubbleFooHandler(e:Event):void {
trace("Triggered \"Foo\" from bubbling phase");
}
}
}
The output from this is
Ready
---------------
Trying a non-bubbling event
Triggered "Foo" from capturing phase
---------------
Trying a bubbling event
Triggered "Foo" from capturing phase
Triggered "Foo" from bubbling phase
Notice that events will always progress through the capturing phase. However, if they are not marked as a "bubbling event", see before, they will descent through the tree they stop when they arrive at target of the event (the EventDispatcher the event was dispatched on).
Bubbling events, on the other hand, will turn around and head back up the tree.
Hopefully, this clears things up.

First of all, you are listening to stage events. This means that as long as stage is not dispatching any Events you will not get any callbacks.
try
stage.dispatchEvent(new Event("pOver"));

Related

Troubles with Custom Events

I've been having lots of trouble with custom events in as3 recently, I've googled a bunch of stuff that doesn't help and used this tutorial to try to figure them out but I'm still confused.
So I set up a new flash fla file to test them and couldn't figure it out, here is what I have:
document as file:
package
{
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class Custom extends MovieClip
{
var intializer:Initializer;
var added:Added;
public function Custom()
{
intializer=new Initializer();
addChild(intializer);
intializer.addEventListener(MouseEvent.CLICK, OnClicker);
addEventListener(CustomEvent.EVENT_CUSTOM, OnCatch);
}
private function OnClicker(event:MouseEvent):void
{
added=new Added();
added.x=300; added.y=300;
addChild(added);
}
private function OnCatch(event:CustomEvent):void
{
trace("hi");
removeChild(added);
}
}
}
event as file:
package
{
import flash.events.Event;
public class CustomEvent extends Event
{
public static const EVENT_CUSTOM="event1";
public function CustomEvent(type)
{
super(type, false, false);
}
}
}
and the movieclips as file:
package
{
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class Added extends MovieClip
{
var addedButton:AddedButton;
public function Added()
{
addedButton=new AddedButton();
addedButton.x=30; addedButton.y=30;
addChild(addedButton);
addedButton.addEventListener(MouseEvent.CLICK, OnClickie);
}
private function OnClickie(event:MouseEvent):void
{
dispatchEvent(new CustomEvent(CustomEvent.EVENT_CUSTOM));
}
}
}
Buttons use an empty class, This gives me this result: (top left corner for first button.)
http://www.fastswf.com/_EfGSoQ
Sorry for so much code, but custom events seem to require a lot of code.
The problem seems to be that you are listening for your custom event in the wrong place. You can address this several ways using event bubbling, the event's capture phase, or by listening for the event on the object that dispatches the event (the event target).
The Flash Event Model follows the W3C event model (used in the DOM/Javascript). When an event is dispatched, it goes through three phases: capture phase, target phase, and bubbling phase. It's described in the above link (in the "Event propagation and phases" section).
For performance reasons (my assumption), the capture and bubbling phases are not enabled by default.
Note you only need to do one of the 3 things below. I suggest using the event target, it's the easiest to understand. The others have their places and can be very useful, but you can do most everything w/the target phase.
How to use the target phase
In your document class remove this line from the constructor:
addEventListener(CustomEvent.EVENT_CUSTOM, OnCatch);
Remove it because we're going to listen for the event coming from the Added object directly (it's the event target). To do that change your code that adds the object in the document class:
private function OnClicker(event:MouseEvent):void
{
added=new Added();
added.x=300; added.y=300;
addChild(added);
added.addEventListener(CustomEvent.EVENT_CUSTOM, OnCatch);
}
How to use the capture phase
In your document class, add an additional parameter when adding the event listener to enable the capture phase:
addEventListener(CustomEvent.EVENT_CUSTOM, OnCatch, true);
This allows any parent of the event target to handle the event, before the target handles it.
How to use the bubbling phase:
To use the bubbling phase, your custom event object needs to "bubble". So you will need to modify the constructor in your custom event class:
public function CustomEvent(type)
{
super(type, true, false);
}
Here I've changed the second parameter in the call to super(), allowing the event to "bubble".
Since the event now bubbles back up the display list, any parent of the event target will also be able to listen for the event after the target has handled it.

Robotlegs - second dispatch does not work with addViewListener

I have a mediator created in Robotlegs, and its related view would dispatch two different kinds of events. When the mediator captures the event, it would just simply dispatch the event. The problem I ran into was that the first event is re-dispatched flawlessly, but the 2nd event was not dispatched.
However, if I manually assign a different handler to the 2nd event, the event is properly captured.
Below is the relevant code:
public class MyMediator extends Mediator
{
[Inject]
public var view:MyView;
public override function onRegister():void
{
super.onRegister();
addViewListener( SomeEventTypeA.COOL_EVENT, dispatch, SomeEventTypeA ); // This event is dispatched correctly
addViewListener( SomeEventTypeB.STUCK, dispatch, SomeEventTypeB ); // This one is not correctly dispatched
//A twist, if I uncomment the following code, the event is captured by its handler
//addViewListener( SomeEventTypeB.STUCK, view_stuck, SomeEventTypeB );
}
private function view_stuck( event:SomeEventTypeB ):void
{
//ah ha, this is called correctly if the above relevant line is uncommented
}
}
Found the cause:
The event needs to have a proper clone method in order to be re-dispatched correctly. See related link:
http://knowledge.robotlegs.org/kb/application-architecture/why-doesnt-my-event-trigger-the-command-it-is-mapped-to

How to access the variable "abc" in the following code structure

1) First of all I don't wanna use CustomEvent class. Some solution I am looking without using CustomEvent.
2) One of the solution can be having abc variable in ClassA. And then dispatching directly via ClassA ( rathar than saying classB.dispatchEvent() ). But still looking if there is some better solution than this.
//Frame1 code :
import flash.events.Event;
var classA:ClassA = new ClassA() ;
classA.addEventListener("hello", hello);
classA.init();
function hello(e:Event)
{
trace(e.currentTarget.abc); //<<<< NEVER EXECUTED
}
//classA
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class ClassA extends MovieClip
{
var classB:ClassB ;
public function ClassA()
{
classB = new ClassB();
}
public function init()
{
classB.dispatchEvent( new Event("hello"));
}
}
}
//classB
package
{
import flash.display.MovieClip;
public class ClassB extends MovieClip
{
public var abc:Number =123;
public function ClassB()
{
}
}
}
You are missing a couple key concepts before you can get your example to work. First you are dispatching the event on an instance of ClassB, however you are listening on an instance of ClassA. So, they have to be related in some way, in order for event to be properly orchestrated when it gets dispatched. One way to do that is to use event bubbling. One caveat to that is that native event bubbling only really works for DisplayObjects, but both of your classes inherit from MovieClip so thats not a big deal.
So the first thing, you have to understand how bubbling events work. A simplified explanation is that events start at the top of the display hierarchy and capture down the display tree towards the element, they are finally dispatched on the target, then they turn around and bubble back out in the opposite direction.
This means that your instance of ClassB has to be a child of ClassA. So the first thing you'll have to change is in your ClassA constructor:
public function ClassA()
{
classB = new ClassB();
addChild(classB);
}
Next, when you dispatch the event, you'll need to explictly say that its a bubbling event, otherwise it'll be triggered on the target, and neither capture nor bubble through the display stack.
public function init()
{
classB.dispatchEvent( new Event("hello", true));
}
The second argument of true sets the event to a bubbling event.
Finally you'll need to change your handler. Right now, it's using e.currentTarget, which isn't going to be what you expect in this case (usually it is, thought).
You have to understand the difference between e.target and e.currentTarget. e.target is the actual target of the event, independent of how its bubbling or capturing. e.currentTarget on the other hand is the element which is presently handling the event. So in your case e.currentTarget is an instance of ClassA (the instance that the event handler is actually attached to) and e.target is an instance of ClassB (the instance that the event was dispatched on). During the event lifecycle, e.currentTarget will change as the event moves around, but e.target should always be the same.
In this case, you want to reference the actual target of the event, not the element that is currently processing the event. So you need to change your handler to:
function hello(e:Event)
{
trace(e.target.abc);
}
And then it should work. You can find a working example here that encapsulates the changes I've described.
If these classes weren't DisplayObjects then you would have to take a different approach -- either by using a signal pattern or to manually listen for an retrigger the event inside ClassA.
First of all you are adding an event listener to classA but your classA init method is asking classB to dispatch an event and this is the reason why your code does not get executed. If you want to catch the hello event you should be doing something like
public function init()
{
this.dispatchEvent( new Event("hello"));
}
Or you should be registering the listener on classB (which is not in scope so no code suggestion).
In ActionScript the best approach to transfer information is to use custom events so my suggestion is to re evaluate your decision on custom events.

Is it possible to SIMULATE a mouse click using a mouse down and up events?

A previous question has gotten me thinking. Is it possible to simulate a MouseEvent.CLICK to get fired by just firing first a MOUSE_DOWN followed by a MOUSE_UP.
As per Adobe's doumentation.
"... For a click event to occur, it must always follow this series of events in the order of occurrence: mouseDown event, then mouseUp. The target object must be identical for both of these events; otherwise the click event does not occur. Any number of other mouse events can occur at any time between the mouseDown or mouseUp events; the click event still occurs." http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html#event:click
From my tests it shows that the CLICK event is NOT constructed from the ActionScript 3 event queue. Or is something wrong with the code?
See:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(backgroundColor="0xFFFFFF", frameRate="30", width="800", height="600")]
public class Test extends Sprite
{
private var spr:Sprite = new Sprite();
public function Test()
{
trace("Test()");
this.addEventListener(Event.ADDED_TO_STAGE,init);
}
public function init(e:Event):void
{
trace("init()");
spr.graphics.beginFill(0xFF0000);
spr.graphics.drawRect(0,0,200,80);
spr.graphics.endFill();
addChild(spr);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
spr.addEventListener(MouseEvent.CLICK, onClick);
}
private var tick:int = 0;
private function onEnterFrame(e:Event):void
{
if (tick == 1) spr.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_DOWN,true,false));
if (tick == 2) spr.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP,true,false));
if (tick == 3) spr.dispatchEvent(new MouseEvent(MouseEvent.CLICK,true,false));
tick++;
}
private function onClick(e:MouseEvent):void
{
trace("onClick() MouseEvent.CLICK dispatched");
}
}
}
I should get TWO 'onClick()' events instead of one.
The reason you cannot is that all three types are created by the plugin, and are not dependent upon each other.
MouseEvent.MOUSE_DOWN is fired as soon as you press on an interactive object.
MouseEvent.MOUSE_UP is fired as soon as you release the mouse, it does not depend upon the mouse click having started a MOUSE_DOWN within the same InteractiveObject.
MouseEvent.CLICK will only be fired when both events take place in the same object without the cursor leaving the object between the itnerval of mouse down and mouse up.
So you can see that there is a simple case, or two even, in which both MOUSE_DOWN and MOUSE_UP are fired, but CLICK is not called because the event is not a CLICK.
Furthermore, the ability to simply dispatch a MouseEvent.CLICK event makes it unnecesasry to create fake user interaction by firing multiple mouse events, when only one is called for. It would be awkward to have to track each object clicked in the mouse down listener, in order to check that the moue up should also trigger a click. You would also need to remove references when a ROLL_OUT event happened.
In short, the CLICK event is really a lot more than the MOUSE_DOWN and MOUSE_UP events. It is also managing that the events happened in succession and on the same display object without leaving the object. When that happens, and ONLY when that happens flash dispatches a CLICK event.
it's impossible, this code:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
/**
* ...
* #author www0z0k
*/
public class Main extends Sprite {
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.addEventListener(MouseEvent.CLICK, onClick);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onStageKeyDown);
}
private function onStageKeyDown(e:KeyboardEvent):void {
trace('pressed');
stage.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_DOWN));
stage.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP));
stage.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
private function onClick(e:MouseEvent):void{
trace('clicked');
}
}
}
outputs just:
pressed
clicked
after a key is pressed on the keyboard
not sure about this for flash. But when i was learning windows MFC and was clueless. What i did was that I sent WM_MOUSEDOWN followed by WM_MOUSEUP after a short delay. It did work and the button's visual states also changed - without any mouse click!
If I understand what you're asking then the answer is YES.
I am curious if I have over simplified the solution here especially after reading your code attempt. It is very simple to "simulate" a mouse click. The code below outputs two "I have been clicked" statements when the object is clicked and none when you mouse down then move out of the objects boundaries.
This class extended a MovieClip I created on the stage so I didn't have to code a box.
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class clickMe extends MovieClip {
public function clickMe() {
// constructor code
this.addEventListener(MouseEvent.CLICK, clicked);
this.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
}
private function clicked(e:MouseEvent):void{
trace("I have been clicked");
this.removeEventListener(MouseEvent.MOUSE_UP, clicked);
}
private function mDown(e:MouseEvent):void{
this.addEventListener(MouseEvent.MOUSE_UP, clicked);
}
}
}
In your code I believe the problem is that you are trying to run event listener dispatches through an "onEnterFrame" which will only ever fire one event per frame - never two. Also after testing your code I'm not sure what your were trying to accomplish with the "tick" variable because you never reset it. So the the MOUSE_UP event fires once (when tick = 2, unless your holding the mouse down) then none of the other dispatches will ever fire again.
Not quite sure why everybody's making these complex spikes. Or maybe I'm just overseeing something.
Anyway, here's a very easy way to check it:
import flash.events.MouseEvent;
stage.addEventListener(MouseEvent.CLICK, function(){
trace( 'clicked' );
} );
stage.dispatchEvent( new MouseEvent( MouseEvent.MOUSE_DOWN ) );
stage.dispatchEvent( new MouseEvent( MouseEvent.MOUSE_UP ) );
And the answer would be, "no, it's not possible"...
...and probably should be followed by a counter-question: WHY would I want to simulate a click event using a sequence of mousedown and mouseup, when I can dispatch a click event just as well?
Am I a button, having an existential crisis?
Or is it a question out of mere curiosity? But you know what happened to the cat... Right, but maybe it's schrödinger's cat, which means that at the end of this completely irrelevant train of thought, curiosity REALLY did and did NOT kill the cat.
Except if the cat's out of a box.
Then it probably just got wasted.
See, thinking out of the box can get you killed.

Flex event handler not working

I have created a custom event in flex 3.5. But the handler is not invoked. How to solve this or what is the way to debug this problem?
The Event class:
package com.saneef.worldlanguages.events
{
import flash.events.Event;
public class LanguageEvent extends Event
{
public static const LANGUAGE_SELECTED:String = "LanguageSelected";
public function LanguageEvent(type:String,languageid:String)
{
super(type);
this.langid = languageid;
trace("LanguageEvent: " + this.langid);
}
public var langid:String;
override public function clone():Event {
return new LanguageEvent(type, langid);
}
}
}
Dispatching:
private function functionOne():void
{
try{
dispatchEvent(new LanguageEvent(LanguageEvent.LANGUAGE_SELECTED,"STR"));
}
catch(e:Error)
{
trace(e.message);
}
}
In the Main application class, EventListener:
protected function application1_initializeHandler(event:FlexEvent):void
{
this.addEventListener(LanguageEvent.LANGUAGE_SELECTED,
application1_LanguageSelectionHandler);
}
The event handler function:
public function application1_LanguageSelectionHandler(event:LanguageEvent):void
{
trace("application1_LanguageSelectionHandler: " + event.langid);
populate_countrya3id_languages(event.langid);
}
Your code looks fine. Since I can't see the full source, here are my two thoughts on what may be going on:
Are you sure your addEventListener call is done before you dispatch the event? Add some trace to make sure the application1_initializeHandler prints before functionOne does.
Is your functionOne call in another different component than your main application? If so, you'll need to set your custom event's bubbles attribute to true in your event's super call.
public function LanguageEvent(type:String,languageid:String,bubbles:Boolean=True)
{
super(type, bubbles);
this.langid = languageid;
trace("LanguageEvent: " + this.langid);
}
See the flash.events.Event docs for the constructor call. Also, here's a quote about the bubbles argument explained here:
The bubbles property
An event is said to bubble if its
event object participates in the
bubbling phase of the event flow,
which means that the event object is
passed from the target node back
through its ancestors until it reaches
the Stage. The Event.bubbles property
stores a Boolean value that indicates
whether the event object participates
in the bubbling phase. Because all
events that bubble also participate in
the capture and target phases, any
event that bubbles participates in all
three of the event flow phases. If the
value is true, the event object
participates in all three phases. If
the value is false, the event object
does not participate in the bubbling
phase.
Based on your source code, it looks like you've seen the "Dispatching Custom Events" in the flex docs, but I'll link to it anyways for future/easy reference: http://livedocs.adobe.com/flex/3/html/help.html?content=createevents_3.html.
Also, check out http://www.adnandoric.com/2008/12/29/understanding-the-flex-event-propagation/ for a high-level overview of the event propagation system to try to get a better understanding of what's going on while developing.
Edit:
Based on your comments I'm guessing your functionOne call is in a separate class and your "main" application has an instance of this class. If that's so you'll want to attach your event listener on that instance and delegate it to your main's application1_LanguageSelectionHandler function... Like so:
protected function application1_initializeHandler(event:FlexEvent):void
{
this.theInstanceThatHoldsYourFunctionOne.addEventListener(LanguageEvent.LANGUAGE_SELECTED,
application1_LanguageSelectionHandler);
}