The Display List: Chapter 4 - Learning ActionScript 3.0
Pages: 1, 2, 3, 4

Removing Objects from the Display List and from Memory

It's equally important to know how to remove objects from the display list. The process for removing objects is nearly identical to the process for adding objects to the display list. To remove a specific display object from the display list, you can use the removeChild() method:

removeChild(ball);

Remove a display object at a specific level using removeChildAt():

removeChildAt(0);

The following example is the reverse of the addChildAt() script discussed in the prior section. It starts by using a for loop to add 20 balls to the stage, positioning them with the same technique used in the prior script. (For more information on for loops, please review .) It then uses the event listener to remove the children with each click.

1 for (var inc:uint = 0; inc < 20; inc++) {
2     var ball:MovieClip = new Ball();
3     ball.x = ball.y = 100 + inc * 10;
4     addChild(ball);
5 }
6
7 stage.addEventListener(MouseEvent.CLICK, onClick,false, 0, true);
8
9 function onClick(evt:MouseEvent):void{
10     removeChildAt(0);
11 }

Preventing out of bounds errors

The previous script works if something's in the display list. If after removing the last ball, you click the stage again, you're warned "the supplied index is out of bounds." That's because you're trying to remove a child from position 0 of the display list, when there's nothing in the display list at all.

To avoid this problem, you can first check to see whether there are any children in the display object container that you are trying to empty. Making sure that the number of children exceeds zero will prevent the aforementioned error from occurring. The following is an updated onClick() function, replacing lines 9-11 in the previous code, with the new conditional in bold. (For more information on conditionals, please review .)

9   function onClick(evt:MouseEvent):void{
10    if (numChildren > 0) {
11       removeChildAt(0);
12    }
13 }

Note: If you ever want to use a for loop to remove many objects at once (everything in the display list, for example), it is easier to remove the objects from the bottom, as discussed here. This is because, as long as there is something in the display list, there will always be something in position 0, and you will avoid the index out of bounds error. For more information, consult Chapter 20 of Colin Moock's Essential ActionScript 3.0.

Removing objects from memory

As we discussed when introducing event listeners in , it is important to remember that inadequate asset management can result in memory leaks. It is always a good idea to try to keep track of your objects and, when you are sure you will no longer need them, remove them from memory.

Keeping track of objects is particularly relevant when discussing the display list because it is easy to remove an object from the display list but forget to remove it from RAM. Doing so will cease displaying the object, but the object will still linger in memory. The following script, a simplification of the previous example, will both remove a movie clip from the display list and from RAM.

1 var ball:MovieClip = new Ball();
2 ball.x = ball.y = 100;
3 addChild(ball);
4
5 stage.addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
6
7 function onClick(evt:MouseEvent):void{
8     this.removeChild(ball);
9     //ball removed from display list but still exists
10    trace(ball)
11    ball = null;
12    //ball now entirely removed
13    trace(ball)
14
15    stage.removeEventListener(MouseEvent.CLICK, onClick);
16 }

Lines 1 through 5 are derived from the previous example, creating and positioning the ball, adding it to the display list, and adding a mouse click listener to the stage. The first line of function content, line 8, removes the ball from the display list using the removeChild() method. Although it is no longer displayed, it is still around, as shown by line 10, which traces the object to the output panel. Line 11, however, sets the object to null, marking it for removal from memory—again, shown by tracing the object to the output panel in Line 13.

Note: As an added review of best practices, line 15 emphasizes the concept of removing event listeners covered in Chapter 3. This is a good example of this practice, since using a weak reference in the last parameter of the addEventListener() method in line 5 is not reliable. Remember, weak references are a best practice backup plan, not a substitute for explicitly removing your unwanted listeners. For additional information, please review Chapter 3.

Section 4.3: Managing Object Names, Positions, and Data Types

As any display list grows, it inevitably becomes necessary to traverse its contents and work with individual display objects. This may require simple tasks such as identifying a display object by name or z index, or even by referencing existing display objects as a specific display list class.

Finding Children by Position and by Name

Many of the example scripts in this chapter demonstrate working with children that have previously been stored in a variable and that are already known to you. However, you will likely have the need to find children in the display list with little more to go on than their position or name.

