blob: 4d6e59d22900498158b28f5643171ed7ccc973cf [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en-us" xml:lang="en-us">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="DC.Type" content="topic"/>
<meta name="DC.Title" content="Create advanced MX visual components in ActionScript"/>
<meta name="DC.Format" content="XHTML"/>
<meta name="DC.Identifier" content="WS2db454920e96a9e51e63e3d11c0bf69084-7cdd_verapache"/>
<link rel="stylesheet" type="text/css" href="commonltr.css"/>
<title>Create advanced MX visual components in ActionScript</title>
</head>
<body id="WS2db454920e96a9e51e63e3d11c0bf69084-7cdd_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7cdd_verapache"><!-- --></a>
<h1 class="topictitle1">Create advanced MX visual components
in ActionScript</h1>
<div>
<p>You can create advanced visual components for use in applications
built with Flex . </p>
</div>
<div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ff0_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ff0_verapache"><!-- --></a>
<h2 class="topictitle2">About creating advanced MX components</h2>
<div>
<p>
Simple
visual components are subclasses of existing Flex components that modify
the appearance of the component by using skins or styles, or add
new functionality to the component. For example, you add a new event
type to a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a> control,
or modify the default styles or skins of a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/DataGrid.html" target="_blank">DataGrid</a> control.
For more information, see <a href="flx_ascomponents_as.html#WS2db454920e96a9e51e63e3d11c0bf69084-7fea_verapache">Create
simple visual components in ActionScript </a>.</p>
<p>In advanced components, you typically perform the following actions:</p>
<ul>
<li>
<p>Modify the visual appearance or visual characteristics
of an existing component.</p>
</li>
<li>
<p>Create a composite component that encapsulates two or more
components within it.</p>
</li>
<li>
<p>Create a component by creating a subclass of the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html" target="_blank">UIComponent</a> class.</p>
</li>
</ul>
<p>You usually create a component as a subclass of an existing class.
For example, to create a component that is based on the Button control,
you create a subclass of the mx.controls.Button class. To make your
own component, you create a subclass of the mx.core.UIComponent
class. </p>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ffa_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ffa_verapache"><!-- --></a>
<h3 class="topictitle3">About overriding protected UIComponent
methods for MX components</h3>
<div>
<p>All Flex visual components are subclasses of the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html" target="_blank">UIComponent</a> class.
Therefore, visual components inherit the methods, properties, events,
styles, and effects defined by the UIComponent class. </p>
<p>To create an advanced visual component, you must implement a
class constructor. Also, you optionally override one or more of
the following protected methods of the UIComponent class:</p>
<div class="tablenoborder"><table cellpadding="4" cellspacing="0" summary="" frame="border" border="1" rules="all">
<thead align="left">
<tr>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e112">
<p>UIComponent method</p>
</th>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e118">
<p>Description</p>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e112 ">
<div class="p">
<pre class="codeblock">commitProperties()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e118 ">
<p>Commits any changes to component properties,
either to make the changes occur at the same time or to ensure that
properties are set in a specific order.</p>
<p>For more information,
see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79eb_verapache">Implementing
the commitProperties() method</a>.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e112 ">
<div class="p">
<pre class="codeblock">createChildren()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e118 ">
<p>Creates any child components of the component.
For example, the ComboBox control contains a TextInput control and
a Button control as child components. </p>
<p>For more information,
see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79ec_verapache">Implementing
the createChildren() method</a>.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e112 ">
<div class="p">
<pre class="codeblock">layoutChrome()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e118 ">
<p>Defines the border area around the container
for subclasses of the Container class. </p>
<p>For more information,
see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79e0_verapache">Implementing
the layoutChrome() method</a>.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e112 ">
<div class="p">
<pre class="codeblock">measure()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e118 ">
<p>Sets the default size and default minimum
size of the component. </p>
<p>For more information, see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79ed_verapache">Implementing
the measure() method</a>.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e112 ">
<div class="p">
<pre class="codeblock">updateDisplayList()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e118 ">
<p>Sizes and positions the children of the
component on the screen based on all previous property and style settings,
and draws any skins or graphic elements used by the component. The
parent container for the component determines the size of the component
itself.</p>
<p>For more information, see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79e9_verapache">Implementing
the updateDisplayList() method</a>.</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>Component users do not call these methods directly; Flex calls
them as part of the initialization process of creating a component,
or when other method calls occur. For more information, see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79e5_verapache">About
the component instantiation life cycle</a>. </p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ff9_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ff9_verapache"><!-- --></a>
<h3 class="topictitle3">About the invalidation methods
for MX components</h3>
<div>
<p>During the lifetime of a component, your application might
modify the component by changing its size or position, modifying
a property that controls its display, or modifying a style or skin
property of the component. For example, you might change the font
size of the text displayed in a component. As part of changing the
font size, the component’s size might also change, which requires Flex
to update the layout of the application. The layout operation might
require Flex to invoke the <samp class="codeph">commitProperties()</samp>, <samp class="codeph">measure()</samp>, <samp class="codeph">layoutChrome()</samp>, and
the <samp class="codeph">updateDisplayList()</samp> methods of your component. </p>
<p>Your application can programmatically change the font size of
a component much faster than Flex can update the layout of an application.
Therefore, you should only want to update the layout after you are
sure that you’ve determined the final value of the font size.</p>
<p>In another scenario, when you set multiple properties of a component,
such as the <samp class="codeph">label</samp> and <samp class="codeph">icon</samp> properties
of a Button control, you want the <samp class="codeph">commitProperties()</samp>, <samp class="codeph">measure()</samp>,
and <samp class="codeph">updateDisplayList()</samp> methods to execute only
once, after all properties are set. You do not want these methods
to execute when you set the <samp class="codeph">label</samp> property, and
then execute again when you set the <samp class="codeph">icon</samp> property.</p>
<p>Also, several components might change their font size at the
same time. Rather than updating the application layout after each
component changes its font size, you want Flex to coordinate the
layout operation to eliminate any redundant processing. </p>
<p>Flex uses an invalidation mechanism to synchronize modifications
to components. Flex implements the invalidation mechanism as a set
of methods that you call to signal that something about the component
has changed and requires Flex to call the component’s <samp class="codeph">commitProperties()</samp>, <samp class="codeph">measure()</samp>, <samp class="codeph">layoutChrome()</samp>,
or <samp class="codeph">updateDisplayList()</samp> methods.</p>
<p>The following table describes the invalidation methods:</p>
<div class="tablenoborder"><table cellpadding="4" cellspacing="0" summary="" frame="border" border="1" rules="all">
<thead align="left">
<tr>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e354">
<p>Invalidation method</p>
</th>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e360">
<p>Description</p>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e354 ">
<div class="p">
<pre class="codeblock">invalidateProperties()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e360 ">
<p>Marks a component so that its <samp class="codeph">commitProperties()</samp> method
gets called during the next screen update.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e354 ">
<div class="p">
<pre class="codeblock">invalidateSize()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e360 ">
<p>Marks a component so that its <samp class="codeph">measure()</samp> method
gets called during the next screen update.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e354 ">
<div class="p">
<pre class="codeblock">invalidateDisplayList()</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e360 ">
<p>Marks a component so that its <samp class="codeph">layoutChrome()</samp> and <samp class="codeph">updateDisplayList()</samp> methods
get called during the next screen update.</p>
</td>
</tr>
</tbody>
</table>
</div>
<p>When a component calls an invalidation method, it signals to
Flex that the component must be updated. When multiple components
call invalidation methods, Flex coordinates updates so that they
all occur together during the next screen update.</p>
<p>Typically, component users do not call the invalidation methods
directly. Instead, they are called by the component’s setter methods,
or by any other methods of a component class as necessary. For more
information and examples, see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79eb_verapache">Implementing
the commitProperties() method</a>.</p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-79e5_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-79e5_verapache"><!-- --></a>
<h3 class="topictitle3">About the component instantiation
life cycle for MX components</h3>
<div>
<p>
The component instantiation
life cycle describes the sequence of steps that occur when you create
a component object from a component class. As part of that life
cycle, Flex automatically calls component methods, dispatches events, and
makes the component visible. </p>
<p>The following example creates a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a> control
in ActionScript and adds it to a container: </p>
<pre class="codeblock"> // Create a Box container.
 var boxContainer:Box = new Box();
 // Configure the Box container.
 // Create a Button control.
 var b:Button = new Button()
 // Configure the button control.
 b.label = "Submit";
 ...
 // Add the Button control to the Box container.
 boxContainer.addChild(b);</pre>
<p>The following steps show what occurs when you execute the code
to create the Button control, and add the control to the Box container: </p>
<ol>
<li>
<p>You call the component’s constructor, as the following
code shows: </p>
<pre class="codeblock"> // Create a Button control.
 var b:Button = new Button()</pre>
</li>
<li>
<p>You configure the component by setting its properties, as
the following code shows:</p>
<pre class="codeblock"> // Configure the button control.
 b.label = "Submit";</pre>
<p>Component setter methods might
call the <samp class="codeph">invalidateProperties()</samp>, <samp class="codeph">invalidateSize()</samp>,
or <samp class="codeph">invalidateDisplayList()</samp> methods.</p>
</li>
<li>
<p>You call the <samp class="codeph">addChild()</samp> method to add the
component to its parent, as the following code shows:</p>
<pre class="codeblock"> // Add the Button control to the Box container.
 boxContainer.addChild(b);</pre>
<p>Flex then performs the
following actions:</p>
</li>
<li>
<p>Sets the <samp class="codeph">parent</samp> property for the component
to reference its parent container. </p>
</li>
<li>
<p>Computes the style settings for the component. </p>
</li>
<li>
<p>Dispatches the <samp class="codeph">preinitialize</samp> event on the
component. </p>
</li>
<li>
<p>Calls the component’s <samp class="codeph">createChildren()</samp> method.</p>
</li>
<li>
<p>Calls the <samp class="codeph">invalidateProperties()</samp>, <samp class="codeph">invalidateSize()</samp>,
and <samp class="codeph">invalidateDisplayList()</samp> methods to trigger
later calls to the <samp class="codeph">commitProperties()</samp>, <samp class="codeph">measure()</samp>,
or <samp class="codeph">updateDisplayList()</samp> methods during the next <samp class="codeph">render</samp> event.</p>
<p>The
only exception to this rule is that Flex does not call the <samp class="codeph">measure()</samp> method
when the user sets the height and width of the component. </p>
</li>
<li>
<p>Dispatches the <samp class="codeph">initialize</samp> event on the component.
At this time, all of the component’s children are initialized, but
the component has not been sized or processed for layout. You can
use this event to perform additional processing of the component
before it is laid out. </p>
</li>
<li>
<p>Dispatches the <samp class="codeph">childAdd</samp> event on the parent
container. </p>
</li>
<li>
<p>Dispatches the <samp class="codeph">initialize</samp> event on the parent
container. </p>
</li>
<li>
<p>During the next <samp class="codeph">render</samp> event, Flex performs
the following actions:</p>
<ol type="a">
<li>
<p>Calls the component’s <samp class="codeph">commitProperties()</samp> method.</p>
</li>
<li>
<p>Calls the component’s <samp class="codeph">measure()</samp> method.</p>
</li>
<li>
<p>Calls the component’s <samp class="codeph">layoutChrome()</samp> method.</p>
</li>
<li>
<p>Calls the component’s <samp class="codeph">updateDisplayList()</samp> method.</p>
</li>
<li>
<p>If steps 13 and 14 are not required, which is the most common
scenario, dispatches the <samp class="codeph">updateComplete</samp> event on
the component. </p>
</li>
</ol>
</li>
<li>
<p>Flex dispatches additional <samp class="codeph">render</samp> events
if the <samp class="codeph">commitProperties()</samp>, <samp class="codeph">measure()</samp>,
or <samp class="codeph">updateDisplayList()</samp> methods call the <samp class="codeph">invalidateProperties()</samp>, <samp class="codeph">invalidateSize()</samp>,
or <samp class="codeph">invalidateDisplayList()</samp> methods. </p>
</li>
<li>
<p>After the last <samp class="codeph">render</samp> event occurs, Flex
performs the following actions: </p>
<ol type="a">
<li>
<p>Makes the component
visible by setting the <samp class="codeph">visible</samp> property to <samp class="codeph">true</samp>. </p>
</li>
<li>
<p>Dispatches the <samp class="codeph">creationComplete</samp> event on
the component. The component is sized and processed for layout.
This event is only dispatched once when the component is created. </p>
</li>
<li>
<p>Dispatches the <samp class="codeph">updateComplete</samp> event on the
component. Flex dispatches additional <samp class="codeph">updateComplete</samp> events
whenever the layout, position, size, or other visual characteristic
of the component changes and the component is updated for display. </p>
</li>
</ol>
</li>
</ol>
<p>Most of the work for configuring a component occurs when you
add the component to a container by using the <samp class="codeph">addChild()</samp> method.
That is because until you add the component to a container, Flex
cannot determine its size, set inheriting style properties, or draw
it on the screen. </p>
<p>You can also define your application in MXML, as the following
example shows:</p>
<pre class="codeblock"> &lt;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"&gt;
  &lt;mx:Box&gt;
  &lt;mx:Button label="Submit"/&gt;
  &lt;/mx:Box&gt;
 &lt;/s:Application&gt;</pre>
<p>The sequence of steps that Flex executes when creating a component
in MXML are equivalent to the steps described for ActionScript. </p>
<p>You can remove a component from a container by using the <samp class="codeph">removeChild()</samp> method.
If there are no references to the component, it is eventually deleted
from memory by the garbage collection mechanism of Adobe<sup>®</sup> Flash<sup>®</sup> Player
or Adobe<sup>®</sup> AIR™.</p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ff7_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ff7_verapache"><!-- --></a>
<h3 class="topictitle3">About the steps for creating a
component for MX components</h3>
<div>
<p>When you implement a component, you override component
methods, define new properties, dispatch new events, or perform
any other customizations required by your application. </p>
<p>To implement your component, follow these general steps: </p>
<ol>
<li>
<p>If necessary, create any skins for the component.</p>
</li>
<li>
<p>Create an ActionScript class file.</p>
<ol type="a">
<li>
<p>Extend one
of the base classes, such as UIComponent or another component class.</p>
</li>
<li>
<p>Specify properties that the user can set by using an MXML
tag property. </p>
</li>
<li>
<p>Embed any graphic and skin files. </p>
</li>
<li>
<p>Implement the constructor.</p>
</li>
<li>
<p>Implement the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#createChildren()" target="_blank">UIComponent.createChildren()</a> method.</p>
</li>
<li>
<p>Implement the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#commitProperties()" target="_blank">UIComponent.commitProperties()</a> method.</p>
</li>
<li>
<p>Implement the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#measure()" target="_blank">UIComponent.measure()</a> method.</p>
</li>
<li>
<p>Implement the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#layoutChrome()" target="_blank">UIComponent.layoutChrome()</a> method.</p>
</li>
<li>
<p>Implement the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#updateDisplayList()" target="_blank">UIComponent.updateDisplayList()</a> method.</p>
</li>
<li>
<p>Add properties, methods, styles, events, and metadata.</p>
</li>
</ol>
</li>
<li>
<p>Deploy the component as an ActionScript file or as a SWC
file.</p>
</li>
</ol>
<p>For more information about MXML tag properties and embedding
graphic and skin files, see <a href="flx_ascomponents_as.html#WS2db454920e96a9e51e63e3d11c0bf69084-7fea_verapache">Create
simple visual components in ActionScript </a>.</p>
<p>You do not have to override all component methods to define a
new component. You only override the methods required to implement
the functionality of your component. If you create a subclass of
an existing component, such as Button control or VBox container,
you must implement the methods necessary for you to add any new
functionality to the component. </p>
<p>For example, you can implement a custom Button control that uses
a new mechanism for defining its default size. In that case, you
only need to override the <samp class="codeph">measure()</samp> method. For
an example, see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79ed_verapache">Implementing
the measure() method</a>.</p>
<p>Or you might implement a new subclass of the VBox container.
Your new subclass uses all of the existing sizing logic of the VBox
class, but changes the layout logic of the class to lay out the
container children from the bottom of the container to the top,
rather than from the top down. In this case, you only need to override
the <samp class="codeph">updateDisplayList()</samp> method. For an example,
see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79e9_verapache">Implementing
the updateDisplayList() method</a>.</p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ffd_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ffd_verapache"><!-- --></a>
<h3 class="topictitle3">About interfaces</h3>
<div>
<p>
Flex uses
interfaces to divide the basic functionality of components into
discrete elements so that they can be implemented piece by piece.
For example, to make your component focusable, it must implement
the IFocusable interface; to let it participate in the layout process,
it must implement ILayoutClient interface.</p>
<p>To simplify the use of interfaces, the UIComponent class implements
all of the interfaces defined in the following table, except for
the IFocusManagerComponent and IToolTipManagerClient interfaces.
However, many subclasses of UIComponent implement the IFocusManagerComponent
and IToolTipManagerClient interfaces. </p>
<p>Therefore, if you create a subclass of the class or subclass
of UIComponent, you do not have to implement these interfaces. But,
if you create a component that is not a subclass of UIComponent,
and you want to use that component in Flex, you might have to implement
one or more of these interfaces. </p>
<div class="note"><span class="notetitle">Note:</span> For Flex, its best that all of your components
extend the UIComponent class or a class that extends UIComponent.</div>
<p>The following table lists the main interfaces implemented by
Flex components:</p>
<div class="tablenoborder"><table cellpadding="4" cellspacing="0" summary="" frame="border" border="1" rules="all">
<thead align="left">
<tr>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e995">
<p>Interface</p>
</th>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e1001">
<p>Use</p>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/styles/IAdvancedStyleClient.html" target="_blank">IAdvancedStyleClient</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that the component supports the
advanced style subsystem.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/automation/IAutomationObject.html" target="_blank">IAutomationObject</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component is an object
within the automation object hierarchy.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IChildList.html" target="_blank">IChildList</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates the number of children in a container.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IConstraintClient.html" target="_blank">IConstraintClient</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that the component support layout
constraints.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IDeferredInstantiationUIComponent.html" target="_blank">IDeferredInstantiationUIComponent</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component or object can
effect deferred instantiation.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IFlexDisplayObject.html" target="_blank">IFlexDisplayObject</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Specifies the interface for skin elements.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IFlexModule.html" target="_blank">IFlexModule</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>indicates that the component can be used
with module factories</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IInvalidating.html" target="_blank">IInvalidating</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component or object can
use the invalidation mechanism to perform delayed, rather than immediate,
property commitment, measurement, and drawing or layout.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/managers/ILayoutManagerClient.html" target="_blank">ILayoutManagerClient</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component or object can
participate in the LayoutManager's commit, measure, and update sequence.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IPropertyChangeNotifier.html" target="_blank">IPropertyChangeNotifier </a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component supports a specialized
form of event propagation.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IRepeaterClient.html" target="_blank">IRepeaterClient</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component or object can
be used with the Repeater class.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IStateClient.html" target="_blank">IStateClient</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that the component supports view
states.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/managers/IToolTipManagerClient.html" target="_blank">IToolTipManagerClient</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component has a <samp class="codeph">toolTip</samp> property,
and therefore is monitored by the ToolTipManager.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IUIComponent.html" target="_blank">IUIComponent</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Defines the basic set of APIs that you must
implement in order to be a child of layout containers and lists.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/validators/IValidatorListener.html" target="_blank">IValidatorListener</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that a component can listen for
validation events, and therefore show a validation state, such as
a red border and error tooltips.</p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e995 ">
<p>
<a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/IVisualElement.html" target="_blank">IVisualElement</a>
</p>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1001 ">
<p>Indicates that the component can be laid
out and displayed in a Spark application.</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ff1_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ff1_verapache"><!-- --></a>
<h2 class="topictitle2">Implementing the component </h2>
<div>
<p>When you create a custom component in ActionScript, you
have to override the methods of the UIComponent class. You implement
the basic component structure, the constructor, and the <samp class="codeph">createChildren()</samp>, <samp class="codeph">commitProperties()</samp>, <samp class="codeph">measure()</samp>, <samp class="codeph">layoutChrome()</samp>,
and <samp class="codeph">updateDisplayList()</samp> methods.</p>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fff_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fff_verapache"><!-- --></a>
<h3 class="topictitle3">Basic component structure</h3>
<div>
<p>The following example shows the basic structure of a Flex
component:</p>
<pre class="codeblock"> package myComponents
 {
 public class MyComponent extends UIComponent
 {
 ....
  }
 }</pre>
<p>You must define your ActionScript custom components within a
package. The package reflects the directory location of your component
within the directory structure of your application.</p>
<p>The class definition of your component must be prefixed by the <samp class="codeph">public</samp> keyword.
A file that contains a class definition can have one, and only one,
public class definition, although it can have additional internal
class definitions. Place any internal class definitions at the bottom
of your source file below the closing curly brace of the package
definition.</p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ff2_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ff2_verapache"><!-- --></a>
<h3 class="topictitle3">Implementing the constructor</h3>
<div>
<p>
Your
ActionScript class should define a public constructor method for
a class that is a subclass of the UIComponent class, or a subclass
of any child of the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html" target="_blank">UIComponent</a> class.
The constructor has the following characteristics:</p>
<ul>
<li>
<p>No return type</p>
</li>
<li>
<p>Should be declared public</p>
</li>
<li>
<p>No arguments</p>
</li>
<li>
<p>Calls the <samp class="codeph">super()</samp> method to invoke the superclass’
constructor</p>
</li>
</ul>
<p>Each class can contain only one constructor method; ActionScript
does not support overloaded constructor methods. For more information,
see <a href="flx_createcomps_basicas_cca.html#WS2db454920e96a9e51e63e3d11c0bf69084-79dd_verapache">Defining the
constructor</a>. </p>
<p>Use the constructor to set the initial values of class properties.
For example, you can set default values for properties and styles,
or initialize data structures, such as Arrays. </p>
<p>Do not create child display objects in the constructor; you should
use it only for setting initial properties of the component. If
your component creates child components, create them in the <samp class="codeph">createChildren()</samp> method. </p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-79ec_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-79ec_verapache"><!-- --></a>
<h3 class="topictitle3">Implementing the createChildren()
method for MX components</h3>
<div>
<p>
A
component that creates other components or visual objects within
it is called a <em>composite component</em>. For example, the Flex <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/ComboBox.html" target="_blank">ComboBox</a> control
contains a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/TextInput.html" target="_blank">TextInput</a> control
to define the text area of the ComboBox, and a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a> control to
define the ComboBox arrow. Components implement the <samp class="codeph">createChildren()</samp> method
to create child objects (such as other components) in the component.</p>
<p>You do not call the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#createChildren()" target="_blank">createChildren()</a> method
directly; Flex calls it when the call to the <samp class="codeph">addChild()</samp> method
occurs to add the component to its parent. Notice that the <samp class="codeph">createChildren()</samp> method
has no invalidation method, which means that you do not have to
call it a second time after the component is added to its parent. </p>
<p>For example, you might define a new component that consists of
a Button control and a TextArea control, where the Button control
enables and disables user input to the TextArea control. The following
example creates the TextArea and Button controls:</p>
<pre class="codeblock"> // Declare two variables for the component children.
 private var text_mc:TextArea;
 private var mode_mc:Button;
 override protected function createChildren():void {
  // Call the createChildren() method of the superclass.
  super.createChildren();
  // Test for the existence of the children before creating them.
  // This is optional, but do this so a subclass can create a different
  // child.
  if (!text_mc) {
  text_mc = new TextArea();
  text_mc.explicitWidth = 80;
  text_mc.editable = false;
  text_mc.addEventListener("change", handleChangeEvent);
  // Add the child component to the custom component.
<strong>addChild(text_mc);</strong>
  }
  // Test for the existence of the children before creating them.
  if (!mode_mc) {
  mode_mc = new Button();
  mode_mc.label = "Toggle Editing";
  mode_mc.addEventListener("click", handleClickEvent);
  // Add the child component to the custom component.
<strong>addChild(mode_mc);</strong>
  }
 }</pre>
<p>Notice in this example that the <samp class="codeph">createChildren()</samp> method
calls the <samp class="codeph">addChild()</samp> method to add the child component.
You must call the <samp class="codeph">addChild()</samp> method for each child
object.</p>
<p>After you create a child component, you can use properties of
the child component to define its characteristics. In this example,
you create the Button and TextArea controls, initialize them, and
register event listeners for them. You could also apply skins to
the child components. For a complete example, see <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79e8_verapache">Example:
Creating a composite component</a>.</p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-79eb_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-79eb_verapache"><!-- --></a>
<h3 class="topictitle3">Implementing the commitProperties()
method for MX components</h3>
<div>
<p>
You
use the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#commitProperties()" target="_blank">commitProperties()</a> method
to coordinate modifications to component properties. Most often,
you use it with properties that affect how a component appears on
the screen. </p>
<p>Flex schedules a call to the <samp class="codeph">commitProperties()</samp> method
when a call to the <samp class="codeph">invalidateProperties()</samp> method
occurs. The <samp class="codeph">commitProperties()</samp> method executes
during the next <samp class="codeph">render</samp> event after a call to the <samp class="codeph">invalidateProperties()</samp> method.
When you use the <samp class="codeph">addChild()</samp> method to add a component
to a container, Flex automatically calls the <samp class="codeph">invalidateProperties()</samp> method. </p>
<p>
Calls to the <samp class="codeph">commitProperties()</samp> method
occur before calls to the <samp class="codeph">measure()</samp> method. This
lets you set property values that the <samp class="codeph">measure()</samp> method
might use. </p>
<p>The typical pattern for defining component properties is to define
the properties by using getter and setter methods, as the following
example shows: </p>
<pre class="codeblock"> // Define a private variable for the alignText property.
 private var _alignText:String = "right";
 // Define a flag to indicate when the _alignText property changes.
 private var bAlignTextChanged:Boolean = false;
 // Define getter and setter methods for the property.
 public function get alignText():String {
  return _alignText;
 }
 public function set alignText(t:String):void {
  _alignText = t;
  bAlignTextChanged = true;
<strong>// Trigger the commitProperties(), measure(), and updateDisplayList() </strong>
<strong>// methods as necessary. </strong>
<strong>// In this case, you do not need to remeasure the component. </strong>
<strong>invalidateProperties();</strong>
<strong>invalidateDisplayList();</strong>
 }
 // Implement the commitProperties() method.
 override protected function commitProperties():void {
  super.commitProperties();
<strong>// Check whether the flag indicates a change to the alignText property. </strong>
<strong>if (bAlignTextChanged) {</strong>
  // Reset flag.
  bAlignTextChanged = false;
  // Handle alignment change
  }
 }</pre>
<p>As you can see in this example, the setter method modifies the
property, calls the <samp class="codeph">invalidateProperties()</samp> and <samp class="codeph">invalidateDisplayList()</samp> methods, and
then returns. The setter itself does not perform any calculations
based on the new property value. This design lets the setter method
return quickly, and leaves any processing of the new value to the <samp class="codeph">commitProperties()</samp> method. </p>
<p>Changing the alignment of text in a control does not necessarily
change the control’s size. However, if it does, include a call to
the <samp class="codeph">invalidateSize()</samp> method to trigger the <samp class="codeph">measure()</samp> method. </p>
<p>The main advantages of using the <samp class="codeph">commitProperties()</samp> method
are the following:</p>
<ul>
<li>
<p>To coordinate the modifications of multiple properties
so that the modifications occur synchronously.</p>
<p>For example,
you might define multiple properties that control the text displayed
by the component, such as the alignment of the text within the component.
A change to either the text or the alignment property requires Flex
to update the appearance of the component. However, if you modify
both the text and the alignment, you want Flex to perform any calculations
for sizing or positioning the component once, when the screen updates. </p>
<p>Therefore,
you use the <samp class="codeph">commitProperties()</samp> method to calculate
any values based on the relationship of multiple component properties.
By coordinating the property changes in the <samp class="codeph">commitProperties()</samp> method,
you can reduce unnecessary processing overhead. </p>
</li>
<li>
<p>To coordinate multiple modifications to the same property.</p>
<p>You
do not necessarily want to perform a complex calculation every time
a user updates a component property. For example, users modify the <samp class="codeph">icon</samp> property
of the Button control to change the image displayed in the button. Calculating
the label position based on the presence or size of an icon can
be a computationally expensive operation that you want to perform
only when necessary. </p>
<p>To avoid this behavior, you use the <samp class="codeph">commitProperties()</samp> method
to perform the calculations. Flex calls the <samp class="codeph">commitProperties()</samp> method when
it updates the display. That means you perform the calculations
once when Flex updates the screen, regardless of the number of times
the property changed between screen updates. </p>
</li>
</ul>
<p>The following example shows how you can handle two related properties
in the <samp class="codeph">commitProperties()</samp> method:</p>
<pre class="codeblock"><strong>// Define a private variable for the text property.</strong>
 private var _text:String = "ModalText";
 private var bTextChanged:Boolean = false;
 // Define the getter method.
 public function get text():String {
  return _text;
 }
 //Define the setter method to call invalidateProperties()
 // when the property changes.
 public function set text(t:String):void {
  _text = t;
  bTextChanged = true;
<strong>invalidateProperties();</strong>
<strong>// Changing the text causes the control to recalculate its default size.</strong>
<strong>invalidateSize();</strong>
<strong>invalidateDisplayList();</strong>
 }
<strong>// Define a private variable for the alignText property.</strong>
 private var _alignText:String = "right";
 private var bAlignTextChanged:Boolean = false;
 public function get alignText():String {
  return _alignText;
 }
 public function set alignText(t:String):void {
  _alignText = t;
  bAlignTextChanged = true;
<strong>invalidateProperties();</strong>
<strong>invalidateDisplayList();</strong>
 }
 // Implement the commitProperties() method.
 override protected function commitProperties():void {
  super.commitProperties();
<strong>// Check whether the flags indicate a change to both properties. </strong>
<strong>if (bTextChanged &amp;&amp; bAlignTextChanged) {</strong>
  // Reset flags.
  bTextChanged = false;
  bAlignTextChanged = false;
  // Handle case where both properties changed.
  }
  // Check whether the flag indicates a change to the text property.
  if (bTextChanged) {
  // Reset flag.
  bTextChanged = false;
  // Handle text change.
  }
  // Check whether the flag indicates a change to the alignText property.
  if (bAlignTextChanged) {
  // Reset flag.
  bAlignTextChanged = false;
  // Handle alignment change.
  }
 }</pre>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-79ed_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-79ed_verapache"><!-- --></a>
<h3 class="topictitle3">Implementing the measure() method
for MX components</h3>
<div>
<p>
The <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#measure()" target="_blank">measure()</a> method
sets the default component size, in pixels, and optionally sets
the component’s default minimum size. </p>
<p>Flex schedules a call to the <samp class="codeph">measure()</samp> method
when a call to the <samp class="codeph">invalidateSize()</samp> method occurs.
The <samp class="codeph">measure()</samp> method executes during the next <samp class="codeph">render</samp> event
after a call to the <samp class="codeph">invalidateSize()</samp> method. When
you use the <samp class="codeph">addChild()</samp> method to add a component
to a container, Flex automatically calls the <samp class="codeph">invalidateSize()</samp> method. </p>
<p>When you set a specific height and width of a component, Flex
does not call the <samp class="codeph">measure()</samp> method, even if you
explicitly call the <samp class="codeph">invalidateSize()</samp> method. That
is, Flex calls the <samp class="codeph">measure()</samp> method only if the <samp class="codeph">explicitWidth</samp> property
or the <samp class="codeph">explicitHeight</samp> property of the component
is <samp class="codeph">NaN</samp>. </p>
<p>In the following example, because you explicitly set the size
of the Button control, Flex does not call the <samp class="codeph">Button.measure()</samp> method: </p>
<pre class="codeblock"> &lt;mx:Button height="10" width="10"/&gt;</pre>
<p>In a subclass of an existing component, you might implement the <samp class="codeph">measure()</samp> method
only if you are performing an action that requires modification
to the default sizing rules defined in the superclass. Therefore,
to set a new default size, or perform calculations at run time to
determine component sizing rules, implement the <samp class="codeph">measure()</samp> method. </p>
<p>You set the following properties in the <samp class="codeph">measure()</samp> method
to specify the default size: </p>
<div class="tablenoborder"><table cellpadding="4" cellspacing="0" summary="" frame="border" border="1" rules="all">
<thead align="left">
<tr>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e1852">
<p>Properties</p>
</th>
<th class="cellrowborder" valign="top" width="NaN%" id="d37436e1858">
<p>Description</p>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1852 ">
<div class="p">
<pre class="codeblock">measuredHeightmeasuredWidth</pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1858 ">
<p>Specifies the default height and width of
the component, in pixels. </p>
<p>These properties are set to 0 until
the <samp class="codeph">measure()</samp> method executes. Although you can
leave them set to 0, it makes the component invisible by default. </p>
</td>
</tr>
<tr>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1852 ">
<div class="p">
<pre class="codeblock">measuredMinHeightmeasuredMinWidth </pre>
</div>
</td>
<td class="cellrowborder" valign="top" width="NaN%" headers="d37436e1858 ">
<p>Specifies the default minimum height and
minimum width of the component, in pixels. Flex cannot set the size
of a component smaller than its specified minimum size. </p>
</td>
</tr>
</tbody>
</table>
</div>
<p>The <samp class="codeph">measure()</samp> method only sets the default size
of the component. In the <samp class="codeph">updateDisplayList()</samp> method,
the parent container of the component passes to it its actual size,
which may be different than the default size. </p>
<p>Component users can also override the default size settings in
an application by using the component in the following ways:</p>
<ul>
<li>
<p>Setting the <samp class="codeph">explicitHeight</samp> and <samp class="codeph">exlicitWidth</samp> properties</p>
</li>
<li>
<p>Setting the <samp class="codeph">width</samp> and <samp class="codeph">height</samp> properties</p>
</li>
<li>
<p>Setting the <samp class="codeph">percentHeight</samp> and <samp class="codeph">percentWidth</samp> properties</p>
</li>
</ul>
<p>For example, you can define a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a> control
with a default size of 100 pixels wide and 50 pixels tall, and a
default minimum size of 50 pixels by 25 pixels, as the following
example shows:</p>
<pre class="codeblock">package myComponents
{
// asAdvanced/myComponents/BlueButton.as
import mx.controls.Button;
public class BlueButton extends Button {
public function BlueButton() {
super();
}
override protected function measure():void {
super.measure();
measuredWidth=100;
measuredMinWidth=50;
measuredHeight=50;
measuredMinHeight=25;
}
}
}</pre>
<p>The following application uses this button in an application:</p>
<pre class="codeblock">&lt;?xml version="1.0"?&gt;
&lt;!-- asAdvanced/ASAdvancedMainBlueButton.mxml --&gt;
&lt;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"
xmlns:MyComp="myComponents.*" &gt;
&lt;mx:VBox&gt;
&lt;MyComp:BlueButton/&gt;
&lt;mx:Button/&gt;
&lt;/mx:VBox&gt;
&lt;/s:Application&gt;</pre>
<p>In the absence of any other sizing constraints on the button,
 the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/containers/VBox.html" target="_blank">VBox</a> container uses
the default size and default minimum size of the button to calculate
its size at run time. For information on the rules for sizing a
component, see <a href="flx_containers_intro_cn.html#WS2db454920e96a9e51e63e3d11c0bf69084-7ffa_verapache">Introduction to
containers</a>. </p>
<p>You can override the default size settings in an application,
as the following example shows:</p>
<pre class="codeblock">&lt;?xml version="1.0"?&gt;
&lt;!-- asAdvanced/MainBlueButtonResize.mxml --&gt;
&lt;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"
xmlns:MyComp="myComponents.*" &gt;
&lt;mx:VBox&gt;
&lt;MyComp:BlueButton width="50%"/&gt;
&lt;mx:Button/&gt;
&lt;/mx:VBox&gt;
&lt;/s:Application&gt;</pre>
<p>In this example, you specify that the width of the button is
50% of the width of the VBox container. When 50% of the width of
the container is smaller than the minimum width of the button, the
button uses its minimum width. </p>
</div>
<div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ff6_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ff6_verapache"><!-- --></a>
<h4 class="topictitle4">Calculating default sizes</h4>
<div>
<p>The example in <a href="flx_ascomponents_advanced_asa.html#WS2db454920e96a9e51e63e3d11c0bf69084-79ed_verapache">Implementing
the measure() method</a> uses static values for the default size
and default minimum size of a component. Some Flex components use
static sizes. For example, the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/TextArea.html" target="_blank">TextArea</a> control
has a default size of 100 pixels wide by 44 pixels high, regardless
of the text it contains. If the text is larger than the TextArea
control, the control displays scroll bars. </p>
<p>Often, you set the default size based on characteristics of the
component or information passed to the component. For example, the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a> control’s <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#measure()" target="_blank">measure</a>
<samp class="codeph">()</samp> method
examines its label text, margin settings, and font characteristics
to determine the control’s default size.</p>
<p>In the following example, you override the <samp class="codeph">measure()</samp> method
of the TextArea control so that it examines the text passed to the
control, and calculates the default size of the TextArea control
to display the entire text string in a single line:</p>
<pre class="codeblock">package myComponents
{
// asAdvanced/myComponents/MyTextArea.as
import mx.controls.TextArea;
import flash.text.TextLineMetrics;
public class MyTextArea extends TextArea
{
public function MyTextArea() {
super();
}
// The default size is the size of the text plus a 10 pixel margin.
override protected function measure():void {
super.measure();
// Calculate the default size of the control based on the
// contents of the TextArea.text property.
var lineMetrics:TextLineMetrics = measureText(text);
// Add a 10 pixel border area around the text.
measuredWidth = measuredMinWidth = lineMetrics.width + 10;
measuredHeight = measuredMinHeight = lineMetrics.height + 10;
}
}
}</pre>
<p>For text strings that are longer than the display area of your
application, you can add logic to increase the height of the TextArea
control to display the text on multiple lines. The following application
uses this component:</p>
<pre class="codeblock">&lt;?xml version="1.0"?&gt;
&lt;!-- asAdvanced/MainMyTextArea.mxml --&gt;
&lt;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"
xmlns:MyComp="myComponents.*"
width="1000"&gt;
&lt;s:layout&gt;
&lt;s:VerticalLayout/&gt;
&lt;/s:layout&gt;
&lt;MyComp:MyTextArea id="myTA" text="This is a long text strring that would normally cause a TextArea control to display scroll bars. But, the custom MyTextArea control calcualtes its default size based on the text size."/&gt;
&lt;mx:TextArea id="flexTA" text="This is a long text strring that would normally cause a TextArea control to display scroll bars. But, the custom MyTextArea control calcualtes its default size based on the text size."/&gt;
&lt;/s:Application&gt;</pre>
</div>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-79e0_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-79e0_verapache"><!-- --></a>
<h3 class="topictitle3">Implementing the layoutChrome()
method for MX components</h3>
<div>
<p>
The <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/Container.html" target="_blank">Container</a> class,
and some subclasses of the Container class, use the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/Container.html#layoutChrome()" target="_blank">layoutChrome()</a> method
to define the border area around the container.</p>
<p>Flex schedules a call to the <samp class="codeph">layoutChrome()</samp> method
when a call to the <samp class="codeph">invalidateDisplayList()</samp> method
occurs. The <samp class="codeph">layoutChrome()</samp> method executes during
the next <samp class="codeph">render</samp> event after a call to the <samp class="codeph">invalidateDisplayList()</samp> method.
When you use the <samp class="codeph">addChild()</samp> method to add a component
to a container, Flex automatically calls the <samp class="codeph">invalidateDisplayList()</samp> method. </p>
<p>Typically, you use the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/skins/RectangularBorder.html" target="_blank">RectangularBorder</a> class
to define the border area of a container. For example, you can create
the RectangularBorder object, and add it as a child of the component
in your override of the <samp class="codeph">createChildren()</samp> method. </p>
<p>When you create a subclass of the Container class, you can use
the <samp class="codeph">createChildren()</samp> method to create the content
children of the container; the content children are the child components
that appear within the container. You then use <samp class="codeph">updateDisplayList()</samp> to
position the content children.</p>
<p>You typically use the <samp class="codeph">layoutChrome()</samp> method
to define and position the border area of the container, and any
additional elements that you want to appear in the border area.
For example, the Panel container uses the <samp class="codeph">layoutChrome()</samp> method
to define the title area of the panel container, including the title
text and close button. </p>
<p>The primary reason for dividing the handling of the content area
of a container from its border area is to handle the situation when
the <samp class="codeph">Container.autoLayout</samp> property is set to <samp class="codeph">false</samp>.
When the <samp class="codeph">autoLayout</samp> property is set to <samp class="codeph">true</samp>,
measurement and layout of the container and of its children are
done whenever the position or size of a container child changes.
The default value is <samp class="codeph">true</samp>. </p>
<p>When the <samp class="codeph">autoLayout</samp> property is set to <samp class="codeph">false</samp>,
measurement and layout are done only once, when children are added
to or removed from the container. However, Flex executes the <samp class="codeph">layoutChrome()</samp> method
in both cases. Therefore, the container can still update its border
area even when the <samp class="codeph">autoLayout</samp> property is set to <samp class="codeph">false</samp>.</p>
</div>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-79e9_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-79e9_verapache"><!-- --></a>
<h3 class="topictitle3">Implementing the updateDisplayList()
method for MX components</h3>
<div>
<p>
The <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#updateDisplayList()" target="_blank">updateDisplayList()</a> method
sizes and positions the children of your component based on all
previous property and style settings, and draws any skins or graphic
elements that the component uses. The parent container for the component
determines the size of the component itself.</p>
<p>A component does not appear on the screen until its <samp class="codeph">updateDisplayList()</samp> method
gets called. Flex schedules a call to the <samp class="codeph">updateDisplayList()</samp> method
when a call to the <samp class="codeph">invalidateDisplayList()</samp> method
occurs. The <samp class="codeph">updateDisplayList()</samp> method executes
during the next <samp class="codeph">render</samp> event after a call to the <samp class="codeph">invalidateDisplayList()</samp> method.
When you use the <samp class="codeph">addChild()</samp> method to add a component
to a container, Flex automatically calls the <samp class="codeph">invalidateDisplayList()</samp> method. </p>
<p>The main uses of the <samp class="codeph">updateDisplayList()</samp> method
are the following:</p>
<ul>
<li>
<p>To set the size and position of the elements of the component
for display. </p>
<p>Many components are made up of one or more child
components, or have properties that control the display of information
in the component. For example, the Button control lets you specify
an optional icon, and use the <samp class="codeph">labelPlacement</samp> property
to specify where the button text appears relative to the icon. </p>
<p>The <samp class="codeph">Button.updateDisplayList()</samp> method
uses the settings of the <samp class="codeph">icon</samp> and <samp class="codeph">labelPlacement</samp> properties
to control the display of the button.</p>
<p>For containers that
have child controls, the <samp class="codeph">updateDisplayList()</samp> method
controls how those child components are positioned. For example, the <samp class="codeph">updateDisplayList()</samp> method
on the HBox container positions its children from left to right
in a single row; the <samp class="codeph">updateDisplayList()</samp> method
for a VBox container positions its children from top to bottom in
a single column. </p>
<p>To size components in the <samp class="codeph">updateDisplayList()</samp> method,
you use the <samp class="codeph">setActualSize()</samp> method, not the sizing
properties, such as <samp class="codeph">width</samp> and <samp class="codeph">height</samp>.
To position a component, use the <samp class="codeph">move()</samp> method,
not the <samp class="codeph">x</samp> and <samp class="codeph">y</samp> properties. </p>
</li>
<li>
<p>To draw any visual elements necessary for the component.</p>
<p>Components
support many types of visual elements such as skins, styles, and borders.
Within the <samp class="codeph">updateDisplayList()</samp> method, you can
add these visual elements, use the Flash drawing APIs, and perform
additional control over the visual display of your component. </p>
</li>
</ul>
<p>The <samp class="codeph">updateDisplayList()</samp> method has the following
signature:</p>
<pre class="codeblock"> protected function updateDisplayList(unscaledWidth:Number,
  unscaledHeight:Number):void</pre>
<p>The properties have the following values:</p>
<dl>
<dt class="dlterm">unscaledWidth </dt>
<dd>
<p>Specifies the width of the component, in pixels, in the component’s
coordinates, regardless of the value of the scaleX property of the component.
This is the width of the component as determined by its parent container. </p>
</dd>
<dt class="dlterm">unscaledHeight </dt>
<dd>
<p>Specifies the height of the component, in pixels, in the component’s
coordinates, regardless of the value of the <samp class="codeph">scaleY</samp> property
of the component. This is the height of the component as determined
by its parent container.</p>
<p>Scaling occurs in Flash Player or
AIR, after <samp class="codeph">updateDisplayList()</samp> executes. For example,
a component with an <samp class="codeph">unscaledHeight</samp> value of 100,
and with a <samp class="codeph">scaleY</samp> property of 2.0, appears 200
pixels high in Flash Player or AIR. </p>
</dd>
</dl>
</div>
<div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf68641-7ff3_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7ff3_verapache"><!-- --></a>
<h4 class="topictitle4">Overriding the layout mechanism
of the VBox container</h4>
<div>
<p>
The <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/containers/VBox.html" target="_blank">VBox</a> container
lays out its children from the top of the container to the bottom,
in the order in which the children are added to the container. The following
example overrides the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html#updateDisplayList()" target="_blank">updateDisplayList()</a> method,
which causes the VBox container to layout its children from the
bottom of the container to the top:</p>
<pre class="codeblock">package myComponents
{
// asAdvanced/myComponents/BottomUpVBox.as
import mx.containers.VBox;
import mx.core.EdgeMetrics;
import mx.core.UIComponent;
public class BottomUpVBox extends VBox
{
public function BottomUpVBox() {
super();
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
// Get information about the container border area.
// The usable area of the container for its children is the
// container size, minus any border areas.
var vm:EdgeMetrics = viewMetricsAndPadding;
// Get the setting for the vertical gap between children.
var gap:Number = getStyle("verticalGap");
// Determine the y coordinate of the bottom of the usable area
// of the VBox.
var yOfComp:Number = unscaledHeight-vm.bottom;
// Temp variable for a container child.
var obj:UIComponent;
for (var i:int = 0; i &lt; numChildren; i++)
{
// Get the first container child.
obj = UIComponent(getChildAt(i));
// Determine the y coordinate of the child.
yOfComp = yOfComp - obj.height;
// Set the x and y coordinate of the child.
// Note that you do not change the x coordinate.
obj.move(obj.x, yOfComp);
// Save the y coordinate of the child,
// plus the vertical gap between children.
// This is used to calculate the coordinate
// of the next child.
yOfComp = yOfComp - gap;
}
}
}
}</pre>
<p>In this example, you use the <samp class="codeph">UIComponent.move()</samp> method
to set the position of each child in the container. You can also
use the <samp class="codeph">UIComponent.x</samp> and <samp class="codeph">UIComponent.y</samp> properties
to set these coordinates. The difference is that the <samp class="codeph">move()</samp> method
changes the location of the component and then dispatches a <samp class="codeph">move</samp> event
when you call the method immediately; setting the <samp class="codeph">x</samp> and <samp class="codeph">y</samp> properties
changes the location of the component and dispatches the event on
the next screen update. </p>
<p>The following application uses this component:</p>
<pre class="codeblock">&lt;?xml version="1.0"?&gt;
&lt;!-- asAdvanced/MainBottomVBox.mxml --&gt;
&lt;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"
xmlns:MyComp="myComponents.*" &gt;
&lt;MyComp:BottomUpVBox&gt;
&lt;mx:Label text="Label 1"/&gt;
&lt;mx:Button label="Button 1"/&gt;
&lt;mx:Label text="Label 2"/&gt;
&lt;mx:Button label="Button 2"/&gt;
&lt;mx:Label text="Label 3"/&gt;
&lt;mx:Button label="Button 3"/&gt;
&lt;mx:Label text="Label 4"/&gt;
&lt;mx:Button label="Button 4"/&gt;
&lt;/MyComp:BottomUpVBox&gt;
&lt;/s:Application&gt;</pre>
</div>
</div>
<div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fea_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fea_verapache"><!-- --></a>
<h4 class="topictitle4">Drawing graphics in your component</h4>
<div>
<p>Every Flex component is a subclass of the Flash <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Sprite.html" target="_blank">Sprite</a> class,
and therefore inherits the <samp class="codeph">Sprite.graphics</samp> property.
The <samp class="codeph">Sprite.graphics</samp> property specifies a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html" target="_blank">Graphics</a> object
that you can use to add vector drawings to your component.</p>
<p>For example, in the <samp class="codeph">updateDisplayList()</samp> method,
you can use methods of the Graphics class to draw borders, rules,
and other graphical elements:</p>
<pre class="codeblock"> override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
  super.updateDisplayList(unscaledWidth, unscaledHeight);
  // Draw a simple border around the child components.
  graphics.lineStyle(1, 0x000000, 1.0);
  graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
 }</pre>
