Access main stage from class definition file (as3) - actionscript-3

I'd like to access the stage of the main timeline from w/i a class that extends a movieclip. Basically, I have a button in the main timeline that makes a HUD appear. The HUD is an extended MovieClip class. When people click on a button in the HUD, I'd like to remove the object from the stage of the main MovieClip.
#curro: I think your confusion may come from the fact that I am running this code from a class definition file. Clicking on a button w/i this object should remove it from the DisplayList of the MainTimeline. Here's the code from the class definition file:
package classes {
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class Answers extends MovieClip {
public function Answers(){
listen();
}//constructor
//initiatlize variables
public var answersArray:Array = new Array();
private function listen():void {
submit_btn.addEventListener(MouseEvent.CLICK, function(e:MouseEvent){
answersArray.push(answer_txt.text);
e.currentTarget.parent.parent.stage.removeChild(this);
});//listen
}//listen
}//class Definition
}//package
trace(e.currentTarget.parent.parent) gets me the MainTimeline, and trace(e.currentTarget.parent.parent.stage) appears to return the main stage, but I cannot use removeChild w/o getting an error that I am trying to coerce the stage to be a DisplayObject (which it ought to be).
What's on the stage of the MainTimeline: A single button that, when clicked, adds an instance of the Answers class to the stage.
What's part of the Answers class that's not in the code?
I first created Answers as a MovieClip object in the main library. It has 3 parts:
a TextField named "answer_txt"
a "clear_btn" that clears the answer_txt
a "submit_btn" that submits the text of answer_txt and then removes the entire Answers object from the MainTimeline (at least, that's what I want it to do).

your class definition is really weird. Looks like a mixture of as2 and as3.
Try with this:
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.text.*;
import fl.controls.Button;
public class Answers extends MovieClip
{
public var answersArray:Array = new Array();
public function Answers()
{
submit_btn.addEventListener(MouseEvent.CLICK, remove);
}
private function remove(e:MouseEvent)
{
answersArray.push(answer_txt.text);
this.parent.removeChild(this);
}
}
}
This works on my computer. Your code doesn't. I think it has something to do with the listen method. The class isn't still instatiated and you are making it work.

Hey, I can't make head or tail from the code. Where does submit_btn come from? Is it a property of the class? What about answer_txt?
You don't need to access e.currentTarget... to remove "this" simply:
this.parent.removeChild(this);

If you add that movieclip to the stage then you can access the stage from that class as simple as in the document class
stage
Otherwise you can't access stage from that class. But you can access it by sending the stage as argument when instantiate the class.

Related

AS3 Using a custom event to change property of different class