Finding a child by position is consistent with adding or removing children at a specific location in the display list. Using the getChildAt() method, you can work with the first child of a container using this familiar syntax:

var dispObj:DisplayObject = getChildAt(0);

If you don't know the location of a child that you wish to manipulate, you can try to find it by name using its instance name. Assuming a child had an instance name of circle, you could store a reference to that child using this syntax:

var dispObj:DisplayObject = getChildByName("circle");

Finally, if you need to know the location of a display object in the display list, but have only its name, you can use the getChildIndex() method to accomplish your goal.

var dispObj:DisplayObject = getChildByName("circle");
var doIndex:int = getChildIndex(dispObj);

Casting a Display Object

Note that, in the preceding discussion, we used DisplayObject as the data type when retrieving a reference to a display object—rather than MovieClip, for example. This is because you may not know if the child is a movie clip, sprite, shape, and so on.

In fact, Flash may not even know the data type, such as when referencing a parent movie clip created using the Flash interface (rather than ActionScript), or even the main timeline. Without the data type information supplied in the ActionScript creation process, Flash sees only the parent timeline as a display object container.

To tell Flash the container in question is a movie clip, you can cast it as such—that is, you can change the data type of that object to MovieClip. For example, consider a movie clip created in the Flash interface that needs to tell its parent, the main timeline, to go to frame 20. A simple line of ActionScript is all that would ordinarily be required:

parent.gotoAndStop(20);

However, because Flash doesn't know that gotoAndStop() is a legal method of the display object container (the stage, for example, can't go to frame 20, and neither can a sprite), you will get the following error:

Call to a possibly undefined method gotoAndStop through a reference
    with static type flash.display:DisplayObjectContainer.

To tell Flash the method is legal for the main timeline, you need only state that the parent is of a data type that supports the method. In this case, the main timeline is a movie clip, so you can say:

MovieClip(parent).gotoAndStop(20);

This will prevent the error from occurring, and the movie clip will be able to successfully send the main timeline to frame 20.

Section 4.4: Changing the Display List Hierarchy

In addition to the improved consistency over previous versions of ActionScript, when adding and removing visual assets at runtime, the display list also makes managing assets much easier. Particularly simplified are: changing the visual stacking order (depth management) and dynamically changing the familial relationship between visual assets (reparenting, or moving a display object from one parent to another).

Depth Management

Adding items to the display list does not require that you specify which level the new child should occupy, because all that is handled for you automatically. This also makes managing the depths of display objects much easier than ever before.

To begin with, you can simply use the addChild() or addChildAt() methods to alter the order of display list items. As we discussed, adding a child to a level below other elements using the addChildAt() method will automatically push the other element depths up a level. But you can also use the addChild() method on an object that already exists in the display list. This step will remove the object from its original position and move it to the top of stack, pushing the other elements down.

For example, consider the following code. Lines 1 through 6 use the standard approach of creating and adding movie clips to the display list, with the added step of giving each clip an instance name. Lines 7 and 8 display the results at this point and, as expected, mc1, or "clip1," is at level 0, and mc2, or "clip2," is at level 1.

1 var mc1:MovieClip = new MovieClip();
2 mc1.name = "clip1";
3 addChild(mc1);
4 var mc2:MovieClip = new MovieClip();
5 mc2.name = "clip2";
6 addChild(mc2);
7 trace(getChildAt(0).name);
8 trace(getChildAt(1).name);

However, if you add mc1 to the display list again, it is moved from position 0 to the end of the list, and mc2 gets pushed to position 0. This can be shown by adding these new lines to the script:

9 addChild (mc1);
10 trace (getChildAt (0).name );
11 trace (getChildAt (1).name );

There are three additional ways to set the z-order of objects that are already in the display list. The swapChildren() method will swap the locations of two known display objects. For example, adding the following line to the ongoing script will swap positions between mc1 and mc2, no matter where they are:

12 swapChildren(mc1, mc2);

If you don't already have references to the children, you can get them using the aforementioned getChildByName() method, or switch the children based on their current levels using the swapChildrenAt() method. Adding the following line to this simplified example will achieve this result, but this method will swap any two levels, even if they're not consecutive.

Pages: 1, 2, 3, 4

Next Pagearrow