</div>
</div>
</div>
</div>
<div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe9_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe9_verapache"><!-- --></a>
<h2 class="topictitle2">Making components accessible</h2>
<div>
<p>
A
growing requirement for web content is that it should be accessible
to people who have disabilities. Visually impaired people can use
the visual content in Flash applications by using screen reader
software, which provides an audio description of the material on
the screen.</p>
<p>When you create a component, you can include ActionScript that
enables the component and a screen reader for audio communication.
When developers use your component to build an application in Flash,
they use the Accessibility panel to configure each component instance.</p>
<p>Flash includes the following accessibility features:</p>
<ul>
<li>
<p>Custom focus navigation</p>
</li>
<li>
<p>Custom keyboard shortcuts</p>
</li>
<li>
<p>Screen-based documents and the screen authoring environment</p>
</li>
<li>
<p>An Accessibility class</p>
</li>
</ul>
<p>To enable accessibility in your component, add the following
line to your component’s class file:</p>
<pre class="codeblock"> mx.accessibility.ComponentName.enableAccessibility();</pre>
<p>For example, the following line enables accessibility for the
MyButton component:</p>
<pre class="codeblock"> mx.accessibility.MyButton.enableAccessibility();</pre>
<p>For additional information about accessibility, see <a href="flx_accessible_ac.html#WS2db454920e96a9e51e63e3d11c0bf69084-7f60_verapache">Accessible
applications </a>.</p>
</div>
</div>
<div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe8_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe8_verapache"><!-- --></a>
<h2 class="topictitle2">Adding version numbers</h2>
<div>
<p>
When releasing components,
you can define a version number. This lets developers know whether
they should upgrade, and helps with technical support issues. When
you set a component’s version number, use the static variable <samp class="codeph">version</samp>,
as the following example shows:</p>
<pre class="codeblock"> static var version:String = "1.0.0.42";</pre>
<div class="note"><span class="notetitle">Note:</span> Flex does not use or interpret the value of
the <samp class="codeph">version</samp> property. </div>
<p>If you create many components as part of a component package,
you can include the version number in an external file. That way,
you update the version number in only one place. For example, the
following code imports the contents of an external file that stores
the version number in one place:</p>
<pre class="codeblock"> include "../myPackage/ComponentVersion.as"</pre>
<p>The contents of the ComponentVersion.as file are identical to
the previous variable declaration, as the following example shows:</p>
<pre class="codeblock"> static var version:String = "1.0.0.42";</pre>
</div>
</div>
<div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf68641-8000_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-8000_verapache"><!-- --></a>
<h2 class="topictitle2">Best practices when designing a component</h2>
<div>
<p>
Use
the following practices when you design a component:</p>
<ul>
<li>
<p>Keep the file size as small as possible. </p>
</li>
<li>
<p>Make your component as reusable as possible by generalizing
functionality. </p>
</li>
<li>
<p>Use the Border class rather than graphical elements to draw
borders around objects. </p>
</li>
<li>
<p>Assume an initial state. Because style properties are on
the object, you can set initial settings for styles and properties
so your initialization code does not have to set them when the object
is constructed, unless the user overrides the default state. </p>
</li>
</ul>
</div>
</div>
<div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf69084-79e8_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-79e8_verapache"><!-- --></a>
<h2 class="topictitle2">Example: Creating a composite MX component</h2>
<div>
<p>
<em>Composite components</em> are
components that contain multiple components. They might be graphical
assets or a combination of graphical assets and component classes.
For example, you can create a component that includes a button and
a text field, or a component that includes a button, a text field,
and a validator. </p>
<p>When you create composite components, you should instantiate
the controls inside the component’s class file. Assuming that some
of these controls have graphical assets, you must plan the layout
of the controls that you are including, and set properties such
as default values in your class file. You must also ensure that
you import all the necessary classes that the composite component
uses.</p>
<p>Because the class extends one of the base classes, such as <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html" target="_blank">UIComponent</a>,
and not a controls class like <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a>, you
must instantiate each of the controls as children of the custom
component and arrange them on the screen.</p>
<p>Properties of the individual controls are not accessible from
the MXML author’s environment unless you design your class to allow
this. For example, if you create a component that extends the UIComponent
class and uses a Button and a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/TextArea.html" target="_blank">TextArea</a> component,
you cannot set the Button control’s label text in the MXML tag because
you do not directly extend the Button class. </p>
</div>
<div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe6_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe6_verapache"><!-- --></a>
<h3 class="topictitle3">Creating the component</h3>
<div>
<p>This example component, called ModalText and defined in
the file ModalText.as, combines a Button control and a TextArea
control. You use the Button control to enable or disable text input
in the TextArea control. </p>
</div>
<div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe5_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe5_verapache"><!-- --></a>
<h4 class="topictitle4">Defining event listeners for composite
components</h4>
<div>
<p>Custom components implement the <samp class="codeph">createChildren()</samp> method
to create children of the component, as the following example shows: </p>
<pre class="codeblock"> override protected function createChildren():void {
  super.createChildren();
  // Create and initialize the TextArea control.
  if (!text_mc) {
  text_mc = new TextArea();
  ...
  text_mc.addEventListener("change", handleChangeEvent);
  addChild(text_mc);
  }
  // Create and initialize the Button control.
  if (!mode_mc) {
  mode_mc = new Button();
  ...
  mode_mc.addEventListener("click", handleClickEvent);
  addChild(mode_mc);
  }
 }</pre>
