09-03-2006, 12:20 PM
|
#196
|

 |
San Francisco, CA (USA) |
|
 |
17,426 |
|
|
Detecting Addition to or Removal from Stage
The added and removed events in ActionScript 3 let you detect when a display object is added to or removed from another display object container. These events, however, only work for the immediate parent of that display object. This means a sprite instance can be removed from the stage and not know it if its parent was removed from the stage and it continues to exist within the parent. Currently, there is no way to detect when this happens with Flash Player 9.0. The following StageDetection class ( com.senocular.events.StageDetection), can be used to do so, however:
Code:
package com.senocular.events {
import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.Dictionary;
/**
* StageDetection
* Lets a DisplayObject know when its been added to
* a display list attached to the stage.
*
* Usage:
* // used in the constructor where addedToStage and removedFromStage
* // are event handler methods
* var stageDetect:StageDetection = new StageDetection(this);
* stageDetect.addEventListener(StageDetection.ADDED_TO_STAGE, addedToStage);
* stageDetect.addEventListener(StageDetection.REMOVED_FROM_STAGE, removedFromStage);
*/
public class StageDetection extends EventDispatcher {
protected var target:DisplayObject;
protected var parents:Dictionary;
protected var detect:String;
public static const ADDED_TO_STAGE:String = "addedToStage";
public static const REMOVED_FROM_STAGE:String = "removedFromStage";
/**
* Constructor
*/
public function StageDetection(targetObject:DisplayObject) {
target = targetObject;
// determine whether need to detect for added or removed
detect = (target.stage == null) ? Event.ADDED : Event.REMOVED;
// update parent listeners for detect events
updateListeners();
}
/**
* updates listeners from which ADDED and REMOVED events are to be received
*/
protected function updateListeners(newDetect:String = null):void {
// cleanup old listeners in parents
if (parents) {
for (var key:Object in parents) {
key.removeEventListener(detect, stageCheck, false);
}
}
// new event to detect if given
if (newDetect) detect = newDetect;
// set up detect event with current parents
parents = new Dictionary(true);
var parent:DisplayObject = target;
while (parent) {
parent.addEventListener(detect, stageCheck, false, 0, true);
parents[parent] = true;
parent = parent.parent;
}
}
/**
* event handler for ADDED and REMOVED events checking for stage access
*/
protected function stageCheck(evt:Event):void {
// only check for originating object
if (evt.target != evt.currentTarget) return;
// evt.type either ADDED or REMOVED
switch(evt.type) {
// parent added to another display object
case Event.ADDED:
// stage available, added to stage
if (target.stage != null) {
// added to stage, dispatch event, update
dispatchEvent(new Event(ADDED_TO_STAGE));
updateListeners(Event.REMOVED);
// stage inaccessible, added to some other display object not on stage
} else {
// display list has changed, update parent listeners
updateListeners();
}
break;
// parent removed from stage
case Event.REMOVED:
// removed from stage, dispatch event, update
dispatchEvent(new Event(REMOVED_FROM_STAGE));
updateListeners(Event.ADDED);
break;
}
}
}
}
Note: As of Flash Player 9.0.28.0, Event.ADDED_TO_STAGE ("addedToStage"), and Event.REMOVED_FROM_STAGE ("removedFromStage") are built into the player.
__________________

|
|
|
09-03-2006, 01:02 PM
|
#197
|

 |
San Francisco, CA (USA) |
|
 |
