flash display_list_accessing_objects

Accessing display objects

Open a new Flash CS3 document and create a simple vectorial shape with the help of the rectangle tool. By targeting the numChildren property in our main stage, we get the number of children corresponding to the length of the internal array:

// display : 1
trace( numChildren );

The numChildren property sends us back a 1 as the only object contained by our main stage is our vectorial shape. This was added automatically to the display list. Even though the vectorial shape doesn’t have an occurrence name we can access it thanks to methods defined by the DisplayObjectContainer class.

To access a child object placed at the specific index we have the getChildAt method at our disposal:

public function getChildAt(index:int):DisplayObject

Don’t forget that the getChildAt method only points to the internal array of the DisplayObjectContainer depending on the index passed as parameter:

myDisplayObjectContainer.getChildAt ( index );

To access the vectorial shape that we have just drawn, we target index 0 with the help of the getChildAt method:

// accesses the graphic object placed in the index 0
var shape:Shape = getChildAt ( 0 );

In compiling the previous code, the error is raised indicating that it is impossible to place a DisplayObject object type in a Shape variable type:

1118: Implicit constraint of a static value flash.display:DisplayObject type to a flash.display:Shape type without any connection.

We try to store the reference sent by the getChildAt method in a Shape container type.

In rereading the signature of the getChildAt method we can read the type returned by the DisplayObject.

Flash therefore refuses the compilation as we try to store a DisplayObject in a Shape type container.

We can therefore indicate to the compiler that the object will be a Shape type object by using the keyword as:

// accesses the graphic object placed in index 0
var shape:Shape = getChildAt ( 0 ) as Shape;
// display : [object Shape]
trace( shape );

Actually, this code proves to be dangerous because if the object that is placed in the index 0 is replaced by a graphic object which is not compatible with the Shape type, the casting result fails and returns null.

We therefore need to assure ourselves that no matter what graphic object is placed in index 0, our variable will be a compatible type. In this situation it is therefore advisable to always use the generic DisplayObject to store the graphic object reference:

// access the graphic object in index 0
var shape:DisplayObject = getChildAt ( 0 );
// display : [object Shape]
trace( shape );

By doing this we don’t take any risks because due to inheritance the graphic object will be a DisplayObject. If we try to access an unoccupied index we get:

// access to the graphic object placed in index 0
var shape:DisplayObject = getChildAt ( 1 );

A RangeError error type is raised as the specified index 1 doesn’t contain a graphic object:

RangeError: Error #2006: The index indicated is not within the limits.

Before ActionScript 3, when a graphic object was created at an already occupied depth, the object residing at that depth was replaced. To avoid all conflict between designers and developers the graphic objects created through development were placed at a positive depth and those created in the author environment at a negative depth.

It is no longer the case in ActionScript 3, everybody works on the same depth levels. When we place a graphic object from the Flash CS3 author environment on the stage, it is created and automatically added to the display list.

In ActionScript 1 and 2 it was impossible to access a simple shape contained in a timeline. One of ActionScript 3’s powers is the posiility to access any object in the display list.

Let’s go further and create a second vectorial shape on the main timeline with the help of the Oval tool,the following code still shows us one child object only:

// display : 1
trace( numChildren );

We might have believed that each vectorial shape created corresponds to a different graphic object, but this is not the case. All of the vectorial shapes created in the author environment are actually one Shape object.

Even if vectorial shapes are placed on multiple layers, one single Shape object is created to contain them all.

The following code makes our two vectorial shapes invisible:

var myShapes:DisplayObject = getChildAt ( 0 );
myShapes.visible = false;

Remember that ActionScript 3 integrates an automatic depth management. On each calling of the addChild method the DisplayObject passes as a parameter and is added to the DisplayObjectContainer. The child objects add themselves on behind the other in the internal array.

Each graphic object is placed graphically above the previous one. It is therefore no longer necessary to worry about the depth of a MovieClip in a for loop:

var myClip:MovieClip;
var i:int;
for ( i = 0; i< 10; i++ )
{
myClip = new MovieClip();
addChild ( myClip );
}

On exiting the loop, ten clips will have been added to the display list:

var myClip:MovieClip;
var i:int;
for ( i = 0; i< 10; i++ )
{
myClip = new MovieClip();
addChild ( myClip );
}
// display : 10
trace( numChildren );

To make reference to each clip we add the following code:

var lng:int = numChildren;
for ( i = 0; i< lng; i++ )
{
/* display :
[object MovieClip]
[object MovieClip]
[object MovieClip]
[object MovieClip]
[object MovieClip]
[object MovieClip]
[object MovieClip]
[object MovieClip]
[object MovieClip]
[object MovieClip]
*/
trace( getChildAt ( i ) );
}