<p>The <samp class="codeph">createChildren()</samp> method also contains a
call to the <samp class="codeph">addEventListener()</samp> method to register
an event listener for the <samp class="codeph">change</samp> event generated
by the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/TextArea.html" target="_blank">TextArea</a> control,
and for the <samp class="codeph">click</samp> event for the <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a> control.
These event listeners are defined within the ModalText class, as
the following example shows:</p>
<pre class="codeblock"> // Handle events that are dispatched by the children.
 private function handleChangeEvent(eventObj:Event):void {
  dispatchEvent(new Event("change"));
 }
 // Handle events that are dispatched by the children.
 private function handleClickEvent(eventObj:Event):void {
  text_mc.editable = !text_mc.editable;
 }</pre>
<p>You can handle an event dispatched by a child of a composite
component in the component. In this example, the event listener
for the Button control’s <samp class="codeph">click</samp> event is defined
in the class definition to toggle the <samp class="codeph">editable</samp> property
of the TextArea control.</p>
<p>However, if a child component dispatches an event, and you want
that opportunity to handle the event outside of the component, you
must add logic to your custom component to propagate the event.
Notice that the event listener for the <samp class="codeph">change</samp> event
for the TextArea control propagates the event. This lets you handle
the event in your application, as the following example shows:</p>
<pre class="codeblock"> &lt;?xml version="1.0"?&gt;
 &lt;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"