17,426 |
|
|
Event Phases and Event Capturing
Along with event propagation in ActionScript 3 comes different phases of events with display objects. With propagation, you have events being propagated from display objects to other display objects, such as mouse click events being propagated from children to their parents. This lets clicks within children objects to be recognized by parents (since children make up the contents of their parents, its only natural for the parent to also have those same events). The phases of such an event represent the progression of the event as it makes its way through the parent and child objects.
Events actually start with parent objects (phase 1: capturing), starting with the top most parent (stage) and making its way down to the child where the event originated (phase 2: at target). Then after reaching the child it makes its way back up through all the parents again (phase 3: bubbling).
Phase 1: Capturing
Code:
event
+---------|----+
| parent | |
| +------V-+ |
| |child | |
| | | |
| +--------+ |
+--------------+
Phase 2: At Target
Code:
+--------------+
| parent |
| +------ -+ |
| |child | |
| |event X | |
| +--------+ |
+--------------+
Phase 3: Bubbling
Code:
+---------^----+
| parent | |
| +------|-+ |
| |child | | |
| | event| | |
| +--------+ |
+--------------+
The default listening behavior for addEventListener is to listen for both phases 2 and 3, the at target and bubbling phases. This lets your listener recieves events the target object recieves as well as all of those that bubble up from its children. Note: the bubbling phase does not include the event target, but since addEvent listener listens to both phases by default, it includes the target (at phase) with its default bubbling listening.
If you would want to listen for the capturing phase, addEventListener provides a third argument that allows you to do so.
Code:
var useCapture:Boolean = true;
target.addEventListener("event", listener, useCapture);
This, instead, allows a listener to receive events during the capture phase of an event. Unlike when not using capture (default behavior of addEventListener), using capture does not allow the listener function to be called when the event reaches the target at the at target phase. It only listens for the capturing phase.
To listen to all phases, you would use addEventListener twice
Code:
target.addEventListener("event", listener, true); // capturing
target.addEventListener("event", listener, false); // at target and bubbling
__________________

|
|
|
09-03-2006, 01:25 PM
|
#200
|

 |
San Francisco, CA (USA) |
|
 |
17,426 |
|
|
Determining Event Phase
Event listener functions in ActionScript 3 can dermine what phase they're being called from using the Event object ( flash.events.Event) that gets passed into function during the event. Each Event instance contains an eventPhase property that relates to the current phase of the event.
The eventPhase property is an integer value representing the phase. These values are contained as static properties of the EventPhase class ( flash.events.EventPhase). They are as follows: - EventPhase.CAPTURING_PHASE
- EventPhase.AT_TARGET
- EventPhase.BUBBLING_PHASE
Example:
Code:
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x4080A0);
circle.graphics.drawCircle(50, 50, 25);
addChild(circle);
circle.addEventListener(MouseEvent.CLICK, clickCircle);
circle.addEventListener(MouseEvent.CLICK, clickCircle, true);
stage.addEventListener(MouseEvent.CLICK, clickStage);
stage.addEventListener(MouseEvent.CLICK, clickStage, true);
function clickCircle(evt:MouseEvent):void {
trace("clickCircle: " + getPhaseName(evt.eventPhase));
}
function clickStage(evt:MouseEvent):void {
trace("clickStage: " + getPhaseName(evt.eventPhase));
}
function getPhaseName(phase:int):String {
switch(phase) {
case EventPhase.CAPTURING_PHASE:
return "Capturing Phase";
case EventPhase.AT_TARGET:
return "At Target Phase";
case EventPhase.BUBBLING_PHASE:
return "Bubbling Phase";
}
return "Error: No Phase Detected";
}
Clicking around on the circle you can see the different phases as they occur within the movie. Note that the using capturing with addEventListener on the circle does nothing in this example since the circle has no children that would allow an event to pass through the circle for a capture phase.
clicking on circle output
Code:
clickStage: Capturing Phase
clickCircle: At Target Phase
clickStage: Bubbling Phase
clicking on stage output
Code:
clickStage: At Target Phase
__________________

|
|
|
09-03-2006, 01:56 PM
|
#202
|

 |
San Francisco, CA (USA) |
|
 |
17,426 |
|
|
Preventing Event Propagation
If you want to prevent an event from propagating further, you can stop it from doing so within an event listener using stopPropagation() ( flash.events.Event.stopPropagation()) or stopImmediatePropagation() ( flash.events.Event.stopImmediatePropagation()). These methods are called from the Event objects passed into event listeners and essentially stop the event from happening - at least past that point.
stopPropagation prevents any objects beyond the current from recieving the event, and this can be within any phase of the event. stopImmediatePropagation does the same but also takes the extra step of preventing additional events within the current target receiving the event from happening too. So where as stopPropagation would prevent sprite A's parent from receiving the event, stopImmediatePropagation would prevent sprite A's parent as well as any other listeners listening to sprite A from receiving the event.
Example: toggle between using stopPropagation and stopImmediatePropagation
Code:
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x4080A0);
circle.graphics.drawCircle(50, 50, 25);
addChild(circle);
circle.addEventListener(MouseEvent.CLICK, clickCircle1);
circle.addEventListener(MouseEvent.CLICK, clickCircle2);
stage.addEventListener(MouseEvent.CLICK, clickStage);
function clickCircle1(evt:MouseEvent):void {
evt.stopPropagation();
// evt.stopImmediatePropagation();
trace("clickCircle1");
}
function clickCircle2(evt:MouseEvent):void {
trace("clickCircle2");
}
function clickStage(evt:MouseEvent):void {
trace("clickStage");
}
Click the circle and see how the event is stopped with each method. stopPropagation prevented the stage from receiving the event while stopImmediatePropagation also prevented clickCircle2 from recognizing the event
normal output
Code:
clickCircle1
clickCircle2
clickStage
stopPropagation output
Code:
clickCircle1
clickCircle2
stopImmediatePropagation output
__________________

