Actionscript 3 addChild problems - actionscript-3

The error messages from FlashDevelop are rather difficult to translate.
I'm using addChild in several situations, generally with no problems. However, every once in a while I get:
Error: Call to a possibly undefined method addChild.
However, the exact same code works in other classes, and I am importing exactly the same files. Obviously addChild is not an undefined method! Here's the code- works in one module, doesn't work in another.
public var artist:Loader;
public var artistName:Loader;
public function SceneTJ():void {
artistName = new Loader();
artistName.load(new URLRequest("images/artistname.jpg"));
artist = new Loader();
artist.load(new URLRequest("images/artist.jpg"));
artistName.x = artistName.y = 0;
artist.x = 0;
artist.y = 0;
addChild(artist);
addChild(artistName);
}

Got it. Like a dummy, I forgot to add "extends Sprite" after the class declaration.

Related

ActionScript 3 - use [brackets] instead of getChildByName

I have a MovieClip inside library, linkaged to MyObject and it contains a textField.
I don't know how I can access this textField without using the getChildByName method.
Apparently, the 3rd section works when object is on stage (without using addChild). But when using addChild I think there has to be some kind of casting; which I don't know how.
var childElement: MyObject = new MyObject();
childElement.name = "theChildElement";
container.addChild(childElement);
btn.addEventListener(MouseEvent.CLICK, changeText);
function changeText(event: MouseEvent): void
{
var targetBox:MovieClip = container.getChildByName(childElement.name) as MovieClip;
targetBox.textField.text = "hello"; // THIS WORKS
// This works too:
// MovieClip(container.getChildByName("theChildElement"))["textField"].text = "hello"; // THIS WORKS TOO.
// THIS DOESN'T WORK. why?
// container["theChildElement"]["textField"].text = "hello";
}
As confusing as it may seem, instance name, and name are not the same. From your code you should always be able to get to your MC by it's variable name. To get your last like to work you could just use this.
childElement["textField"].text = "hello";
There is a difference between Symbols created by the Flash IDE, which aggregate other DisplayObjects and programmatically created DisplayObjects.
When a DisplayObject is created in the Flash IDE, it's instance name can be used to resolve the instance as a property - which means it can be accessed via []. The [] can be used to access properties or keys of dynamic declared classes - like MovieClip. This necessary because you'll most likely down cast to MovieClip instead of using the symbol class created by Flash. That is not possible when simply using addChild, addChildAt or setChildAt from the DisplayObjectContainer API.
It is always the save way to access it via getChildByNameand check for null because otherwise your app, website or whatever is doomed for 1009 errors as soon as someone is changing the symbols.
I'd create a bunch of helper methods, like
// not tested
function getChildIn(parent:DisplayObjectContainer, names:Array):DisplayObject {
var child:DisplayObject, name:String;
while (names.length > 0) {
name = names.shift();
child = parent.getChildByName(name);
if (!child) {
// log it
return null;
}
if (names.length == 0) {
return child;
}
}
// log it
return null;
}
function getTextFieldIn(parent:DisplayObjectContainer, names:Array):TextField {
return getChildIn(parent, names) as TextField;
}
function getMovieClipIn(parent:DisplayObjectContainer, names:Array):MovieClip {
return getChildIn(parent, names) as MovieClip;
}
Your third method doesn't work because you are trying to call the ChildElement by it's name
without using getChildByName method. On the other hand, you shouldn't call your textField textField, because that's already an actionScript property.
Your should rather call it 'displayText' for example.
For a textField called 'displayText' contained in childElement :
function changeText(event:MouseEvent): void
{
childElement.displayText.text = "hello";
}

AS3 - types and classes

