You
typically use MXML to lay out the user interface of your application,
and use ActionScript for event handling and run-time control of
the application. You can also use ActionScript to create component
instances at run time. For example, you could use MXML to define
an empty Accordion container and use ActionScript to add panels
to the container in response to user actions.
About the display list and container children
Flash Player
maintains a tree of visible (or potentially visible) objects that
make up your application. The root of the tree is the Spark Application
or MX Application object, and child containers and components are
branches and leaf nodes of the tree. That tree is known as the display list.
When you add child components to a container or remove child components
from a container, you are adding and removing them from the display
list. You can also change their relative positions by changing their
positions in the display list.
Although the display list is a tree rooted at the top of the
application, when you manipulate a container’s children by ’s methods
and properties, you only access the container’s direct children.
Treat the container’s children as items in a list, where the first
child has an index of 0.
Using the container API for managing container children
Spark Group and SkinnableContainer containers, and all
MX containers, provide properties and methods that you use to manage
the container’s children. Because the Spark Group and SkinnableContainer
containers can hold many types of children, the methods that you
use to manipulate its children refer to the children by a generic
name of element.
Note: This section does not apply to the
Spark DataGroup and Spark SkinnableDataContainer. Those containers
use a data provider to define their children. You manage the children
of those containers in the same way that you manage any data provider control.
For more information, see Data providers and collections and The Spark DataGroup and Spark SkinnableDataContainer containers.
The following table shows these properties and methods:
Spark container
MX container
Description
numElements
numChildren
Number of children in the container.
addElement()
addChild()
Adds a child to the container as the last
child.
addElementAt()
addChildAt()
Add a child at a specific index in the container.
getChildren()
Returns an Array containing all children.
getElementAt()
getChildAt()
Return a child at the specified index.
getChildByName()
Return a child with the specified id.
getElementIndex()
getChildIndex()
Returns the index of a child.
removeAllElements()
removeAllChildren()
Removes all container children.
removeElement()
removeChild()
Remove the first child.
removeElementAt()
removeChildAt()
Remove the child at the specified index
setElementIndex()
setChildIndex()
Set the index of a child.
swapElements()
swapChildren()
Swap the indexes of two children
swapElementsAt()
swapChildrenAt()
Swap the indexes of two children.
Note: Make sure that you use the correct method for your type
of container, either Spark or MX. Using the wrong method can cause
unexpected results.
Obtaining the number of child components in a container or application
Use
the numElements or numChildren property
to obtain a count of the number of direct child components that
the container has in the display list. The following application
gets the number of children in the application and a Group container.
The Group control has five label controls, and therefore has five children.
The Application container has the Group and Button controls as its children,
and therefore has two children.
<?xml version="1.0"?>
<!-- containers\intro\VBoxNumChildren.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
// Import the Alert class.
import mx.controls.Alert;
public function calculateChildren():void {
var myText:String = new String();
myText="The Group container has " +
myGroup.numElements + " children.";
myText+="\nThe application has " +
numElements + " children.";
Alert.show(myText);
}
]]>
</fx:Script>
<s:VGroup id="myGroup">
<s:Label text="This is label 1."/>
<s:Label text="This is label 2."/>
<s:Label text="This is label 3."/>
<s:Label text="This is label 4."/>
<s:Label text="This is label 5."/>
</s:VGroup>
<s:Button label="Show Children" click="calculateChildren();"/>
</s:Application>
The executing SWF file for the previous example is shown below:
In the main MXML application
file, the file that contains the <s:Application> tag,
the current scope is always the Application object. Therefore, the
reference to the numElements property without an
object prefix refers to the numElements property
of the Application object. For more information on accessing the
root application, see About scope.
Accessing display-only children
The MX Container class defines the rawChildren property
that contains the full display list of all the children of a container.
This list includes all the container’s children, plus the DisplayObjects
that implement the container’s chrome (display elements),
such as its border and the background image.
The numChildren property
and accessor methods let you count and access only child components.
However, the container might contain style elements and skins, such
as the border and background. The container’s rawChildren property
lets you access all children of a container, including the component “content
children” and the skin and style “display children.” The object
returned by the rawChildren property implements
the IChildList interface. You then use methods and properties of
this interface, such as getChildAt(), to access and
manipulate all the container’s children.
Creating and removing components at run time
To create a component instance at run time, you define
it, set any properties, and then add it as a child of a parent container
by calling the addElement() or addChild() method
on the parent container.
The addElement() method has the following signature:
addElement(element:IVisualElement):IVisualElement
The element argument specifies the component
to add to the container.
The addChild() method has the following signature:
addChild(child:DisplayObject):DisplayObject
The child argument specifies the component to
add to the container.
Note: Although the child argument
of the addChild() method is specified as type DisplayObject,
the argument must implement the IUIComponent interface to be added
as a child of a container. All Flex components implement this interface.
For example, the following application creates a Group container
with an Button control called myButton:
<?xml version="1.0"?>
<!-- containers\intro\ContainerAddChild.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
import spark.components.Button;
public function addButton():void {
var myButton:Button = new Button();
myButton.label = "New Button";
myGroup.addElement(myButton);
}
]]>
</fx:Script>
<s:Group id="myGroup" initialize="addButton();"/>
</s:Application>
The executing SWF file for the previous example is shown below:
This example creates the control when the application is loaded
rather than in response to any user action. However, you could add
a new button when the user presses an existing button, as the following
example shows:
<?xml version="1.0"?>
<!-- containers\intro\ContainerAddChild2.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
import spark.components.Button;
public function addButton():void {
var myButton:Button = new Button();
myButton.label = "New Button";
myGroup.addElement(myButton);
}
]]>
</fx:Script>
<s:HGroup id="myGroup">
<s:Button label="Add Button" click="addButton();"/>
</s:HGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
You use the removeElement() or removeChild() method
to remove a control from a container. If the child is no longer
referenced anywhere else in your application after the call, it
gets destroyed by a garbage collection process. The following example
removes a button from the application when the user presses it:
<?xml version="1.0"?>
<!-- containers\intro\ContainerRemoveChild.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
public function removeButton():void {
myGroup.removeElement(myButton);
}
private function resetApp():void {
if (myGroup.numElements == 0) {
myGroup.addElement(myButton);
}
}
]]>
</fx:Script>
<s:Group id="myGroup">
<s:Button id="myButton"
label="Remove Me"
click="removeButton();"/>
</s:Group>
<s:Button label="Reset" click="resetApp();"/>
</s:Application>
The executing SWF file for the previous example is shown below:
Example: Creating and removing a child of a container
The following
example uses MXML to define a container that contains two Button
controls. You use one Button control to add an CheckBox control
to the container, and one Button control to delete it.
<?xml version="1.0"?>
<!-- containers\intro\ContainerComponentsExample.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
// Import the CheckBox class.
import spark.components.CheckBox;
// Define a variable to hold the new CheckBox control.
private var myCheckBox:CheckBox;
// Define a variable to track if the CheckBox control
// is in the display list.
private var checkBoxDisplayed:Boolean = false;
public function addCB():void {
// Make sure the check box isn't being displayed.
if(checkBoxDisplayed==false){
// Create the check box if it does not exist.
if (!myCheckBox) {
myCheckBox = new CheckBox();
myCheckBox.label = "New CheckBox";
}
// Add the check box.
myGroup.addElement(myCheckBox);
checkBoxDisplayed=true;
}
}
public function delCB():void {
// Make sure a CheckBox control exists.
if(checkBoxDisplayed){
myGroup.removeElement(myCheckBox);
checkBoxDisplayed=false;
}
}
]]>
</fx:Script>
<s:VGroup id="myGroup">
<s:Button label="Add CheckBox"
click="addCB();"/>
<s:Button label="Remove CheckBox"
click="delCB();"/>
</s:VGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
Example: Creating and removing children of an Accordion container
The
following example adds panels to and removes them from an MX Accordion container.
The Accordion container initially contains one panel. Each time
you select the Add HBox button, it adds a new HBox container to
the Accordion container.
Note: MX navigators can only take MX containers
and the Spark NavigatorContent container as children. You cannot
use other Spark containers as direct children of a navigator container.
Instead, wrap the Spark container in an MX container on in a Spark
NavigatorContent container when adding the Spark container to a
navigator.
<?xml version="1.0"?>
<!-- containers\intro\ContainerComponentsExample2.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
/* Import HBox class. */
import mx.containers.HBox;
/* Array of created containers. */
private var myHBoxes:Array = [];
public function addHBox():void {
/* Create new HBox container. */
var newHBox:HBox = new HBox();
newHBox.label="Label: " + String(myHBoxes.length);
/* Add it to the Accordion container, and to the
Array of HBox containers. */
myHBoxes.push(myAcc.addChild(newHBox));
}
public function delHBox():void {
/* If there is at least one HBox container in the Array,
remove it. */
if (myHBoxes.length>= 1) {
myAcc.removeChild(myHBoxes.pop());
}
}
]]>
</fx:Script>
<s:VGroup>
<mx:Accordion id="myAcc" height="150" width="150">
<mx:HBox/>
</mx:Accordion>
<s:Button label="Add HBox" click="addHBox();"/>
<s:Button label="Remove HBox" click="delHBox();"/>
</s:VGroup>
</s:Application>
The executing SWF file for the previous example is shown below:
Controlling child order
You can control the order of children by adding them in
a specific order. You can also control them as follows:
By using the addElementAt() or addChildAt() method
to specify where among the component’s children to add a child
Note: As with the addChild() method,
although the child argument of the addChildAt() method
is specified as type DisplayObject, the argument must implement
the IUIComponent interface to be added as a child of a container.
All Flex components implement this interface.
By using the setElementAt() or setChildIndex() method
to specify the location of a specific child among a component’s
children in the display list
The following example modifies the previous example. It uses
the addElementAt() method to add the CheckBox control
as the first child (index 0) of the VGroup. It also has a Reorder
children button that uses the setChildIndex() method
to move a CheckBox control down the display list until it is the
last child in the VGroup container.
<?xml version="1.0"?>
<!-- containers\intro\ContainerComponentsReorder.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
// Import the CheckBox and Alert classes.
import spark.components.CheckBox;
import mx.controls.Alert;
// Define a variable to hold the new CheckBox control.
private var myCheckBox:CheckBox;
// Define a variable to track if the CheckBox control
// is in the display list.
private var checkBoxDisplayed:Boolean = false;
public function addCB():void {
// Make sure the check box isn't being displayed.
if(checkBoxDisplayed==false){
// Create the check box if it does not exist.
if (!myCheckBox) {
myCheckBox = new CheckBox();
myCheckBox.label = "New CheckBox";
}
// Add the check box as the first child of the container.
myGroup.addElementAt(myCheckBox, 0);
checkBoxDisplayed=true;
}
}
public function delCB():void {
// Make sure a CheckBox control exists.
if(checkBoxDisplayed){
myGroup.removeElement(myCheckBox);
checkBoxDisplayed=false;
}
}
public function reorder():void {
// Make sure a CheckBox control exists.
if(checkBoxDisplayed==true)
{
// Don't try to move the check box past the end
// of the children. Because indexes are 0 based,
// the last child index is one less
// than the number of children.
if (myGroup.getElementIndex(myCheckBox) < myGroup.numElements-1)
{
// Increment the checkBoxIndex variable and use it to
// set the index of the check box among the VBox children.
myGroup.setElementIndex(myCheckBox,
myGroup.getElementIndex(myCheckBox) + 1);
}
}
else {
Alert.show("Add the check box before you can move it");
}
}
]]>
</fx:Script>
<s:VGroup id="myGroup">
<s:Button label="Add CheckBox" click="addCB();"/>
<s:Button label="Remove CheckBox" click="delCB();"/>
<s:Button label="Reorder children" click="reorder();"/>
</s:VGroup>
</s:Application>
The executing SWF file for the previous example is shown below: