Skip to main content
sinious
Legend
April 15, 2011
Question

Traversing display list hierarchies in an easier means, ala-AS2? (dot syntax)

  • April 15, 2011
  • 6 replies
  • 2519 views

Hey all,

I've been searching around forever trying to find a way to make traversing nested display lists more of a 1-line possibility.

In AS2 you could grab a clip just by _container.clip1.nestedclip2.nestedclip3 and it was blatently simple.

In AS3, is there any way to do that?

So far my only methods are keeping a class level reference to important parts of the UI or doing a painful series of getChildByName chains until I drill down to it:

(I know the sprite casting is optional up till the last stop, but I hate DisplayObject).

var clip1:Sprite = Sprite(_container.getChildByName('clip1'));

var nestedclip2:Sprite = Sprite(clip1.getChildByName('nestedclip2'));

var nestedclip3:Sprite = Sprite(nestedclip2.getChildByName('nestedclip3'));

wtf?

I have no idea why I can't daisy chain.

var nestedclip3:Sprite = Sprite(_container.getChildByName('clip1').getChildByName('nestedclip2).getChildByName('nestedclip3'));

I know gCBN isn't a method without a cast tough and even though it's hideous, this should still work:

var nestedclip3:Sprite = Sprite(Sprite(Sprite(Sprite(_container).getChildByName('clip1')).getChildByName('nestedclip2)).getChildByName('nestedclip3')));

The casting makes the getChildByName method possible.

What's the deal on this?

This topic has been closed for replies.

6 replies

sinious
siniousAuthor
Legend
April 16, 2011

I'm using all sprites because I don't need any dynamic nature to them and I'd like the UI to be as fast as possible so I really can't  use that dot notation unfortunately.

I come from c#, obj-c, perl, php, etc, very enumerated languages. When I do something like:

var a:Sprite = _container.getObjectByName('b');

That is not a property.

I am specifically adding a reference (and increasing the reference count to garbage collection) to the sprite who's name is 'b' that's contained in _container.

That's not a property, that is an object.

That is why it makes no sense to me when I can daisy chain operations in return-value style.

It is very much the same object nature that relates to functions. Nested functions use each others return values as arguments. Such as:

var num:Number = Math.round(Math.min(1.5,2.5));

Math.min returned 1, which Math.round accepts as a valid value to work with, which then rounds and returns to num. That was how you could traverse the display list before.

var cRef:Sprite = DisplayObjectContainer(a.getChildByName('b')).getChildByName('c');

That is not confusing and that is very much object oriented. The return value of a.getChildByName('b') returns to DisplayObjectContainer()'s scopeing function which then becomes a DisplayObjectContainer object that supports the method getChildByName('c'). There's nothing wrong with enclosing return values of objects methods into others.

I do a ton of *.graphics drawing all over my UI. I have a 500kb external XML file that I read in settings for about every aspect of the UI and all of it is generated in AS3. Lots of things are "just graphics", have no interaction and I have no need for them. But sometimes I'd like to affect them based on contextual situations and I always give them a name in the display list. I was just looking for a way to 1-line access those rare instances.

Inspiring
April 16, 2011

I am not sure I got all the point of your last post but the original post was about dot notation vs accessing runtime variables.

I didn't notice anyone arguing that the line

var cRef:Sprite = DisplayObjectContainer(a.getChildByName('b')).getChildByName('c');

is illegitimate. It is the only way to get variables that are on display list. I must say that this is the most performance expensive way to reference objects in AS3. This is why suggestions to have a mechanism to store these references are more elegant.

Given that chasing parent/children tree is a tricky proposition (especially in AS3 where, again, it can be turned on a dime) in my view (that, I believe, echoes Ken's) an application that relies on arbitrary naming conventions/names is flawed and architecture should be reconsidered. Direct referencing to variables and properties is faster than making application search references based on arbitrary string values.

I am not proficient on other languages but something tells me that tree-like/dasy-chain variables accessing is not the best idea in any OO environment no matter whether it is possible or not. One thing I am sure of is that this kind of access stems from lack of proper encapsulation and modularity. But this is, perhaps, a matter of personal taste (and in my taste and style any object should be totally independent).

I am not sure how Math methods example playes out in the context of the original post as well.

This is, perhaps, more of an academic discussion than finding proper solution.

The answer to the original question still stands at "No, one cannot access display list members via dot notation in AS3."

sinious
siniousAuthor
Legend
April 16, 2011

My original post was about finding the AS3 alternative to the AS2 dot syntax method of accessing specific objects in any tree.

I have no idea why I can't daisy chain.

That was my original question which I ended up experimenting with until I found it. I've searched deep and wide on the internet to even find this method and I still can't find it. That's why I came here.

I 110% agree with you that looking up objects this way is:

  1. Inefficient
  2. Terrible to plan an app using solely this approach
  3. and also.. Terribly complex to even look at down the line revisiting code

I have absolutely no intention of making extensive use of this, but my interfaces have hundreds of graphical elements on the screen at once. I don't want to make an array with hundreds of references in memory to 95% of the objects that I have no use to interact with outside rare occasion.

A simple example..

You have a 20 buttons, each having 6 different graphical states, all are images to represent the states (Loaders). My method is to simply add in 20 references, ala buttons = button_n. When I want to change state, this is where multi-gigahertz computers are not going to balk even for a 0.00005 seconds traversing a display tree of 6 objects looking up an expensive comparison, a string. This is where I would use this technique. Not because it's the most efficient computationally, but it sure is regarding my time.

You seem to argue the better idea is to bloat up an array such as: buttons = [button_n,button_n_image1,button_n_image2,button_n_image3,button_n_image4,button_n_image5,button_n_image6];

Yes, it gives me direct access to the button and all 6 of the Loader images below it but it creates 20 * 6 array references (120 references). Not to mention if you plan on destroying that panel you better not only pop the whole display list but also nuke potentially thousands of references.

I'd rather traverse a display list because the user may not interact with 90% of the buttons on one panel. The 10% they do, the cost to look up something inside those buttons to make them interactive is cheap.

I want my code to read like english. I could get the child objects by index to speed up performance rather than a string comparison, but when you're reading your own code, which is more readible 6 months after the projects is done?

Sprite(buttons['playbutton'].getObjectByName('paused_roll')).alpha = 1;

or

// dont fotget button 19 is play/pause and the object at index 3 is the paused roll state

Sprite(buttons[19].getObjectAtIndex(3)).alpha = 1;

We're talking dual+ core multi-gigahertz computers. They're not going to bat a lash at each method of just changing a state of a single image. Why make your code horribly unreadable when your application will perform so slightly faster than me that nobody on this planet will actually notice?

Inspiring
April 16, 2011

"What's the deal on this?"

It looks like there is a gap in understanding AS3 syntax and display list model AS3 uses.

1. Dot notation is allowed for objects's (class' which is an Object) PUBLIC (or protected in case of extended classes) properties/methods ONLY.

2. Members of display list ARE not properties just because they were placed into DIsplayObjectContainer hierarchy - thus they cannot be accessed as properties. In other words, there is a very clear separation between presentation and information layers in AS3. There are numerous benefits to this model. One of those benefits is that DisplayObjects can be moved around and loose/acquire parents without restriction but they NEVER loose scope they belong to.

Another VERY important thing re point 2 is that ONLY DisplayObject instances have an ability to be members of display lists. Other classes cannot be added but their public properties still can be accessed without any consideration given to dispaly list aspects.

With that said, as other guys suggested, in order to access an instance/property of anything directly one has to expose them explicitly to the outside scopes. Note that external scope is anything that doesn't belong to the current object's scope INCLUDING functions.

AS3 is a truley OO language and it is strict in how things are handled unlike AS2 where anything goes.

Community Expert
April 16, 2011

Andrei your point 1 applies also to INTERNAL properties/methods as well, including undeclared properties/methods that are internal by default, such as those made on the timeline (with a caveat - accessible within the package), and also those made dynamically to the dynamic classes (Objects, Arrays, MovieClips) - they are undeclared so they are technically internal (or public? not sure) - this is why you can access child display objects with dot notation in my examples above.

You are right that the display list and the properties must not be confused.

sinious
siniousAuthor
Legend
April 15, 2011

Because my class will build something dynamically in a loop using temporary variables.

import flash.display.Sprite;


for (var i:Number = 0; i < 100; i++)

{

   var someItem:Sprite = new Sprite();

   someItem.name = 'sprite' + i;

   addChild(someItem);

}


// someItem now out of context..


trace(sprite1.name); // Scene 1, Layer 'Layer 1', Frame 1, Line 13    1120: Access of undefined property sprite1.

Understand now? I'm dynamically generating hundreds of things in classes using loops.

Thus 'c' does not exist. I must traverse by name to get back to it or make a hard reference. I don't want to keep an array full of hard references to every graphic I draw.

Community Expert
April 15, 2011

Not really. I would do:

var list:Object = new Object();

for (var i:uint = 0; i < 100; i++) {
    var someItem:Sprite = new Sprite();
    list["sprite"+i]=someItem;
    addChild(someItem);
}

trace(list.sprite1);

// [object Sprite]

Of course you can do whatever you like, but since you asked if there's an easier way - this is

The following won't work in your case since your parent container is a Sprite, but if it's a MovieClip you can also do like this:

(Sprite is not a dynamic class but MovieClip is.)

for (var i:uint = 0; i < 100; i++) {
    var someItem:Sprite = new Sprite();
    this["sprite"+i] = addChild(someItem);
}

trace(this.sprite1);

// [object Sprite]

... so you can access parent.child just like in AS1/2.

Another thing to note is getChildByName() is not efficient because "getChildByName() method has to traverse a linked list to access a child".

sinious
siniousAuthor
Legend
April 15, 2011

Yes every sprite is named. As I mentioned, I figured out a way to daisy chain it together in one line using casting.

e.g.:

var a:Sprite() = new Sprite();

a.name = 'a';

addChild(a);

var b:Sprite = new Sprite();

b.name = 'b';

a.addChild(b);

var c:Sprite = new Sprite();

c.name = 'c';

b.addChild(c);

To get C in one line you can just:

var cRef:Sprite = Sprite(DisplayObjectContainer(a.getChildByName('b')).getChildByName('c'));

trace(cRef.name); // traces 'c'

I often make a global registry if I really need to share data or references if 'm being hacking but inside a class I always have tons of class-level variables that point to important portions of the UI. _navigation points directly to the sprite container that holds all my nav elements and I have a separate array _navItems[] with a reference to each individual nav item, etc.

Sometimes you just have a simple button somewhere and it's not really important enough to dedicate a class variable to it. I just wanted a quick 1-line way to traverse the display list and that seems to do it just fine by casting as I go (albeit ugly).

Ned Murphy
Legend
April 15, 2011

You may have buried c, but you still have direct access to it.

trace(c.name); will do the same thing that all of

var cRef:Sprite = Sprite(DisplayObjectContainer(a.getChildByName('b')).getChildByName(' c'));

trace(cRef.name);

did

Community Expert
April 15, 2011

>  you still have direct access to it

That's exactly my point. Why you need to do Sprite(DisplayObjectContainer(a.getChildByName('b')).getChildByName(' c')) where you can just do c ? Why people are using "name" to reference Sprite/MovieClip? I don't really understand.

Chipleh
Inspiring
April 15, 2011

I've found that it is much easier to use event dispatchers to communicate between movie clip levels, especially when you don't know how to dig up through the parent hierarchy(which I've run into many times).

You can dispatch new events and use listeners to act upon what was dispatched. This can work from any level, any class, any mc, any external swf, any object etc.

i.e.:

//child move clip

dispatchEvent(new Event("Call_Prent_MovieClip"));


parentMovieClip.addEventListener("Call_Prent_MovieClip", callParent, true);

function sendColorString(e:Event):void
{  
      trace("Received call from child movie clip");
}

Community Expert
April 15, 2011

I personally don't use timelines at all and do everything with script so it doesn't matter to me, but as far as I'm aware nothing has changed in terms accessing nested MovieClips.

I have a MovieClip instance "movieclip1" on Stage. "movieclip1" contains a MovieClip instance "movieclip2". "movieclip2" contains a MovieClip instance "movieclip3".

From the main timeline:

trace(movieclip1.movieclip2.movieclip3);

// [object MovieClip]

sinious
siniousAuthor
Legend
April 15, 2011

I don't use the timeline at all, this is all AS3 generated sprites.

I have a container clip 'contentContainer', inside that a sprite 'toggleButtonContainer' and inside that a Loader 'toggleOpen'.. I can't trace like this:

trace(contentContainer.toggleButtonContainer.toggleOpen); // error

trace(this.contentContainer.toggleButtonContainer.toggleOpen); // error

trace(stage.contentContainer.toggleButtonContainer.toggleOpen); // error

They're Sprites and not MovieClips though and I didn't stick them on the timeline with instance names. Are sprites dynamically generated just unable to use that technique?

I do take it back, I was able to get this to work:

var toggleOpen:Loader = Loader(DisplayObjectContainer(contentContainer.getChildByName('toggleButtonContainer')).getChildByName('toggleOpen'));

I found an issue with naming it.. All that casting is a pain in the ass and crufty to read but it's better than making 900 extra vars..

Community Expert
April 15, 2011

> I don't use the timeline at all, this is all AS3 generated sprites.

In that case how are you "naming" your Sprites? In order to use getChildByName() your Sprites have to have the "name" property set explicitly. It doesn't make sense to me, since you can assign your Sprites to variables and just do parent.child to access...?