ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Working With Display Objects in AS 3.0
http://www.actionscript.org/resources/articles/623/1/Working-With-Display-Objects-in-AS-30/Page1.html
Patrik Vormittag
I am an interactive digital artist at Crispin Porter + Bugosky. Currently creating RIA's and pushing the powers of flash/flex. To view my work or to contact me, please visit my portfolio - http://www.previsualsdesign.com
By Patrik Vormittag
Published on June 9, 2007
 
Learn how to work with the display list, DisplayObjects, and DisplayObjectContainers in Actionscript 3.0 and how it has replaced the concept of "depth" in actionscript 2.0. You should have a working knowledge of depth in actionscriplt 2.0 and also how the flash player displays content on the screen(stage). This tutorial is made for Flash CS3.

Difficulty: Intermediate
Time: 20 - 30 minutes

The display list

The dawn of Flash CS3 means the ability to use actionsript 3.0. No longer can you only access the new powers of actionscript with just flex 2. In this tutorial, I am going to discuss one of the main diffrences between Actionscript 3.0 and Actionscript 2.0/1.0, which is the display list, DisplayObjects, and DisplayObjectContainers.First, lets discuss the display list. The display list manages all objects that can be displayed in the flash player and it is going to effect the way you add objects to it. Below is an example of how you created a new object (in this case, a MovieClip) and added it to the stage in AS2.0/1.0, and how it is now done in AS 3.0.

actionscript 1.0/2.0
[as]//main timeline: frame 1 this.createEmptyMovieClip("my_mc", this.getNextHighestDepth());
trace(my_mc); //outputs: _level0.my_mc[/as]

actionscript 3.0
[as] //main timeline: frame 1
var myMovieClip:MovieClip = new MovieClip();
this.addChild(myMovieClip);
trace(myMovieClip); //outputs: [object MovieClip][/as]