xmlns:MyComp="myComponents.*"&gt;
  &lt;fx:Script&gt;
  &lt;![CDATA[
  import flash.events.Event;
  function handleText(eventObj:Event)
  {
  ...
  }
  ]]&gt;
  &lt;/fx:Script&gt;
  &lt;MyComp:ModalText change="handleText(event);"/&gt;
 &lt;/s:Application&gt;</pre>
</div>
</div>
<div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe4_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe4_verapache"><!-- --></a>
<h4 class="topictitle4">Creating the ModalText component</h4>
<div>
<p>The following code example implements the class definition
for the ModalText component. The ModalText component is a composite
component that contains a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/Button.html" target="_blank">Button</a> control
and a <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/TextArea.html" target="_blank">TextArea</a> control.
This control has the following attributes:</p>
<ul>
<li>
<p>You cannot edit the TextArea control by default.</p>
</li>
<li>
<p>You click the Button control to toggle editing of the TextArea
control.</p>
</li>
<li>
<p>You use the <samp class="codeph">textPlacement</samp> property of the
control to make the TextArea appear on the right side or the left
side of the control.</p>
</li>
<li>
<p>Editing the <samp class="codeph">textPlacement</samp> property of the
control dispatches the <samp class="codeph">placementChanged</samp> event. </p>
</li>
<li>
<p>You use the <samp class="codeph">text</samp> property to programmatically
write content to the TextArea control. </p>
</li>
<li>
<p>Editing the <samp class="codeph">text</samp> property of the control
dispatches the <samp class="codeph">textChanged</samp> event. </p>
</li>
<li>
<p>Editing the text in the TextArea control dispatches the <samp class="codeph">change</samp> event.</p>
</li>
<li>
<p>You can use both the <samp class="codeph">textPlacement</samp> property
or the <samp class="codeph">text</samp> property as the source for a data binding
expression. </p>
</li>
<li>
<p>You can optionally use skins for the up, down, and over states
of the Button control.</p>
</li>
</ul>
<p>The following is an example MXML file that uses the ModalText
control and sets the <samp class="codeph">textPlacement</samp> property to <samp class="codeph">left</samp>:</p>
<pre class="codeblock">&lt;?xml version="1.0"?&gt;
&lt;!-- asAdvanced/ASAdvancedMainModalText.mxml --&gt;
&lt;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"
xmlns:MyComp="myComponents.*" &gt;
&lt;MyComp:ModalText textPlacement="left" height="40"/&gt;
&lt;/s:Application&gt;</pre>
<p>You can handle the <samp class="codeph">placementChanged</samp> event to
determine when the <samp class="codeph">ModalText.textPlacement</samp> property
is modified, as the following example shows:</p>
<pre class="codeblock">&lt;?xml version="1.0"?&gt;
&lt;!-- asAdvanced/ASAdvancedMainModalTextEvent.mxml --&gt;
&lt;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"
xmlns:MyComp="myComponents.*" &gt;
&lt;s:layout&gt;
&lt;s:VerticalLayout/&gt;
&lt;/s:layout&gt;
&lt;fx:Script&gt;
&lt;![CDATA[
import flash.events.Event;
private function placementChangedListener(event:Event):void {
myEvent.text="placementChanged event occurred - textPlacement = "
+ myMT.textPlacement as String;
}
]]&gt;
&lt;/fx:Script&gt;
&lt;MyComp:ModalText id="myMT"
textPlacement="left"
height="40"
placementChanged="placementChangedListener(event);"/&gt;
&lt;mx:TextArea id="myEvent" width="50%"/&gt;
&lt;mx:Label text="Change Placement" /&gt;
&lt;mx:Button label="Set Text Placement Right"
click="myMT.textPlacement='right';" /&gt;
&lt;mx:Button label="Set Text Placement Left"
click="myMT.textPlacement='left';" /&gt;
&lt;/s:Application&gt;</pre>
<p>The following example shows the ModalText.as file that defines
this control:</p>
<pre class="codeblock">package myComponents
{
// asAdvanced/myComponents/ModalText.as
// Import all necessary classes.
import mx.core.UIComponent;
import mx.controls.Button;
import mx.controls.TextArea;
import flash.events.Event;
import flash.text.TextLineMetrics;
// ModalText dispatches a change event when the text of the child
// TextArea control changes, a textChanged event when you set the text
// property of ModalText, and a placementChanged event
// when you change the textPlacement property of ModalText.
[Event(name="change", type="flash.events.Event")]
[Event(name="textChanged", type="flash.events.Event")]
[Event(name="placementChanged", type="flash.events.Event")]
/*** a) Extend UIComponent. ***/
public class ModalText extends UIComponent {
/*** b) Implement the class constructor. ***/
public function ModalText() {
super();
}
/*** c) Define variables for the two child components. ***/
// Declare two variables for the component children.
private var text_mc:TextArea;
private var mode_mc:Button;
/*** d) Embed new skins used by the Button component. ***/
// You can create a SWF file that contains symbols with the names
// ModalUpSkin, ModalOverSkin, and ModalDownSkin.
// If you do not have skins, comment out these lines.
[Embed(source="Modal2.swf", symbol="blueCircle")]
public var modeUpSkinName:Class;
[Embed(source="Modal2.swf", symbol="blueCircle")]
public var modeOverSkinName:Class;
[Embed(source="Modal2.swf", symbol="greenSquare")]
public var modeDownSkinName:Class;
/*** e) Implement the createChildren() method. ***/
// Test for the existence of the children before creating them.
// This is optional, but we do this so a subclass can create a
// different child instead.
override protected function createChildren():void {
super.createChildren();
// Create and initialize the TextArea control.
if (!text_mc)
{
text_mc = new TextArea();
text_mc.explicitWidth = 80;
text_mc.editable = false;
text_mc.text= _text;
text_mc.addEventListener("change", handleChangeEvent);
addChild(text_mc);
}
// Create and initialize the Button control.
if (!mode_mc)
{ mode_mc = new Button();
mode_mc.label = "Toggle Editing Mode";
// If you do not have skins available,
// comment out these lines.
mode_mc.setStyle('overSkin', modeOverSkinName);
mode_mc.setStyle('upSkin', modeUpSkinName);
mode_mc.setStyle('downSkin', modeDownSkinName);
mode_mc.addEventListener("click", handleClickEvent);
addChild(mode_mc);
}
}
/*** f) Implement the commitProperties() method. ***/
override protected function commitProperties():void {
super.commitProperties();
if (bTextChanged) {
bTextChanged = false;
text_mc.text = _text;
invalidateDisplayList();
}
}
/*** g) Implement the measure() method. ***/
// The default width is the size of the text plus the button.
// The height is dictated by the button.
override protected function measure():void {
super.measure();
// Since the Button control uses skins, get the
// measured size of the Button control.
var buttonWidth:Number = mode_mc.getExplicitOrMeasuredWidth();
var buttonHeight:Number = mode_mc.getExplicitOrMeasuredHeight();
// The default and minimum width are the measuredWidth
// of the TextArea control plus the measuredWidth
// of the Button control.
measuredWidth = measuredMinWidth =
text_mc.measuredWidth + buttonWidth;
// The default and minimum height are the larger of the
// height of the TextArea control or the measuredHeight of the
// Button control, plus a 10 pixel border around the text.
measuredHeight = measuredMinHeight =
Math.max(mode_mc.measuredHeight,buttonHeight) + 10;
}
/*** h) Implement the updateDisplayList() method. ***/
// Size the Button control to the size of its label text
// plus a 10 pixel border area.
// Size the TextArea to the remaining area of the component.
// Place the children depending on the setting of
// the textPlacement property.
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
// Subtract 1 pixel for the left and right border,
// and use a 3 pixel margin on left and right.
var usableWidth:Number = unscaledWidth - 8;
// Subtract 1 pixel for the top and bottom border,
// and use a 3 pixel margin on top and bottom.
var usableHeight:Number = unscaledHeight - 8;
// Calculate the size of the Button control based on its text.
var lineMetrics:TextLineMetrics = measureText(mode_mc.label);
// Add a 10 pixel border area around the text.
var buttonWidth:Number = lineMetrics.width + 10;
var buttonHeight:Number = lineMetrics.height + 10;
mode_mc.setActualSize(buttonWidth, buttonHeight);
// Calculate the size of the text
// Allow for a 5 pixel gap between the Button
// and the TextArea controls.
var textWidth:Number = usableWidth - buttonWidth - 5;
var textHeight:Number = usableHeight;
text_mc.setActualSize(textWidth, textHeight);
// Position the controls based on the textPlacement property.
if (textPlacement == "left") {
text_mc.move(4, 4);
mode_mc.move(4 + textWidth + 5, 4);
}
else {
mode_mc.move(4, 4);
text_mc.move(4 + buttonWidth + 5, 4);
}
// Draw a simple border around the child components.
graphics.lineStyle(1, 0x000000, 1.0);
graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
}
/*** i) Add methods, properties, and metadata. ***/
// The general pattern for properties is to specify a private
// holder variable.
private var _textPlacement:String = "left";
// Create a getter/setter pair for the textPlacement property.
public function set textPlacement(p:String):void {
_textPlacement = p;
invalidateDisplayList();
dispatchEvent(new Event("placementChanged"));
}
// The textPlacement property supports data binding.
[Bindable(event="placementChanged")]
public function get textPlacement():String {
return _textPlacement;
}
private var _text:String = "ModalText";
private var bTextChanged:Boolean = false;
// Create a getter/setter pair for the text property.
public function set text(t:String):void {
_text = t;
bTextChanged = true;
invalidateProperties();
dispatchEvent(new Event("textChanged"));
}
[Bindable(event="textChanged")]
public function get text():String {
return text_mc.text;
}
// Handle events that are dispatched by the children.
private function handleChangeEvent(eventObj:Event):void {
dispatchEvent(new Event("change"));
}
// Handle events that are dispatched by the children.
private function handleClickEvent(eventObj:Event):void {
text_mc.editable = !text_mc.editable;
}
}
}</pre>
</div>
</div>
</div>
</div>
<div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache"><!-- --></a>
<h2 class="topictitle2">Troubleshooting</h2>
<div>
<div class="section" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fe2_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fe2_verapache"><!-- --></a><h3 class="sectiontitle">I
get an error “don't know how to parse…” when I try to use the component
from MXML.</h3>
<p>This means that the compiler could not find
the SWC file, or the contents of the SWC file did not list the component.
Ensure that the SWC file is in a directory that Flex searches, and
ensure that your <samp class="codeph">xmlns</samp> property is pointing to
the right place. Try moving the SWC file to the same directory as
the MXML file and setting the namespace to "*" as the following
example shows:</p>
<pre class="codeblock"> &lt;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"
xmlns="*"&gt;</pre>
<p>For more information, see <a href="flx_compilers_cpl.html#WS2db454920e96a9e51e63e3d11c0bf69084-7ffd_verapache">Flex
compilers</a>.</p>
</div>
<div class="section" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7ff8_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7ff8_verapache"><!-- --></a><h3 class="sectiontitle">I
get an error “xxx is not a valid attribute…” when I try to use the
component from MXML.</h3>
<p>Ensure that the attribute is spelled
correctly. Also ensure that it is not private.</p>
</div>
<div class="section" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fe1_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fe1_verapache"><!-- --></a><h3 class="sectiontitle">I
don't get any errors, but nothing appears.</h3>
<p>Verify that
the component was instantiated. One way to do this is to put a Button control
and a TextArea control in the MXML application and set the <samp class="codeph">text</samp> property
to the ID for the component when the button is clicked. For example: </p>
<pre class="codeblock"> &lt;!-- This verifies whether a component was instantiated. --&gt;
 &lt;zz:mycomponent id="foo"/&gt;
 &lt;mx:TextArea id="output"/&gt;
 &lt;mx:Button label="Print Output" click="output.text = foo.id;"/&gt; </pre>