I'm not exactly sure but i'm guessing my problem has to do with how i'm declaring my variables.
Is the below code legal in AS3?
var fish1:Fish = new Fish;
var fish2:Fish = new Fish;
var fish3:Fish = new Fish;
var fish4:Fish = new Fish;
addChild(fish1);
addChild(fish2);
addChild(fish3);
addChild(fish4);
fish1.x = 0;
fish2.x = 150;
fish3.x = 300;
fish4.x = 450;
i'm getting compiler errors for each line of addChild saying:
Main.as, Line 14 1180: Call to a possibly undefined method addChild.
Main.as, Line 14 1120: Access of undefined property fish3.
and for every line where i'm specifying the x coordinates of my fish i'm getting
a compiler error saying
Main.as, Line 15 1120: Access of undefined property fish4.
the fish variables are of type Fish and I've defined them in my library in my .fla file.
Thank you in advanced!
Your Class needs to subclass some form of DisplayObjectContainer, of which MovieClip and Sprite are two possible choices (find out, be sure).
But I suspect that the real probem is you're writing Class code like it's timeline code. I think you probably have strict mode off, which is why you're ot getting helpful compile-time errors which would help anyone who's familiar with AS3 (though probably not you) to figure out immediately that your code should look more like
class Main extends Sprite {
public var fish1:Fish = new Fish();
public var fish2:Fish = new Fish();
public var fish1:Fish = new Fish();
public function Main() {
addChild(fish1);
addChild(fish2);
addChild(fish3);
//not going to type this crap.
//positioning code (and addChild) is a waste of time.
//that's what the stage is for!
}
}

Why does a closed NetConnection that has no event listeners or references stick around in memory?

It seems that if flash.net.NetConnection is instantiated and connected to an HTTP URL (such as an AMFPHP gateway), that instance is never picked up by garbage collection even after it has been closed and the only reference is set to null.
On the other hand, if the instance is connected to null (as would be done when used to play video/mp3 files), the instance is cleared from memory.
To clarify, the following connection will stick around in memory:
var stickyConn:NetConnection = new NetConnection();
stickyConn.connect("http://myserver/amfphp/gateway.php");
stickyConn.close();
stickyConn = null;
Whereas, the following connection will be cleared from memory immediately:
var tempConn:NetConnection = new NetConnection();
tempConn.connect(null);
tempConn.close();
tempConn = null;
Some things I have already tried to solve this issue:
set the client to an empty object (since the default value of the client is the NetConnection itself)
before closing the connection, call connect(null)
after closing the connection, call connect(null) and close it again
Has anyone run into this issue before? Is there a solution to this?
I have built heavyloaded FLV/Mp4 Players using AS3 quite often. When I am using a service like Akamai or Adobe's internal NetConnection Class I always keep in mind the
client object.
the is the property of NetConnection on which ALL callback methods are invoked. The default is this NetConnection instance this. If you set the client property to another object, callback methods will be invoked on that object.
In this way you can easily understand how Garbage Collection was never really applied accross each component in the same way. So, where stickyConn = null; only stops the playback, since you never declared a Weak Reference, Garbage Collection has no clue what to look for.
I have had success with differrent methods based on the specific player:
Simply stating NetConnectionObj.client = this usually suffices. But what if your NetConnection is extended or implementing an interface? Simply use a null Dictionary object:
var d:Dictionary = new Dictionary(true); . From here Garbage collection will recognize "d" as a weak reference and automatically dump it;
Hence, your snippet will look somewhat like this:
var Dc:Dictionary = new Dictionary(true);
NetConnection:NetConnection.client = Dc;
or some variation with the same intent.
I know this works, so reach out if you need help...
I may have been vague with the last answer in regards to GC and Dictionary Objects. Please take this snippet into consideration. I wrote it quickly but I try to explain the Concept of what solves your problem; mainly since I have dealt with it before:
public class Main extends MovieClip {
private var connection:NetConnection;
private var __nData:*;
private var _instance:*;
private var _closure:Function;
private var _D:Dictionary;
public function Main() {
connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, _nsHandle)
connection.connect(null);
}
public function _nsHandle(event:NetStatusEvent):void {
try {
connection = new NetConnection();
connection.connect(null);
connection.client = RegisterForGC(event.target);
RegisterForGC(connection);
} finally {
__nData = event.target.netConnection;
}
}
public function RegisterForGC(NCObject:*):* {
_instance = NCObject;
_closure = function ():void {}
_listener = function (e:Event):void {}
_D = new Dictionary(true);
_D[_listener] = "A";
_D[_instance] = "B";
_D[_closure] = "C";
try {
new LocalConnection().connect( "A" );
new LocalConnection().connect( "B" );
} catch (anything:*) { }
return _instance;
}
}
I'm not sure but Your example seems to suggest you are declaring your vars on stage / frame.
close(); is all you need for this to work HOWEVER....
from what I have found with NetConnection it for some reason unless all vars / functions are declared in an External class eg. public vars public function,
It stays in memory even after using close();
Pulled out my hair figuring this out with an audio streaming project.
However once I moved all coding to an external class, close(); actually closed the connection.
If your code is on a frame on stage or within MC I would create a class and declare vars & functions in said External Class.as and for some stupid reason it works.
Hope this helps.
Are you using a NetStream object and not disposing of it when finished? I only ask because I rarely see a NetConnection without a NetStream object far behind it.