|
|
|
09-03-2006, 02:13 PM
|
#203
|

 |
San Francisco, CA (USA) |
|
 |
17,426 |
|
|
Global Events
Sometimes in ActionScript you'll want to determine when an event happens globally, whether it starts on this object or that object or even no objects. For mouse clicks, ActionScript 1 and 2 had onMouseDown and onMouseUp events which were called globally despite the location of the mouse and which object it was over. If the mouse was clicked, these events would fire. In ActionScript 3, these events now only relate to mouse events specific to the object under the mouse. A normal sprite would not receive the mouseUp event if the mouse was over an empty area of the stage when the mouse was released.
To get these events to be recognized globally within ActionScript 3, you will need to have to use event listeners with the Stage object. Since the stage is the end parent of all display objects, all events pass through the stage.
Now, one might think a simple use of addEventListener with a listener function would be all you need, but its not that easy. What happens when someone listens for an event like mouseDown for a sprite and then stops propagation for that event? Then the event would never bubble up to reach the stage. However, the event would still reach the stage in the capturing phase so if a listener is set for the stage using capture, it will be recognized before it even reaches the target. This, however, does not account for instances where the stage itself was clicked. For that, you would need to use addEventListener twice for the stage, one for captures and one to get the at target phase of the event if the stage is clicked. The only problem with this is that if an instance on the stage is clicked and it doesn't stop propagation, the stage would receive the event twice, once during capture and once during bubbling. To prevent this, you can just have your listener function only react to the capturing and at target phases by checking the eventPhase property of the Event instance passed to it.
Example:
Code:
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x4080A0);
circle.graphics.drawCircle(50, 50, 25);
addChild(circle);
// using stage for a global mouse up
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp, true);
function mouseUp(evt:MouseEvent):void {
// only care about capturing and at target phases
if (evt.eventPhase == EventPhase.BUBBLING_PHASE) return;
trace("global mouseUp");
}
// circle stops propagation in its mouse up
circle.addEventListener(MouseEvent.MOUSE_UP, mouseUpCircle);
function mouseUpCircle(evt:MouseEvent):void {
trace("mouseUpCircle");
evt.stopPropagation();
}
Even though the circle here stops propagation of the event, the stage is still able to receive the event because it uses the capturing phase.
click stage output
click circle output
Code:
global mouseUp
mouseUpCircle
__________________

|
|
|
09-03-2006, 02:40 PM
|
#204
|

 |
San Francisco, CA (USA) |
|
 |
17,426 |
|
|
Detecting a mouseUp Outside
Unlike ActionScript 1 and 2, there is no onReleaseOutside event for ActionScript 3. mouseDown (Event.MOUSE_DOWN) and mouseUp (Event.MOUSE_UP) events only fire for display objects when the mouse is over the display object. The only way to detect a mouseUp outside is to detect a global mouseUp after the target instance recieves a mouseDown. If the target of that mouseUp event is then not the object originally within the mouseDown, you have a mouseUpOutside. To handle a global mouseUp, you would check for mouseUp events coming from the stage.
The easiest way to go about this is to define one mouseDown event handler for your desired object, then, in that handler, define the stage mouseUp handler. stage access shouldn't be a problem in the mouseDown since for the user to click on the target object, it would have to be in the display list, so stage access is not something to worry about. The mouseUp handler will fire when the mouse is released for the stage, and this means anywhere, even if the mouse is not within the Flash movie. Once that happens, you can check the event.target to see if the mouseUp is happening for your original object (be sure to also check instances within it) or something else such as the stage or another display object.
Example:
Code:
// create a circle to click
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x4080A0);
circle.graphics.drawCircle(50, 50, 25);
addChild(circle);
circle.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
function mouseDown(event:MouseEvent):void {
// down, now check for global mouseUp
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
}
function mouseUp(event:MouseEvent):void {
if (event.target == circle || circle.contains(event.target)){
// mouse is up over circle (onRelease)
// (if circle is not a DisplayObjectContainer,
// you do not need to use the contains check)
}else{
// mouse is up outside circle (onReleaseOutside)
}
// be sure to clean up stage listener
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
}
__________________