In the game that I am making, you choose a shape, and then on the next screen choose a color. The shape selector works fine and loads one of 6 'shape' movie clips into the next stage of the game. On this stage, I have buttons to control color. Im trying to make the buttons change the color of the movieclip by launching a custom event. This would then be detected by a listener within the class for each movieclip.
So far this is my code:
The screen that contains the color change button:
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class ColorSelector extends MovieClip
{
public function ColorSelector()
{
charcoal.addEventListener (MouseEvent.CLICK, onClickCharcoal );
}
public function onClickCharcoal (mouseEvent:MouseEvent): void
{
dispatchEvent (new ColorEvent (ColorEvent.CHARCOAL) );
trace ("click")
}}
The custom event class:
package
{
import flash.events.Event;
public class ColorEvent extends Event
{
public static const CHARCOAL:String = "charcoal";
public function ColorEvent( type: String )
{
super ( type );
}
}}
The movieclip being acted upon:
package {
import flash.display.MovieClip;
public class Gobbert extends MovieClip {
public function Gobbert()
{
this.addEventListener (ColorEvent.CHARCOAL, makeCharcoal)
}
public function makeCharcoal (colorEvent: ColorEvent) :void
{
this.alpha = .5
}
}
It seems to me like the event is not getting through to the class with the listener. I could really use a fresh pair of eyes to help me figure out whats going on. The program doesn't give me any error, just doesn't do much else either. Thanks in advance!
You are missing the bubbles parameter on the constructor. If omitted it defaults to false. The call to super on the custom event should be:
super(type, bubbles, cancelable);
You will want to pass bubbles in as true via addEventListener function call or hard code inside the custom event constructor.
Also make sure the target (instance of Gobbert) movie clip is on the event bubbling path which means the ColorSelector has to be a child of the display list of Gobbert. If your display list is not set up this way you may want to rethink your approach and have the event propagate from the selector to a common parent and then set the color on Gobbert through that common parent.

ActionScript 3 Access Manually Added MovieClip Instance From A Class (not Document Class)

If I have an instance named "btnExit" which I added manually to the Main Timeline, I can refer to it from my Document Class simply by typing its name, eg.
package{
public class Engine extends MovieClip{
public function Engine(){
trace(btnExit.x);
}
}
}
But now I have an instance that is nested in another movieclip, and I want to access it from a class (not a Document Class).
Let's say I have "Menu" movieclip on my library.
Then I manually drag a "ButtonExit" button to the "Menu" movieclip timeline, I named the instance "btnExit", so "btnExit" is the child of "Menu" movieclip.
The "Menu" movieclip will be added dynamically by code to the main timeline.
Now I want to access the "btnExit" from "Menu" class file, so I write these codes.
The Document Class:
package{
public class Engine extends MovieClip{
public var menu:Menu;
public function Engine(){
menu = new Menu();
addChild(menu);
}
}
}
The Other Class:
package{
public class Menu extends MovieClip{
public function Menu(){
trace(btnExit.x);
}
}
}
But I got error #1009 (null object reference) for unable to access btnExit;
Can anybody help me, pleaseee?
Make sure that the instance of ButtonExit exists on every frame of the menu timeline and that it's instance named appropriately on every frame or write an if statement to only run your code if the Button is currently on the correct frame.
Every frame when the menu clip animates it's going to re instantiate everything on the frame, so if your second/third/fourth/etc frame doesn't have a clip named btnExit it's going to throw an error when the constructor is called for that frame.

Adding to Stage in ActionScript 3 from a .as file

Note: Yes, I know that similar questions have been asked before. However, after following the answers in such questions I'm still stuck and can't find a solution to my problem.
I'm having a problem which requires adding DisplayObjects to the Flash stage. Since I have to Display elements of several different classes, I decided to create a class to work as an intermediary between the .as files and the addChild function called "Displayer" as shown below:
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.Stage;
public class Displayer extends Sprite //I read somewhere that DisplayObject
//as an extension can't be used for this, so Sprite will have to do.
{
private var _stage:Stage;
function Displayer()
{
_stage = new Stage;
}
public function displayElement(displayable:DisplayObject)
{
_stage.addChild(displayable);
}
}
}
I compile it and there appears a problem that I don't understand: Error #2012: Can't instantiate Stage class. Evidently, something in this code is either missing or out of place, but since it's so straightforward I fail to see what the problem can be. I'm sure that it's not very complicated, I probably just need an outsider's perspective.
The Stage object is not globally accessible. You need to access it through the stage property of a DisplayObject instance.
refer a following docs.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Stage.html
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.Stage;
public class Displayer extends Sprite
{
var isAddedToStage:Boolean;
public function Displayer()
{
if(stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
isAddedToStage = true;
}
public function displayElement(displayable:DisplayObject):void
{
if(isAddedToStage)
this.stage.addChild(displayable);
}
}
}
You don't instantiate the Stage class, as the error says. Just like you cannot instantiate the DisplayObject class (which is why you have to extend Sprite).
Basically, you have two options here:
1) You add the child from a DisplayObjectContainer instance.
var displayerInstance:Displayer = new Displayer();
this.addChild( displayerInstance );
You would run this from a DisplayObjectContainer object that has already been added to the global stage. There is only a single stage in every project, even if you embed SWFs, the stage property of the SWF is actually the stage property of the top level application. So if you have this Displayer instance nested inside a class which is nested inside another class that is created in your main application, you would have to run "addChild" in each of those classes to get the Displayer to show.
2) You cheat. This is not recommended, at all. Basically, you pass in the stage object of an object when you instantiate the Displayer class.
var displayerInstance:Displayer = new Displayer( this.stage );
public function Displayer( stage:Stage ) {
this.stage = stage;
if ( this.stage ) {
this.stage.addChild( this );
}
}
This is a method that is good for adding Singletons to the stage (except there is not constructor for a Singleton). I created a profiler just before Christmas that was a Singleton (And later found Scout, damnit) that used this method for adding things to the stage when appropriate.
Again, that second option is not recommended for this situation, but it is a possibility.
As an aside, you should never add things directly to Stage, unless there is a clear reason for doing so (such as a popup). You should follow the display list methodology, where a DisplayObjectContainer adds another DisplayObject or DisplayObject container as a child and so on and so forth so that they are all connected to the TopLevelApplication.
Ok, I think instantiating a stage class won't do because as the as3 documentation says: "The Stage object is not globally accessible. You need to access it through the stage property of a DisplayObject instance."
You should instead pass a reference to the Stage object to your Displayer class and you can get a reference to the stage object, as the docs say, via a display object instance.
So the constructor might now look like:
function Displayer( stage:Stage )
{
_stage = stage;
}
Assuming that the object which instantiates your Displayer is a child of the stage you can instantiate the Displayer by
displayer = new Displayer( stage );
If you use this approach there is no need for the Displayer class to extend anything or be added to the stage ( which is required btw in the approach of bitmapdata.com ).
There is always a simple solutions.if you need to add a child element into a stage from your class you can just pass the stage into your class as a object and add the child element into it, i did this for adding an image into my stage like this.
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.display.Bitmap;
public class ImageLoader extends Sprite{
private var stageObj:Object; //create local variable to refarance stage
public function loadeimage(StageObject:Object, Url:String){ //StageObject will bring the stage refarance into the class
var reQuest:URLRequest = new URLRequest(Url);
loader.load(reQuest);
stageObj=StageObject; //make local refarance for stage inside the class
var image:Bitmap;
image=Bitmap(loader.content);
image.x = 100;
image.y = 100;
stageObj.addChild(image); // add whatever object into stage refarance and this means the real stage..
}
}
}
only the things with comments are important and you can save this file as ImageLoader.as and import it and use it like this.
import ImageLoader;
var IL:ImageLoader = new ImageLoader();
IL.loadeimage(this,"img.jpg");
its simple as that. i think this is what you have search for... good luck. (you can pass any container or parant container this or this.stage it doesn't matter your child will be a part of it.

How to implement custom google search for ActionScript 3.0

I was trying to implement custom google search in my course-ware that developed in flash. I define a class named 'Main' (Main.as) and put my search code there. But the problem is, that Main class has a conflict with the other codes containing in my course-ware (i've combo box & other basic navigation in course-ware). i have no idea how to resolve it. is there any way to put that code in timeline layer? help please.. thanks. here is my Main class:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.net.navigateToURL;
import flash.net.URLRequest;
public class Main extends Sprite
{
public function Main():void
{
searchButton.addEventListener(MouseEvent.MOUSE_UP, google);
addEventListener(KeyboardEvent.KEY_DOWN, google);
searchTerms.addEventListener(MouseEvent.MOUSE_DOWN, selectText);
}
private function google(e:*):void
{
if(e.type == "mouseUp")
{
navigateToURL(new URLRequest("http://www.google.com/search?q=" + searchTerms.text));
}
else if(e.keyCode == Keyboard.ENTER)
{
navigateToURL(new URLRequest("http://www.google.com/search?q=" + searchTerms.text));
}
}
private function selectText(e:MouseEvent):void
{
searchTerms.setSelection(0, searchTerms.length);
}
}
}
From what you shared & the messages here, I assume you are trying to add code through the flash IDE while at the same time having a document class called Main, for your application.
There are lots of ways you may get around this.
Assuming you want keep your timeline code unaltered while adding an instance of the Main class :
Add an empty movie clip to the library, say SearchClass.
Go to properties of the movie clip & click export for actionscript.
Set the class to Main. Do make sure where Main.as lies outside with respect to the fla.
Add this movieclip onto the stage, on any frame or layer.
Do remember to clear the document class field.
As a side note, You should also rename the class Main to something meaningful, like SearchClass.
If you wonder about setting the class vs base class,
We use base class only when you wish to extend the features of the class (by adding UI elements for eg).
You could also simply call the class directly from the timeline code as :
var main:Main = new Main();
addChild(main);
Just make sure the Main.as file lies next to the fla... ie make sure the path is available to compiler.

Detecting when an object gets added to a movieclip

Alright, so I'm trying to figure out when a child is added to a movieclip "x", and handling/detouring this operation from within this "x" movieclip.
I tried overriding addChild and addChildAt at with no prevail. The movieclips that are placed on the stage via flash still don't trigger addChild or addChildAt. However, tracing this.numChildren shows '2' correctly.
Any hints?
You can add an event listener for the "added" event for the x movie clip.
x.addEventListener(Event.ADDED, addHandler);
function addHandler(e:Event){
// your code here
}
This link may explain it better:
AS3.0 – Event.ADDED and Event.ADDED_TO_STAGE
The documentation is also a good resource:
flash.events.Event
You can override the default methods of a movieclip by doing the following:
Create a class to extend a movieclip:
package {
import flash.display.*;
public class SuperMovieClip extends MovieClip {
public function SuperMovieClip() {
// constructor code
super();
}
override public function addChild(child:DisplayObject):DisplayObject {
trace("Hello, I am overriding add child");
// still perform the default behavior but you can do what ever you want.
return super.addChild(child);
}
}
}
Then in Flash create a new movieclip, and make sure it is marked as Enable for ActionScript. The Class should be any name you want, but the base class needs to be SuperMovieClip (or the name you chose for your extended class) See image:
Now when any stage clip is created of this base type (regardless if it's in the IDE or through code) it will be of type SuperMovieClip and anytime addChild is called it will override the original function.
For example, I placed an instance of this mc from library onto the stage at design time and compiled it using the following code on the timeline:
import flash.display.Sprite;
stage_mc.addChild(new Sprite());
And it output Hello, I am overriding add child