How to access MC inside movieclip added from library?

I have the following code and I followed the answer from this question, but it doesn't seem to be working for me. I'm not getting an error or getting a trace response.
Basically I need to access this test_mc inside the added child. Am I doing something wrong?
for (var i:int=0; i<30; i++) {
var mc:panelClass = new panelClass();
all_mc.addChild(mc);
mc.x = allWidth * i;
// Accessing the test mc
mc.test_mc.addEventListener(MouseEvent.CLICK, ctaOnClickHandler);
}
function ctaOnClickHandler(e:MouseEvent) {
trace("Clicked");
}
Kind of hard to answer this without know what panelClass is and how it is built. I'm assuming test_mc is a movieclip that's using all it's default properties and is on the display list of panelClass and since there are no errors it's been instantiated. The only think I can think of is there anything being displayed on top of test_mc inside panelClass?

AS3 - How to assign names or tags to loader?

I have a list of images that i’ve loaded with the Loader class, but I’m having a tough time assigning them unique names.
I need unique names because I want to remove certain images after a while.
Is there a way to assign loaders a name or some unique tag so i can remove them later? thanks.
Here's part of my code
for (var i = startnum; i < endnum; i++){
var thumb = panels[i].#THUMB;
var thumb_loader = new Loader();
thumb_loader.load(new URLRequest(thumb));
thumb_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
thumb_loader.name = i;
thumb_loader.x = (thumb_width + 20)*i;
}
I tried to use getChildByName in another function..
var myLoader:Loader = getChildByName( "1" ) as Loader;
myLoader.unload();
But it's giving me
Error #1009: Cannot access a property or method of a null object reference.
I tried to put thumb_loader as global variable, and do this
var myLoader:Loader = thumb_loader.getChildByName( "1" ) as Loader;
But it's still not working.
Thanks.
All display objects in ActionScript 3 have a name property. Whenever you create a Loader object you can assign a name to it like so:
var myLoader:Loader = new Loader();
myLoader.name = "myUniqueName";
myLoader.load( .... );
addChild( myLoader );
If you'd like to refer to the loader by the name you gave it, use the getChildByName() method.
var myLoader:Loader = getChildByName( "myUniqueName" ) as Loader;
myLoader.unload();
Please be mindful that getChildByName() will only work after you've added the Loader(s) to the display list using addChild(). Otherwise, you'll have to create something to store the references to the Loader objects in, such as an Array and refer to the loaders via that Array. For example, outside your loop you could create an Array named loadersArr. In your loop you would do:
loadersArr["uniqueName"] = thumb_loader;
Then you can refer to your loaders with your unique name through the loadersArr Array.
var loaderToUnload:Loader = loadersArr["uniqueName"];
loaderToUnload.unload();
Without seeing more of your code, its difficult to understand the scope in which this code resides and where any other code that may try to reference these Loaders resides.
Not sure I 100% understand your problem, but why not put them in an object map rather than a list and generate unique names for them if you don't have them...
var img:Image;
var img_map:Object = new Object();
var last_added:int = 0;
for each (img in yourListOfImages)
{
img_map["img_"+last_added] = img;
last_added++;
}
Depending on your environment (Flex or Flash) you can use a UID generator instead of my simplistic unique names above.
package
{
import flash.display.Loader;
public dynamic class DynamicLoader extends Loader
{
public function DynamicLoader()
{
super();
}
}
}
I believe the Loader class is a sealed class so you would want to create this class and use it instead of the normal Loader class to give it any attribute you want. I also believe that without using this DynamicLoader instead of the normal Loader, the Loader class does have the name property available to it.