|
|
|
09-06-2006, 11:05 AM
|
#209
|

 |
San Francisco, CA (USA) |
|
 |
17,426 |
|
|
Flash 9: Document Class
ActionScript 3 with Flash 9 lets you specify a "Document Class" (aka Application class) for the main timeline. This represents the class of the root object - the display object in which (essentially) all other display objects are placed.
You can set the Document class in the Document Class option of the Property Inspector for a document with nothing selected. You can also set the Document Class in the ActionScript 3 Settings dialog using File > Publish Settings > Flash [Tab] > Settings... [Button (for ActionScript 3)]. When defining the Document class, you simply provide the name of the class which is to pose as the class for your document. Note: This class should exist within your class path.
The Document Class for Flash needs to extend Sprite or any subclass of Sprite ( flash.display.Sprite) to be valid. If you use the main timeline for ActionScript at all in Flash, you would want your document class to extend MovieClip ( flash.display.MovieClip) since MovieClips, unlike Sprites, support frames.
A document class should also be public (along with its constructor which is inherently public). A non-public class will result in an error when you publish your movie.
When published from Flash, SWF meta tags within Document Classes are ignored and the settings within Flash are used.
Unlike other display object classes you make, the stage property of a Document class will always be accessible since the document class is inherently a child of the stage. Similarly, if you place any objects on the main timeline in Flash, the will already be children of the Document class when its instantiated.
Example of a Document class:
Code:
package {
import flash.events.Event;
import flash.display.MovieClip;
public class CustomDocument extends MovieClip {
public function CustomDocument() {
addEventListener(Event.ADDED, checkChildren);
checkChildren(new Event("initialize"));
}
private function checkChildren(evt:Event):void {
// only allow one child in root
if (numChildren > 1) {
throw (new Error("This movie can have only one child instance"));
}
}
}
}
This class only allows one child. If more are added, an error is thrown. Notice that the checkChildren method is also automatically called in the constructor since its possible that objects could have been added to the timeline within Flash which would have been before the added event listener was created.
__________________

|
|
|
09-07-2006, 02:05 AM
|
#210
|
|
|
Will the following code run? or is it somthing more I need to code?
I copy pasted the following code in the actions panel and tested the movie.
It gave a compile error: 1037: Packages cannot be nested.
Output window: ReferenceError: Error #1065: Variable MainTimeline is not defined.
Am i doing somthing wrong?
Quote:
|
Originally Posted by mathew.er
So that example at livedocs makes it pretty clear... "stage" is a global object allowing you to view and change its properties or to register events with it.
ActionScript Code:
package {</p>
<p> import flash.display.Sprite;</p>
<p> import flash.display.StageAlign;</p>
<p> import flash.display.StageScaleMode;</p>
<p> import flash.events.Event;</p>
<p> </p>
<p> public class StageExample extends Sprite {</p>
<p> </p>
<p> public function StageExample() {</p>
<p> stage.scaleMode = StageScaleMode.NO_SCALE;</p>
<p> stage.align = StageAlign.TOP_LEFT;</p>
<p> stage.addEventListener(Event.ACTIVATE, activateHandler);</p>
<p> stage.addEventListener(Event.RESIZE, resizeHandler);</p>
<p> }</p>
<p> </p>
<p> private function activateHandler(event:Event):void {</p>
<p> trace("activateHandler: " + event);</p>
<p> }</p>
<p> </p>
<p> private function resizeHandler(event:Event):void {</p>
<p> trace("resizeHandler: " + event);</p>
<p> trace("stageWidth: " + stage.stageWidth + " stageHeight: " + stage.stageHeight);</p>
<p> }</p>
<p> }</p>
<p>}
@fabiopb: Why? Isnt this just a sign, that flash goes on pretty well? If your worried anout the Adobe Flash application itself, then you dont need to be... Flex is just for something else than Flash. It wont also disappear from the Internet as everybody has the plugin, people are used to use it and it still has great potential.
|
Last edited by v_gyku; 09-07-2006 at 03:36 AM..
|
|
|
|
Currently Active Users Viewing This Thread: 6 (0 members and 6 guests)
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 10:55 PM.
|
|