The first thing you'll notice is that in AS 3.0, you can now create any object by using the “new” statement. This includes Buttons and TextFields as well. The next thing you'll notice is that you no longer have to give a depth to an object, this is because “depth” no longer exsists in actionscript. Instead when you create an object in AS 3.0, it is created, but not automatily added to the stage. The display list manages all visible objects on the stage, anything that is not apart of the display list is concidered invisible. In order to add the object to the stage, we must use the addChild method of any DisplayObjectContainer (the main timeline or “_root” is a DisplayObjectContainer, I'll discuss this shortly). You may have aslo noticed that in AS 3.0, we did not give our movieClip object an instance name. In oder to do this, we need to use the MovieClip.name property and set the name. So for our above example:

[as]
myMovieClip.name = "my_mc";
[/as]

If your are working mainly with actionscript though, you may not need to set the name property, since when you create the object you give it a variable name which you would use to refrence the object instead.

Ok, let us move on to DisplayObjects and DisplayObjectContainers



DiplayObjects and DisplayObjectContainers

The DisplayObject class is the base class for all objects that can be placed on the display list. There are to types: DisplayObject and DisplayObjectContianer. DisplayObjects are objects that can have no children (such as Shape or TextField Objects). So, as you may have assumed, the DisplayObjectContainer is an DisplayObject that can have children, being either displayObjects or other DisplayObjectContainers. DisplayObjectsContainers are what allow you arrange objects on the stage. Lets examine the example below:

[as]//main timeline: frame 1 var myMovieClip:MovieClip = new MovieClip(); var container1:Sprite = new Sprite(); var container2:Sprite = new Sprite(); container1.addChild(myMovieClip); container2.addChild(container1); this.addChild(container2);[/as]

As you can see, I have created three Objects, one MovieClip and two Sprites (sprites are new to AS 3.0, they are basicly a lightweight MovieClip containing no timeline, perfect for containers). I then added them to one another using the addChild method. Adding MyMovieClip as a child to container1, container1 as a child of container2, and finally, contiainer2 as a child of the main timeline or _root. Below is one way we could visualize the display list:

display list

main timeline ( _root)
container2 (child of _root)
contianer1 (child of container2)
myMovieClip (child of container3)

The beauty of the display list and its versiatility over depth managment, is that though our MovieClip object is parented (or nested) inside two other objects (three if you count _root), we can still easily move our MovieClip from one parent to another. Below is an example of moving the MovieClip object to the _root:

[as]//main timeline: frame 1
container1.removeChild(myMovieClip);
this.addChild(myMovieClip);
trace(myMovieClip.parent); //outputs: [object MainTimeline][/as]

Thats it! now myMovieClip is a child of the main timeline or _root. To achieve this in AS 1.0/2.0 would be insanly hard and in most cases impossible.


Working With Children
Now that we know how DisplayObjectContainers can add children and how the display list manages them, our next question my be "How do with deal with multiple children?"Well, it's pretty simple. When I said that "depth" no longer exsists in actionscript, I only mean the literal word and in terms of layering or "z-index". The concept on the other hand (z-index), is still in use and is now much easier to work with. If we think of a DisplayObjectContainer as an array, we could assume it's children would look something like this:

[as]var parent:Array = new Array(child, child, child, child);[/as]

Infact, this is very similar to how a parent object deals with its children. the child in the last index will be visually above the rest and so on through all of it's children. When we use the addChild() method to add a child, the child is automaticly added to the end of the child list(similar to an Array.push() method). Now of course, if all we could do is add children and have them only be placed last in the child list, this would not be very handy. Of course though, not only can we move or add a child to any index of a child list, we can also easily swap them. The addChildAt() method allows you to add a new child and also set it's index amoung the existing children of a parent. lets see how this works:

[as]// main timeline: frame 1
var pictureHolder:Sprite = new Sprite();
var picture1:Bitmap = new Bitmap();
var picture2:Bitmap = new Bitmap();
var picture3:Bitmap = new Bitmap();

picture1.name = "pic1";
picture2.name = "pic2";
picture3.name = "pic3";
 
pictureHolder.addChild(picture1);
pictureHolder.addChild(picture2);
pictureHolder.addChildAt(picture3, 2);
trace(pictureHolder.getChildAt(2).name); //outputs: pic3[/as]

As you can see, it was very easy to add the picture3 Bitmap Object to the 2nd index of the pictureHolder's child list. The other great thing about this method is that even though we placed picture3 in the same index as picture2, we did not overwrite the existence of picture2 as a child. Instead, picture2 was automaticly moved one up in the child index. Yet again, this would have been much harder to accomplish in AS 2.0/1.0. More kudos to 3.0!!

putting it all together
Now that we have a good understanding of the display list and the DisplayObject, lets put it altogether. Here is an example that creates a tiled effect of boxes on the stage. When the user clicks one of the boxes, the boxes child index is set to the last index postion of the parents child list (done through the numChildren property of the DisplayObjectContainer ) and in turn, is visually sent to the front of all the boxes. The user can also press and hold to drag the box around the stage.

[as]import flash.display.Sprite;
import flash.events.*;
import flash.display.MovieClip;
import flash.filters.DropShadowFilter;
import flash.text.TextFormatAlign;
import flash.text.TextField;
import flash.text.TextFormat;

stage.align = "TL";
stage.scaleMode = "noScale";

var boxContainer:Sprite = new Sprite();

var columns:int = 5;
var rows:int = 5;

var boxSpacing:int = 2;

var boxWidth:uint = stage.stageWidth / rows;
var boxHeight:uint = stage.stageHeight / columns;
var startX:Number = boxSpacing;
var startY:Number = boxSpacing;
var boxIndex:int = 0;

var dropShadow:DropShadowFilter = new DropShadowFilter();
dropShadow.distance = 3;
dropShadow.angle = 45;
dropShadow.alpha = 20;
dropShadow.blurX = dropShadow.blurY = 6;

for(var j:int = 0; j < columns; ++j){
    startX = boxSpacing;
    for(var i:int = 0; i < rows; ++i){
        var box:Sprite = new Sprite();

        box.name = "box"+ ++boxIndex;
       
        box.x = startX;
        box.y = startY;
        box.buttonMode = true;
        box.graphics.lineStyle(1, 0x999999, 1, true);
        box.graphics.beginFill(0x333333, 1);
        box.graphics.drawRect(0, 0, boxWidth - boxSpacing, boxHeight - boxSpacing);
        box.filters = [dropShadow];
       
        box.addEventListener(MouseEvent.MOUSE_OVER, boxOnMouseOver);
        box.addEventListener(MouseEvent.MOUSE_OUT, boxOnMouseOut);
        box.addEventListener(MouseEvent.MOUSE_DOWN, boxOnPress);
        box.addEventListener(MouseEvent.MOUSE_UP, boxOnRelease);
       
        startX += box.width + boxSpacing;
       
        var boxName:TextField = new TextField();
        boxName.text = box.name;
        boxName.width = boxWidth;
        boxName.height = 25;
        boxName.y = (box.height / 2) - (boxName.height / 2);
        boxName.mouseEnabled = false;
        boxName.wordWrap = true;

        var boxNameFormat:TextFormat = new TextFormat("verdana", 10, 0x666666, null, null, null, null, null, TextFormatAlign.CENTER);
        boxName.setTextFormat(boxNameFormat);
       
        box.addChild(boxName);
        boxContainer.addChild(box);
    }
    startY += box.height + boxSpacing;
}
addChild(boxContainer);

function boxOnMouseOut(evt:MouseEvent){
    if(evt.eventPhase == EventPhase.AT_TARGET){
        evt.target.graphics.clear();
        evt.target.graphics.lineStyle(1, 0x999999, 1, true);
        evt.target.graphics.beginFill(0x333333, 1);
        evt.target.graphics.drawRect(0, 0, boxWidth - boxSpacing, boxHeight - boxSpacing);
    }
}

function boxOnMouseOver(evt:MouseEvent){
    if(evt.eventPhase == EventPhase.AT_TARGET){
        evt.target.graphics.clear();
        evt.target.graphics.lineStyle(1, 0x333333, 1, true);
        evt.target.graphics.beginFill(0x999999, 1);
        evt.target.graphics.drawRect(0, 0, boxWidth - boxSpacing, boxHeight - boxSpacing);
    }
}

function boxOnPress(evt:MouseEvent){
    if(evt.eventPhase == EventPhase.AT_TARGET){
        evt.target.parent.setChildIndex(evt.target, (evt.target.parent.numChildren - 1));
        evt.target.startDrag();
    }
}

function boxOnRelease(evt:MouseEvent){
    if(evt.eventPhase == EventPhase.AT_TARGET){
        evt.target.stopDrag();
    }
}[/as]
Which outputs:


This example uses a lot more then just manipulation of DisplayObjects, such as EventHandlers and working with the Flash Drawing API (The handling of events is another main difference in AS 3.0, but that will need to wait for another tutorial). I hope this helped! Enjoy!