We get the total number of child objects with the numChildren property then we pass the i index as the index to the getChildAt method to target each occurrence.

To get the index associated with a DisplayObject we pass it as a reference to the getChildIndex method:

public function getChildIndex(child:DisplayObject):int

In the following code we access the previously created clips and get the index of each one:

var lng:int = numChildren;
var objetEnfant:DisplayObject;
for ( i = 0; i< lng; i++ )
{
objetEnfant = getChildAt( i );
/*display :
[object MovieClip] to the index : 0
[object MovieClip] to the index : 1
[object MovieClip] to the index : 2
[object MovieClip] to the index : 3
[object MovieClip] to the index : 4
[object MovieClip] to the index : 5
[object MovieClip] to the index : 6
[object MovieClip] to the index : 7
[object MovieClip] to the index : 8
[object MovieClip] to the index : 9
*/
trace ( objetEnfant + " to the index : " + getChildIndex ( objetEnfant ) );
}

Bear in mind that it is always possible to give a name to a graphic object. To give a name to a clip in ActionScript 1 and 2, you have to specify the occurrence name as a parameter upon the calling of a createEmptyMovieClip or attachMovie method.

In ActionScript 3, once the graphic object is instantiated we can pass a character string to the name property defined by the DisplayObject class.

The following code creates an instance of the MovieClip and gives it an occurrence name:

var myClip:MovieClip = new MovieClip();
myClip.name = "myOccurrence";
addChild ( myClip );
// display : myOccurrence
trace(myClip.name);

To access our MovieClip we can use the getChildByName method allowing us to target a DisplayObject by its name and not by its index like the getChildAt method allows.

The getChildByName method defined by the DisplayObjectContainer class accepts a character string corresponding to the occurrence name of the DisplayObject which we want to access as the only parameter. Here is its signature:

public function getChildByName(name:String):DisplayObject

The following code allows us to target our MovieClip:

var myClip:MovieClip = new MovieClip();
myClip.name = "myOccurrence";
addChild ( myClip );
// display : [object MovieClip]
trace( getChildByName ("myOccurrence") );

The getChildByName method recursively crosses all the objects of the child object list until the DisplayObject is found.

If the graphic object that has been searched for is not present in the concerned DisplayObjectContainer, the getChildByName method returns null:

var myClip:MovieClip = new MovieClip();
myClip.name = "myOccurrence";
// display : null
trace( getChildByName ("myOccurrence") );

It is not recommended to use the getChildByName name, it proves much more slow on execution than the getChildAt method which points directly to the internal array of the DisplayObjectContainer.

A simple test shows the significant difference in performances. Within a loop we access a clip present within the display list with the help of the getChildByName method:

var myClip:MovieClip = new MovieClip();
myClip.name = "myOccurrence";
addChild ( myClip );
var departure:Number = getTimer();
for ( var i:int = 0; i< 5000000; i++ )
{
getChildByName ("myOccurrence");
}
var arrival:Number = getTimer();
// display : 854 ms
trace( (arrival - departure) + " ms" );

Our loop takes around 854 ms to execute by using the getChildByName access method. Let’s proceed with the same test but using the getChildAt access method this time:

var myClip:MovieClip = new MovieClip();
myClip.name = "myOccurrence";
addChild ( myClip );
var departure:Number = getTimer();
for ( var i:int = 0; i< 5000000; i++ )
{
getChildAt (0);
}
var arrival:Number = getTimer();
// display : 466 ms
trace( (arrival - departure) + " ms" );

We get a difference of about 400 ms between the two loops. The results of this test encourage us to use the getChildAt method rather than the getChildByName method. A question that you may be asking is ‘If I don’t specify the occurrence name, what name will my graphic object carry?’.

Flash 9 player proceeds in the same way as previous players by using the occurrence name by default.

Take the following example of a dynamically-created MovieClip:

var myClip:MovieClip = new MovieClip();
// display : instance1
trace( myClip.name );

An occurrence name is automatically affected.

It is important to note that it is impossible to modify the name property of an object created in the author environment.

In the following code, we try to modify the name property of a MovieClip created in the author environment:

myClip.name = "newName";

Which generates the following compilation error:

Error: Error #2078: Impossible to modify the name property of an object placed on the timeline.

In reality this doesn’t pose much of a problem as we rarely use the name property which is strongly linked to the getChildByName method.








Adobe Training center


Mediabox Training Centre © 2000 - 2008 All rights reserved.
Adobe Authorized Training Centre. State convention under number 25 14 02167 14.
Mediabox : SARL au capital de 62.000€ - Activity number: 25 14 02167 14 - SIRET : 493 716 468 00027
MEDIABOX, 102 Avenue des Champs Elysées, 75008 PARIS - Tel. +33(0)2.31.91.96.89 - Fax. +33(0)2.72.68.56.42