</div>
<div class="section" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fef_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fef_verapache"><!-- --></a><h3 class="sectiontitle">The
component is instantiated properly but does not appear (1).</h3>
<p>In
some cases, helper classes are not ready by the time your component
requires them. Flex adds classes to the application in the order
that they must be initialized (base classes, and then child classes).
However, if you have a static method that gets called as part of
the initialization of a class, and that static method has class
dependencies, Flex does not know to place that dependent class before
the other class, because it does not know when that method is going to
be called.</p>
<p>One possible remedy is to add a static variable
dependency to the class definition. Flex knows that all static variable
dependencies must be ready before the class is initialized, so it
orders the class loading correctly.</p>
<p>The following example
adds a static variable to tell the linker that class A must be initialized
before class B:</p>
<pre class="codeblock"> public class A {
  static function foo():Number {
  return 5;
  }
 }
 public class B {
  static function bar():Number {
  return mx.example.A.foo();
  }
  static var z = B.bar();
  // Dependency
<strong>static var ADependency:mx.example.A = mx.example.A;</strong>
 }</pre>
</div>
<div class="section" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fee_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fee_verapache"><!-- --></a><h3 class="sectiontitle">The
component is instantiated properly but does not appear (2).</h3>
<p>Verify
that the <samp class="codeph">measuredWidth</samp> and <samp class="codeph">measuredHeight</samp> properties
are nonzero. If they are zero or <samp class="codeph">NaN</samp>, ensure that
you implemented the <samp class="codeph">measure()</samp> method correctly. </p>
<p>You
can also verify that the <samp class="codeph">visible</samp> property is set
to <samp class="codeph">true</samp>. If <samp class="codeph">visible </samp>is<samp class="codeph"> false</samp>,
ensure that your component called the <samp class="codeph">invalidateDisplayList()</samp> method.</p>
</div>
<div class="section" id="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fed_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf68641-7fe3_verapache__WS2db454920e96a9e51e63e3d11c0bf68641-7fed_verapache"><!-- --></a><h3 class="sectiontitle">The
component is instantiated properly but does not appear (3).</h3>
<p>It
is possible that there is another class or SWC file that overrides
your custom class or the symbols used in your component. Ensure
that there are no naming conflicts.</p>
<p/>
</div>
</div>
<p>Adobe, Adobe AIR, Adobe Flash and Adobe Flash Player are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries and are used by permission from Adobe. No other license to the Adobe trademarks are granted.</p>
</div>
</body>
</html>