accessing GUI-created elements in a class definition file in AS3 (Flash CS4) - actionscript-3

I've used the GUI to create a rectangle that I turned into a button symbol (SimpleButton). I then edited the button so that it had 4 different button states and a text layer on top. I then created a class definition file for this object so that I could dynamically change the label text (the text layer) when adding instances of this button to the stage.
I was able to create and link a class file (DynamicButton.as) just fine, but when I try to access the text field that I created on the button, I get the error:
"Access of possibly undefined property btnLabel through a reference with static type com.examples:DynamicButton."
when i couldn't get that to work, I decided I'd try adding the TextField directly within the class definition file, using the following code:
package com.examples
{
import flash.display.Sprite;
import flash.display.SimpleButton;
import flash.text.TextField;
public class DynamicButton extends SimpleButton
{
public function DynamicButton(btnText:String="Click Me")
{
placeText();
labelText.text = btnText;
}
//property variables
//create a text box to hold the button label
private var labelText:TextField = new TextField();
//create a displayObject to hold the text
private var labelSprite:Sprite = new Sprite();
private function placeText():void {
labelText.width = this.width;
labelText.height = this.height;
labelText.x = this.x;
labelText.y = this.y;
labelText.visible = true;
labelSprite.addChild(labelText);
this.parent.addChild(labelSprite);
}
}
}
The problem is that I can't seem to add the TextField to the SimpleButton, as it's not a display object. So, I tried adding it to the parent of the simple button (and I figured, I'd just place it exactly above the button). But then I get a "null object reference." error.
So, I have two questions
is there a way to access GUI-created elements from w/i a class definition file?
How would I add the TextField to the button using only AS3 inside of a my class definition file?

OK, it took a few days and some introspection, but it seems that the problem I've having stems from the fact that you cannot add children to a SimpleButton. I changed my class definition to extend a MovieClip, then created a function named "listen()" that I called when constructing the object that added listeners for the "over","down", and "out" mouse states, so as to imitate a simple button. I also had to put a "stop()" command in the constructor, so that each button wouldn't keep cyclying through all the states. The final class definition looks like this:
package com.examples
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class DynamicButton extends MovieClip
{
public function DynamicButton(btnText:String="Click Me")
{
stop();
this.btnText_btn.text = btnText;
listen();
}//constructor
private function listen():void {
this.addEventListener(MouseEvent.MOUSE_OVER,function(){
gotoAndStop(2);
}//anon mouseover fcn
);
this.addEventListener(MouseEvent.MOUSE_DOWN,function(){
gotoAndStop(3);
}//anon mousedown fcn
);
this.addEventListener(MouseEvent.MOUSE_OUT,function(){
gotoAndStop(1);
}//anon mouseout fcn
);
}
}//class definition
}//package

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.

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.

What I might be doing wrong in this code?

I am relatively new to flash. I am trying to create a square grid and add it to the movie. When I open the actionscript panel by pressing F9 and when I type the following code,
var square:SquareClip = new SquareClip();
addChild(square);
Things are working fine (the squareclip is appearing in the movie).
Instead when I do this however, I deleted the above code and just create a new instance of Main,
new Main
and inside Main.as
package{
//----
//IMPORT
//
import flash.display.*;
import flash.events.*;
import flash.text.*;
//Class creation
public class Main extends MovieClip {
//PROPERTIES
public function Main():void {
layout_in_grid();
}
private function layout_in_grid():void{
trace("layout_in_grid");
//create a new Square
var square:SquareClip = new SquareClip();
addChild(square);
trace("Square added");
}
}
}
And when I run the code, my square is not coming. I am doing something wrong very basically. Please help me.
You need to add Main to the displaylist:
var myMain : Main = new Main();
addChild(myMain);
You could also set Main as your document class.
#Mattias is correct. But you should set this as the Document Class as he suggested - When you've selected the stage, in the properties there will be an input box allowing you to enter the name of the class.
If your file is in the same location as the FLA and called 'Main.as' you enter in the box:
Main
If the file is within a folder structure e.g. com/company/projects/Main.as - enter:
com.company.projects.Main
--
Kudos on learning the OOP way!

Access main stage from class definition file (as3)

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.

ActionScript 3.0 stageWidth in custom Class

How do I access Stage Class properties in Costum Class?
Class:
package {
import Main;
import flash.events.*;
import flash.display.Sprite;
import flash.display.Stage;
public class Run extends Sprite {
var obj:a1_spr;
public function Run() {
runAssets();
}
private function runAssets():void {
obj = new a1_spr()
addChild(obj);
obj.x = stage.stageWidth/2;
}
}
}
Output:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
To expand on what Joel said, and put it into context:
Every display object has a .stage property, but that property is null until you add you display object onto the display list. So during construction, you will never be able to access it, (because it gets added afterwards)
The event ADDED_TO_STAGE gets fired when you add your object to the stage, ltting you know that the .stage property is now populated. After that happens you can access the stage from anywhere in you object.
Hope that clarifies things for you.
this.addEventListener(Event.ADDED_TO_STAGE, handleAdedToStage)
private function handleAddedToStage(event:Event):void
{
this.runAssets()
}
private function runAssets():void
{
obj = new a1_spr();
addChild(obj);
obj.x = this.stage.stageWidth/2;
}
You aren't going to have access to the stage in the constructor (unless you inject the stage into the class). Sprite has a stage property.
when flash compiles the fla assets with your .as files, there's no stage. so the code is initiated as preparation for your documentclass, you have to listen to if there's a stage so it can be rendered.
that's why you listen to ADDED_TO_STAGE , to check it's actually in the display list.
This problem occurs for all display objects, since they must be added to the display list when there's an actual stage.
get used to add that listener, and check for a stage. specially when working in a team and your doing your own components in a larger project.