Adobe Flex 3 Developer Guide
Adobe Flex 3 Developer Guide
® ®
DEVELOPER GUIDE
© 2008 Adobe Systems Incorporated. All rights reserved.
Adobe® Flex® 3 Developer Guide
If this guide is distributed with software that includes an end-user agreement, this guide, as well as the software described in it, is furnished under license
and may be used or copied only in accordance with the terms of such license. Except as permitted by any such license, no part of this guide may be
reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, recording, or otherwise, without the prior
written permission of Adobe Systems Incorporated. Please note that the content in this guide is protected under copyright law even if it is not distributed
with software that includes an end-user license agreement.
The content of this guide is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by
Adobe Systems Incorporated. Adobe Systems Incorporated assumes no responsibility or liability for any errors or inaccuracies that may appear in the
informational content contained in this guide.
Please remember that existing artwork or images that you may want to include in your project may be protected under copyright law. The unauthorized
incorporation of such material into your new work could be a violation of the rights of the copyright owner. Please be sure to obtain any permission
required from the copyright owner.
Any references to company names in sample templates are for demonstration purposes only and are not intended to refer to any actual organization.
Adobe, the Adobe logo, ActionScript, Adobe AIR, ColdFusion, Fireworks, Flash, Flex, Illustrator, LiveCycle, and Photoshop are either registered
trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries.
Java is a trademark or registered trademark of Sun Microsystems, Inc. in the United States and other countries. Linux is a registered trademark of Linus
Torvalds. Macintosh is a trademark of Apple Inc., registered in the United States and other countries. Microsoft, OpenType, Windows, Windows ME,
and Windows Vista are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Sun is a
registered trademark or trademark of Sun Microsystems, Inc. in the United States and other countries. All other trademarks are the property of their
respective owners.
This product includes software developed by the Apache Software Foundation (http://www.apache.org/)
This product contains either BISAFE and/or TIPEM software by RSA Data Security, Inc.
The Flex Builder 3 software contains code provided by the Eclipse Foundation (“Eclipse Code”). The source code for the Eclipse Code as contained in
Flex Builder 3 software (“Eclipse Source Code”) is made available under the terms of the Eclipse Public License v1.0 which is provided herein, and is
also available at http://www.eclipse.org/legal/epl-v10.html.
Adobe Systems Incorporated, 345 Park Avenue, San Jose, CA 95110-2704, USA.
Notice to U.S. government end users. The software and documentation are “Commercial Items,” as that term is defined at 48 C.F.R. §2.101, consisting
of “Commercial Computer Software” and “Commercial Computer Software Documentation,” as such terms are used in 48 C.F.R. §12.212 or 48 C.F.R.
§227.7202, as applicable. Consistent with 48 C.F.R. §12.212 or 48 C.F.R. §§227.7202-1 through 227.7202-4, as applicable, the Commercial Computer
Software and Commercial Computer Software Documentation are being licensed to U.S. Government end users (a) only as Commercial items and (b)
with only those rights as are granted to all other end users pursuant to the terms and conditions herein. Unpublished-rights reserved under the
copyright laws of the United States. For U.S. Government End Users, Adobe agrees to comply with all applicable equal opportunity laws including, if
appropriate, the provisions of Executive Order 11246, as amended, Section 402 of the Vietnam Era Veterans Readjustment Assistance Act of 1974 (38
USC 4212), and Section 503 of the Rehabilitation Act of 1973, as amended, and the regulations at 41 CFR Parts 60-1 through 60-60, 60-250 ,and 60-
741. The affirmative action clause and regulations contained in the preceding sentence shall be incorporated by reference.
Part Number: 90085057 (01/08)
iii
Contents
Part 1: Flex Programming Elements
Chapter 9: Controls
About controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Working with controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Button control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
PopUpButton control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
ButtonBar and ToggleButtonBar controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
LinkBar control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
TabBar control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
CheckBox control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
v
Topics
About MXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Developing applications. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
About MXML
You use two languages to write Flex applications: MXML and ActionScript. MXML is an XML markup language
that you use to lay out user interface components. You also use MXML to declaratively define nonvisual aspects
of an application, such as access to data sources on the server and data bindings between user interface compo-
nents and data sources on the server.
Like HTML, MXML provides tags that define user interfaces. MXML will seem very familiar if you have worked
with HTML. However, MXML is more structured than HTML, and it provides a much richer tag set. For example,
MXML includes tags for visual components such as data grids, trees, tab navigators, accordions, and menus, as
well as nonvisual components that provide web service connections, data binding, and animation effects. You can
also extend MXML with custom components that you reference as MXML tags.
One of the biggest differences between MXML and HTML is that MXML-defined applications are compiled into
SWF files and rendered by Adobe® Flash® Player or Adobe® AIR™, which provides a richer and more dynamic user
interface than page-based HTML applications.
You can write an MXML application in a single file or in multiple files. MXML also supports custom components
written in MXML and ActionScript files.
4 CHAPTER 1
Developing applications
MXML development is based on the same iterative process used for other types of web application files such as
HTML, JavaServer Pages (JSP), Active Server Pages (ASP), and ColdFusion Markup Language (CFML). Devel-
oping a useful Flex application is as easy as opening your favorite text editor, typing some XML tags, saving the
file, requesting the file’s URL in a web browser, and then repeating the same process.
Flex also provides tools for code debugging. For more information, see “Using the Command-Line Debugger” on
page 245 in Building and Deploying Adobe Flex 3 Applications.
The following image shows an example Flex application that contains a List control on the left side of the user
interface and a TabNavigator container on the right side. Both controls are enclosed in a Panel container.
<mx:TabNavigator borderStyle="solid">
<mx:VBox label="Pane1" width="300" height="150">
<mx:TextArea text="Hello World"/>
<mx:Button label="Submit"/>
</mx:VBox>
</mx:TabNavigator>
</mx:HBox>
</mx:Panel>
</mx:Application>
The List control and TabNavigator container are laid out side by side because they are in an HBox container. The
controls in the TabNavigator container are laid out from top to bottom because they are in a VBox container.
For more information about laying out user interface components, see “Using Flex Visual Components” on
page 113.
<mx:HBox>
<mx:TextInput id="myText"/>
<mx:Button click="storeZipInDatabase(myText.text)"/>
</mx:HBox>
</mx:Application>
Typical properties of a control tag include id, width, height, fontSize, color, event listeners for events such as
click and change, and effect triggers such as showEffect and rollOverEffect. For information about the
standard Flex controls, see “Controls” on page 223.
10 CHAPTER 1
XML namespaces give you the ability to use custom tags that are not in the MXML namespace. The following
example shows an application that contains a custom tag called CustomBox. The namespace value
containers.boxes.* indicates that an MXML component called CustomBox is in the containers/boxes
directory.
<?xml version="1.0"?>
<!-- mxml/XMLNamespaces.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComps="containers.boxes.*"
>
<mx:Panel title="My Application"
paddingTop="10"
paddingBottom="10"
paddingLeft="10"
paddingRight="10"
>
<MyComps:CustomBox/>
</mx:Panel>
</mx:Application>
The containers/boxes directory can be a subdirectory of the directory that contains the application file, or it can
be a subdirectory of one of the ActionScript source path directories assigned in the flex-config.xml file. If copies
of the same file exist in both places, Flex uses the file in the application file directory. The prefix name is arbitrary,
but it must be used as declared.
When using a component contained in a SWC file, the package name and the namespace must match, even
though the SWC file is in the same directory as the MXML file that uses it. A SWC file is an archive file for Flex
components. SWC files make it easy to exchange components among Flex developers. You exchange only a single
file, rather than the MXML or ActionScript files and images, along with other resource files. Also, the SWF file
inside a SWC file is compiled, which means that the code is obfuscated from casual view. For more information
on SWC files, see “Using the Flex Compilers” on page 125 in Building and Deploying Adobe Flex 3 Applications.
The following example shows the code for a version of the application in which the event listener is contained in
an ActionScript function in an <mx:Script> tag:
<?xml version="1.0"?>
<!-- mxml/TriggerCodeExample2.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function hello():void {
textarea1.text="Hello World";
}
]]>
</mx:Script>
<mx:Panel title="My Application"
paddingTop="10"
paddingBottom="10"
paddingLeft="10"
paddingRight="10"
>
<mx:TextArea id="textarea1"/>
<mx:Button label="Submit" click="hello();"/>
</mx:Panel>
</mx:Application>
For more information about using ActionScript with MXML, see “Using ActionScript” on page 37.
ADOBE FLEX 3 13
Adobe Flex 3 Developer Guide
As an alternative to the curly braces ({ }) syntax, you can use the <mx:Binding> tag, in which you specify the
source and destination of a binding. For more information about data binding, see “Storing Data” on page 1257.
The MXML components that provide data access are called RPC components. MXML includes the following
types of RPC components:
• WebService provides access to SOAP-based web services.
• HTTPService provides access to HTTP URLs that return data.
• RemoteObject provides access to Java objects using the AMF protocol (Adobe LiveCycle Data Services ES
only).
The following example shows an application that calls a web service that provides weather information, and
displays the current temperature for a given ZIP code. The application binds the ZIP code that a user enters in a
TextInput control to a web service input parameter. It binds the current temperature value contained in the web
service result to a TextArea control.
<?xml version="1.0"?>
<!-- mxml/RPCExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- Define the web service connection
(the specified WSDL URL is not functional). -->
<mx:WebService id="WeatherService"
wsdl="http:/example.com/ws/WeatherService?wsdl"
useProxy="false">
<!-- Bind the value of the ZIP code entered in the TextInput control
to the ZipCode parameter of the GetWeather operation. -->
<mx:operation name="GetWeather">
<mx:request>
<ZipCode>{zip.text}</ZipCode>
</mx:request>
</mx:operation>
</mx:WebService>
<!-- Call the web service operation with a Button click. -->
<mx:Button width="60" label="Get Weather"
click="WeatherService.GetWeather.send();"/>
<!-- Display the location for the specified ZIP code. -->
<mx:Label text="Location:"/>
<mx:TextArea text="{WeatherService.GetWeather.lastResult.Location}"/>
<!-- Display the current temperature for the specified ZIP code. -->
<mx:Label text="Temperature:"/>
<mx:TextArea
text="{WeatherService.GetWeather.lastResult.CurrentTemp}"/>
</mx:Panel>
</mx:Application>
ADOBE FLEX 3 15
Adobe Flex 3 Developer Guide
The following image shows the application rendered in a web browser window:
For more information about using RPC services, see “Accessing Server-Side Data with Flex” on page 1163.
<mx:TextInput id="homePhoneInput"
text="This isn't a valid phone number."/>
<mx:TextInput id="cellPhoneInput" text="(999)999-999"/>
<mx:TextInput id="emailInput" text="[email protected]"/>
</mx:Panel>
</mx:Application>
Validating data
You can use validator components to validate data stored in a data model, or in a Flex user interface component.
Flex includes a set of standard validator components. You can also create your own.
The following example uses validator components for validating that the expected type of data is entered in the
TextInput fields. Validation is triggered automatically when the user edits a TextInput control. If validation fails,
the user receives immediate visual feedback.
<?xml version="1.0"?>
<!-- mxml/ValidatingExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- A data model called "contact" stores contact information.
The text property of each TextInput control shown above
is passed to a field of the data model. -->
<mx:Model id="contact">
<info>
<homePhone>{homePhoneInput.text}</homePhone>
<cellPhone>{cellPhoneInput.text}</cellPhone>
<email>{emailInput.text}</email>
</info>
</mx:Model>
<!-- Validator components validate data entered into the TextInput controls. -->
<mx:PhoneNumberValidator id="pnV"
source="{homePhoneInput}" property="text"/>
<mx:PhoneNumberValidator id="pnV2"
source="{cellPhoneInput}" property="text"/>
<mx:EmailValidator id="emV" source="{emailInput}" property="text" />
</mx:Application>
ADOBE FLEX 3 17
Adobe Flex 3 Developer Guide
The following image shows the application rendered in a web browser window:
For more information about using data models, see “Storing Data” on page 1257. For more information on
validators, see “Validating Data” on page 1267.
Formatting data
Formatter components are ActionScript components that perform a one-way conversion of raw data to a
formatted string. They are triggered just before data is displayed in a text field. Flex includes a set of standard
formatters. You can also create your own formatters. The following example shows an application that uses the
standard ZipCodeFormatter component to format the value of a variable:
<?xml version="1.0"?>
<!-- mxml/FormatterExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
private var storedZipCode:Number=123456789;
]]>
</mx:Script>
The following image shows the application rendered in a web browser window:
For more information about formatter components, see “Formatting Data” on page 1305.
The following image shows the application rendered in a web browser window:
For more information about using Cascading Style Sheets, see “Using Styles and Themes” on page 589.
Using skins
Skinning is the process of changing the appearance of a component by modifying or replacing its visual elements.
These elements can be made up of bitmap images, SWF files, or class files that contain drawing methods that
define vector images. Skins can define the entire appearance, or only a part of the appearance, of a component in
various states. For more information about using skins, see “Creating Skins” on page 689.
Using effects
An effect is a change to a component that occurs over a brief period of time. Examples of effects are fading,
resizing, and moving a component. An effect is combined with a trigger, such as a mouse click on a component, a
component getting focus, or a component becoming visible, to form a behavior. In MXML, you apply effects as
properties of a control or container. Flex provides a set of built-in effects with default properties.
The following example shows an application that contains a Button control with its rollOverEffect property set
to use the WipeLeft effect when the user moves the mouse over it:
<?xml version="1.0"?>
<!-- mxml/WipeLeftEffect.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- Define the effect. -->
<mx:WipeLeft id="myWL" duration="1000"/>
For more information about MXML components, see “Simple MXML Components” on page 63 in Creating and
Extending Adobe Flex 3 Components.
You can also define custom Flex components in ActionScript. For more information, see “Simple Visual Compo-
nents in ActionScript” on page 105 in Creating and Extending Adobe Flex 3 Components.
22 CHAPTER 1
23
Topics
Basic MXML syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Setting component properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
• ActionScript properties
• XML data
Adobe recommends that you assign scalar values using tag attributes, and that you assign complex types, such as
ActionScript objects, by using child tags.
You can also define a default property when you create a custom component. For more information, see “Metadata
Tags in Custom Components” on page 33 in Creating and Extending Adobe Flex 3 Components.
<mx:Label text="\{\}"/>
</mx:Application>
In this example, you want to use literal curly brace characters ({ }) in a text string. But Flex uses curly braces to
indicate a data binding operation. Therefore, you prefix each curly brace with the backslash character to cause the
MXML compiler to interpret them as literal characters.
<![CDATA[
[Bindable]
public var myText:String = "Display" + "\n" + "Content";
]]>
</mx:Script>
Component developers may have specified additional information within the component definition that defines
the data type of the Array elements. For example, if the developer specified that the dataProvider property
supports only String elements, this example would cause a compiler error because you specified numbers to it.
The Adobe Flex Language Reference documents the Array properties that define a required data type for the Array
elements.
<mynamespace:shippingAddress>
<mynamespace:DomesticAddress name="Fred" street="123 Elm St."/>
</mynamespace:shippingAddress>
</mynamespace:PurchaseOrder>
If the property is explicitly typed as Object like the value property in the following example, you can specify an
anonymous object using the <mx:Object> tag.
class ObjectHolder {
public var value:Object
}
The following example shows how you specify an anonymous object as the value of the value property:
<mynamespace:ObjectHolder>
<mynamespace:value>
<mx:Object foo='bar'/>
</mynamespace:value>
</mynamespace:ObjectHolder>
If you want to create a single-element array, include the <mx:Array> and </mx:Array> tags around the array
element, as the following example shows:
<mynamespace:MyComponent>
<mynamespace:nameOfObjectProperty>
<mx:Array>
<mx:Number>94062</mx:Number>
</mx:Array>
</mynamespace:nameOfObjectProperty>
</mynamespace:MyComponent>
For example, you can set the creationComplete event property in MXML, as the following code shows:
<mx:TextArea id="myText" creationComplete="creationCompleteHandler()"/>
This MXML code is equivalent to the following ActionScript code:
myText.addEventListener("creationComplete", creationCompleteHandler);
• The <mx:RemoteObject> tag requires a source value or a named value, and does not allow both.
• The <mx:HTTPService> tag requires a url value or a destination value, and does not allow both.
• The <mx:operation> tag requires a name value, and does not allow duplicate name entries.
• The <mx:operation> tag cannot contain an id property.
• The <mx:method> tag requires a name value and does not allow duplicate name entries.
• The <mx:method> tag cannot contain an id property.
36 CHAPTER 2
37
Topics
Using ActionScript in Flex applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Working with Flex components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Comparing, including, and importing ActionScript code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Techniques for separating ActionScript from MXML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Creating ActionScript components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Performing object introspection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
ActionScript compilation
Although a simple Flex application can be written in a single MXML or ActionScript (AS) file, most applications
will be broken into multiple files. For example, it is common to move the <mx:Script> and <mx:Style> blocks
for an <mx:Application> into separate AS and CSS files which the application then includes. It is also common
for an application to import custom MXML and ActionScript components. These must be defined in other files,
and MXML components may put their own <mx:Script> blocks into yet more AS files that they include. Compo-
nents may also be imported from precompiled SWC files rather than source code. Finally, SWF files containing
executable code can also be embedded in an application. The end result of all these input files is a single SWF file.
The Flex compiler transforms the main MXML file and other files it includes into a single ActionScript class. As
a result, you cannot define classes or use statements outside of functions in the MXML files and the included
ActionScript files.
You can reference imported ActionScript classes from your MXML application files, and those classes are added
to the final SWF file. When the transformation to an ActionScript file is complete, Flex links all the ActionScript
components and includes those classes in the final SWF file.
Setting an id property on a component instance within a class results in a public variable being autogenerated in
the subclass that contains a reference to that component instance. For example, if the <mx:Button
id="myButton"/> tag is nested deeply inside several containers, you can still refer to it as myButton.
Event attributes become the bodies of autogenerated event listener methods in the subclass. For example:
<mx:Button id="myButton" click="foo = 1; doSomething()">
becomes
private function __myButton_click(event:MouseEvent):void {
foo = 1;
doSomething()
}
The event attributes become method bodies, so they can access the other properties and methods of the subclass.
All the ActionScript anywhere in an MXML file, whether in its <mx:Script> block or inside tags, executes with
the this keyword referring to an instance of the subclass.
The public properties and methods of the class are accessible by ActionScript code in other components, as long
as that code “dots down” (for example, myCheckoutAccordion.myAddressForm.firstNameTextInput.text)
or reaches up using parentDocument, parentApplication , or Application.application to specify which
component the property or method exists on.
When the user clicks the button, this code sets the value of the TextArea control’s text property to the String
“Hello World.” In most cases, you do not need to look at the generated code, but it is useful to understand what
happens when you write an inline event handler.
To see the generated code, set the value of the keep-generated-actionscript compiler option to true. The
compiler then stores the *.as helper file in the /generated directory, which is a subdirectory of the location of the
SWF file.
For more information about events, see “Using Events” on page 61. For more information on using the command-
line compilers, see “Using the Flex Compilers” on page 125 in Building and Deploying Adobe Flex 3 Applications.
<mx:Label id="label1"/>
</mx:Application>
Most statements must be inside functions in an <mx:Script> block. However, the following statements can be
outside functions:
• import
• var
ADOBE FLEX 3 41
Adobe Flex 3 Developer Guide
• include
• const
• namespace
• use namespace
When using an <mx:Script> block, you should wrap the contents in a CDATA construct. This prevents the
compiler from interpreting the contents of the script block as XML, and allows the ActionScript to be properly
generated. Adobe recommends that you write all your <mx:Script> open and close tags as the following example
shows:
<mx:Script>
<![CDATA[
...
]]>
</mx:Script>
Flex does not parse text in a CDATA construct, which means that you can use XML-parsed characters such as
angle brackets (< and >) and ampersand (&). For example, the following script that includes a less-than (<)
comparison must be in a CDATA construct:
<?xml version="1.0"?>
<!-- usingas/UsingCDATA.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="doSomething()">
<mx:Script><![CDATA[
public var m:Number;
public var n:Number;
public function doSomething():void {
n = 42;
m = 40;
label1.text = "42 > 40 = " + String(n > m);
}
]]></mx:Script>
<mx:Label id="label1"/>
</mx:Application>
You can also get a reference to a component when you have a String that matches the name. To access an object
on the application, you use the this keyword, followed by square brackets, with the String inside the square
brackets. The result is a reference to the objects whose name matches the String.
The following example changes style properties on each Button control using a compound String to get a reference
to the object:
<?xml version="1.0"?>
<!-- usingas/FlexComponents.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
private var newFontStyle:String;
private var newFontSize:int;
if (this[s].getStyle("fontStyle")=="normal") {
newFontStyle = "italic";
newFontSize = 18;
} else {
newFontStyle = "normal";
newFontSize = 10;
}
this[s].setStyle("fontStyle",newFontStyle);
this[s].setStyle("fontSize",newFontSize);
}
]]></mx:Script>
<mx:Button id="myButton1"
click="changeLabel('2')"
label="Change Other Button's Styles"
/>
<mx:Button id="myButton2"
click="changeLabel('1')"
label="Change Other Button's Styles"
/>
</mx:Application>
This technique is especially useful if you use a Repeater control or when you create objects in ActionScript and do
not necessarily know the names of the objects you want to refer to prior to run time. However, when you instan-
tiate an object in ActionScript, to add that object to the properties array, you must declare the variable as public
and declare it in the class’s scope, not inside a function.
The following example uses ActionScript to declare two Label controls in the application scope. During initial-
ization, the labels are instantiated and their text properties are set. The example then gets a reference to the Label
controls by appending the passed-in variable to the String when the user clicks the Button controls.
<?xml version="1.0"?>
<!-- usingas/ASLabels.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initLabels()">
<mx:Script><![CDATA[
44 CHAPTER 3
import mx.controls.Label;
addChild(label1);
addChild(label2);
}
/>
<mx:Button id="myButton"
label="Change Thumb Position"
click="adjustThumb(slider1);"
/>
</mx:Application>
To invoke a method from a child document (such as a custom MXML component), you can use the
parentApplication, parentDocument, or Application.application properties. For more information, see
“Application Container” on page 451.
Note: Because Flex invokes the initialize event before drawing the component, you cannot access size and position
information of that component from within the initialize event handler unless you use the creationComplete event
handler. For more information on the order of initialization events, see “About startup order” on page 92 in Building
and Deploying Adobe Flex 3 Applications.
xLoc = xLoc + 5;
yLoc = yLoc + 1;
circleColor = circleColor + 20;
}
]]></mx:Script>
</mx:Application>
About scope
Scoping in ActionScript is largely a description of what the this keyword refers to at a particular point. In your
application’s core MXML file, you can access the Application object by using the this keyword. In a file defining
an MXML component, this is a reference to the current instance of that component.
In an ActionScript class file, the this keyword refers to the instance of that class. In the following example, the
this keyword refers to an instance of myClass. Because this is implicit, you do not have to include it, but it is
shown here to illustrate its meaning.
class myClass {
var _x:Number = 3;
function get x():Number {
return this._x;
}
function set x(y:Number):void {
if (y > 0) {
this._x = y;
} else {
this._x = 0;
}
}
}
However, in custom ActionScript and MXML components or external ActionScript class files, Flex executes in the
context of those objects and classes, and the this keyword refers to the current scope and not the Application
object scope.
Flex includes an Application.application property that you can use to access the root application. You can
also use the parentDocument property to access the next level up in the document chain of a Flex application, or
the parentApplication property to access the next level up in the application chain when one Application object
uses a SWFLoader component to load another Application object.
48 CHAPTER 3
If you write ActionScript in a component’s event listener, the scope is not the component but rather the appli-
cation. For example, the following code changes the label of the Button control to “Clicked” once the Button
control is pressed:
<?xml version="1.0"?>
<!-- usingas/ButtonScope.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Panel width="250" height="100" layout="absolute" x="65" y="24">
<mx:Button id="myButton"
label="Click Me"
click="myButton.label='Clicked'"
x="79.5"
y="20"
/>
</mx:Panel>
<mx:Button label="Reset"
x="158"
y="149"
click="myButton.label='Click Me'"
/>
</mx:Application>
Contrast the previous example with the following code:
<?xml version="1.0"?>
<!-- usingas/AppScope.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- The following does nothing because the app level scope does
not have a label to set -->
<mx:Button id="myButton" label="Click Me" click="label='Clicked'"/>
</mx:Application>
This code does not work because when an event listener executes, the this keyword does not refer to the Button
instance; the this keyword refers to the Application or other top-level component instance. The second example
attempts to set the label property of the Application object, not the label property of the Button.
Variables declared within a function are locally scoped to that function. These variables can share the same name
as variables in outer scopes, and they do not affect the outer-scoped variable. If a variable is just used temporarily
by a single method, make it a local variable of that method rather than an instance variable. Use instance variables
only for storing the state of an instance, because each instance variable will take up memory for the entire lifetime
of the instance. You can refer to the outer-scoped variable with the this. prefix.
ADOBE FLEX 3 49
Adobe Flex 3 Developer Guide
<mx:Script><![CDATA[
]]></mx:Script>
<mx:Button id="myButton"
label="Call Methods in Included File"
click="ta1.text=doSomething();ta1.text+=doSomethingElse()"
/>
<mx:TextArea width="268" id="ta1"/>
<mx:Button label="Clear" click="ta1.text=''"/>
</mx:Application>
You can specify only a single file for each include directive, but you can use any number of include directives.
You can nest include directives; files with include directives can include files that have include directives.
The include directive supports only relative paths. For more information, see “Referring to external files that
have been included” on page 51.
You can use the include only where multiple statements are allowed. For example, the following is not allowed:
if (expr)
include "foo.as"; // First statement is guarded by IF, but rest are not.
...
The following is allowed:
if (expr) {
include "foo.as"; // All statements inside { } are guarded by IF.
}
The use of curly braces ({ }) allows multiple statements because you can add multiple statements inside the braces.
Adobe recommends that you not use the include directive if you use a large number of included ActionScript
files. You should try to break the code into separate class files where appropriate and store them in logical package
structures.
For an ActionScript include directive, you can reference only relative URLs. Flex searches the source path for
imported classes and packages. Flex does not search the source path for files that are included using the include
directive or the source attribute of the <mx:Script> tag.
<mx:Script><![CDATA[
import MyPackage.Util.MyClass;
]]></mx:Script>
</mx:Application>
In your ActionScript code, instead of referring to the class with its fully qualified package name
(MyPackage.Util.MyClass), you refer to it as MyClass.
You can also use the wildcard character (*) to import the entire package. For example, the following statement
imports the entire MyPackage.Util package:
import MyPackage.Util.*;
Flex searches the source path for imported files and packages, and includes only those that are used in the final
SWF file.
It is not sufficient to simply specify the fully qualified class name. You should use fully qualified class names only
when necessary to distinguish two classes with the same class name that reside in different packages.
If you import a class but do not use it in your application, the class is not included in the resulting SWF file’s
bytecode. As a result, importing an entire package with a wildcard does not create an unnecessarily large SWF file.
ADOBE FLEX 3 53
Adobe Flex 3 Developer Guide
}
]]></mx:Script>
One MXML document and one ActionScript file (event handling logic in separate
script file)
Here, the function call is in an MXML event attribute, and the function is defined in a separate ActionScript file,
as the following code shows:
<?xml version="1.0"?>
<!-- usingas/ASSourceFile.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- Specify the ActionScript file that contains the function. -->
<mx:Script source="includes/Sample3Script.as"/>
The describeType() method returns only public members. The method does not return private members of the
caller’s superclass or any other class where the caller is not an instance. If you call describeType(this), the
method returns information only about nonstatic members of the class. If you call
describeType(getDefinitionByName("MyClass")) , the method returns information only about the target’s
static members.
The following example introspects the Button control and prints the details to TextArea controls:
<?xml version="1.0"?>
<!-- usingas/IntrospectionAPI.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="getDetails()">
<mx:Script><![CDATA[
import flash.utils.*;
The output displays accessors, variables, and methods of the Button control, and appears similar to the following:
Class mx.controls::Button
...
Variable id=button1 (String)
Variable __width=66 (Number)
Variable layoutWidth=66 (Number)
Variable __height=22 (Number)
Variable layoutHeight=22 (Number)
...
Property label=Submit (String)
Property enabled=true (Boolean)
Property numChildren=2 (uint)
Property enabled=true (Boolean)
Property visible=true (Boolean)
Property toolTip=null (String)
...
Method dispatchEvent():Boolean
Method hasEventListener():Boolean
Method layoutContents():void
Method getInheritingStyle():Object
Method getNonInheritingStyle():Object
Another useful method is the ObjectUtil’s getClassInfo() method. This method returns an Object with the
name and properties of the target object. The following example uses the getClassInfo() and toString()
methods to show the properties of the Button control:
<?xml version="1.0"?>
<!-- usingas/IntrospectionObjectUtil.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.controls.Alert;
import mx.utils.ObjectUtil;
private function showProps(b:Button):void {
var o:Object = ObjectUtil.getClassInfo(b);
ta1.text = ObjectUtil.toString(o);
}
]]></mx:Script>
<mx:Button id="b1" label="Show Properties" click="showProps(b1)"/>
<mx:TextArea id="ta1" width="300" height="500"/>
</mx:Application>
For more information about using E4X, see Programming ActionScript 3.0.
60 CHAPTER 3
61
Topics
About events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Using events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Manually dispatching events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Event propagation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Event priorities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Using event subclasses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
About keyboard events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
About events
Events let a developer know when something happens within a Flex application. They can be generated by user
devices, such as the mouse and keyboard, or other external input, such as the return of a web service call. Events
are also triggered when changes happen in the appearance or life cycle of a component, such as the creation or
destruction of a component or when the component is resized.
Any user interaction with your application can generate events. Events can also occur without any direct user
interaction, such as when data finishes loading from a server or when an attached camera becomes active. You can
“handle” these events in your code by adding an event handler. Event handlers are the functions or methods that
you write to respond to specific events. They are also sometimes referred to as event listeners.
The Flex event model is based on the Document Object Model (DOM) Level 3 events model. Although Flex does
not adhere specifically to the DOM standard, the implementations are very similar. The event model in Flex
comprises the Event object and its subclasses, and the event dispatching model. For a quick start in using events
in Flex, see the sample code in “Using events” on page 65.
Components generate and dispatch events and consume (listen to) other events. An object that requires infor-
mation about another object’s events registers a listener with that object. When an event occurs, the object
dispatches the event to all registered listeners by calling a function that was requested during registration. To
receive multiple events from the same object, you must register your listener for each event.
62 CHAPTER 4
Components have built-in events that you can handle in ActionScript blocks in your MXML applications. You can
also take advantage of the Flex event system’s dispatcher-listener model to define your own event listeners outside
of your applications, and define which methods of your custom listeners will listen to certain events. You can
register listeners with the target object so that when the target object dispatches an event, the listeners get called.
All visual objects, including Flex controls and containers, are subclasses of the DisplayObject class. They are in a
tree of visible objects that make up your application. The root of the tree is the Stage. Below that is the System-
Manager object, and then the Application object. Child containers and components are leaf nodes of the tree. That
tree is known as the display list. An object on the display list is analogous to a node in the DOM hierarchical
structure. The terms display list object and node are used interchangeably.
For information about each component’s events, see the component’s description in “Controls” on page 223 or the
control’s entry in ActionScript 3.0 Language Reference.
For a detailed description of a component’s startup life cycle, including major events in that life cycle, see
“Advanced Visual Components in ActionScript” on page 129 in Creating and Extending Adobe Flex 3 Components.
For information on using Event subclasses, see “Using event subclasses” on page 95.
Using events
Using events in Flex is a two-step process. First, you write a function or class method, known as an event listener
or event handler, that responds to events. The function often accesses the properties of the Event object or some
other settings of the application state. The signature of this function usually includes an argument that specifies
the event type being passed in.
The following example shows a simple event listener function that reports when a control triggers the event that
it is listening for:
<?xml version="1.0"?>
<!-- events/SimpleEventHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp();">
<mx:Script><![CDATA[
import mx.controls.Alert;
</mx:Application>
As you can see in this example, you also register that function or class method with a display list object by using
the addEventListener() method.
Most Flex controls simplify listener registration by letting you specify the listener inside the MXML tag. For
example, instead of using the addEventListener() method to specify a listener function for the Button control’s
click event, you specify it in the click attribute of the <mx:Button> tag:
<?xml version="1.0"?>
<!-- events/SimplerEventHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.controls.Alert;
</mx:Application>
66 CHAPTER 4
This is equivalent to the addEventListener() method in the previous code example. However, it is best practice
to use the addEventListener() method. This method gives you greater control over the event by letting you
configure the priority and capturing settings, and use event constants. In addition, if you use
addEventListener() to add an event handler, you can use removeEventListener() to remove the handler
when you no longer need it. If you add an event handler inline, you cannot call removeEventListener() on that
handler.
Each time a control generates an event, Flex creates an Event object that contains information about that event,
including the type of event and a reference to the dispatching control. To use the Event object, you specify it as a
parameter in the event handler function, as the following example shows:
<?xml version="1.0"?>
<!-- events/EventTypeHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.controls.Alert;
</mx:Application>
If you want to access the Event object in an event handler that was triggered by an inline event, you must add the
event keyword inside the MXML tag so that Flex explicitly passes it to the handler, as in the following:
<mx:Button id="b1" label="Click Me" click="myEventHandler(event)"/>
You are not required to use the Event object in a handler function. The following example creates two event
handler functions and registers them with the events of a ComboBox control. The first event handler, openEvt(),
takes no arguments. The second event handler, changeEvt(), takes the Event object as an argument and uses this
object to access the value and selectedIndex of the ComboBox control that triggered the event.
<?xml version="1.0"?>
<!-- events/MultipleEventHandlers.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
private function openEvt():void {
forChange.text="";
}
<mx:dataProvider>
<mx:Array>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
<mx:String>AR</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:ComboBox>
</mx:Application>
This example shows accessing the target property of the Event object. For more information, see “Accessing the
currentTarget property” on page 67.
}
]]></mx:Script>
</mx:Application>
You can access members of the currentTarget. If you do not cast the current target to a specific type, the
compiler assumes that it is of type Object. Objects can have any property or method because the Object type is
dynamic in ActionScript. Therefore, when accessing methods and properties of the currentTarget , it is best
practice to cast currentTarget to whatever class you anticipate will dispatch that event. This gives you strong
type checking at compile time, and helps avoid the risk of throwing a run-time error.
The following example casts the current target to a TextInput class before calling the setSelection() method,
but does not cast it before trying to set the tmesis property. The tmesis property does not exist on the TextInput
class. This illustrates that you will get a run-time error but not a compile-time error when you try to access
members that don’t exist, unless you cast currentTarget to a specific type so that type checking can occur:
<?xml version="1.0"?>
<!-- events/InvokingOnCurrentTarget.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.core.UIComponent;
/*
... unless you cast it to the expected type like the following. Then
the compiler throws an error.
TextInput(e.currentTarget).tmesis = 4;
*/
}
]]></mx:Script>
</mx:Application>
In this example, whenever the user clicks the Button control, Flex calls the myClickHandler() function.
For more information on defining event handlers inline, see “Defining event listeners inline” on page 70.
2 Use the addEventListener() method, as follows:
<?xml version="1.0"?>
<!-- events/SimpleEventHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
<mx:Script><![CDATA[
import mx.controls.Alert;
</mx:Application>
As with the previous example, whenever the user clicks the Button control, Flex calls the myClickHandler()
handler function. However, registering your event handlers using this method provides more flexibility. You
can register multiple components with this event handler, add multiple handlers to a single component, or
remove the handler. For more information, see “Using the addEventListener() method” on page 71.
3 Create an event handler class and register components to use the class for event handling. This approach to
event handling promotes code reuse and lets you centralize event handling outside your MXML files. For more
information on creating custom event handler classes, see “Creating event handler classes” on page 76.
70 CHAPTER 4
</mx:Application>
It is best practice to include the event keyword when you define all inline event listeners and to specify the most
stringent Event object type in the resulting listener function (for example, specify MouseEvent instead of Event).
ADOBE FLEX 3 71
Adobe Flex 3 Developer Guide
You can use the Event object to access a reference to the target object (the object that dispatched the event), the
type of event (for example, click), or other relevant properties, such as the row number and value in a list-based
control. You can also use the Event object to access methods and properties of the target component, or the
component that dispatched the event.
Although you will most often pass the entire Event object to an event listener, you can just pass individual
properties, as the following example shows:
<?xml version="1.0"?>
<!-- events/PropertyHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.controls.Alert;
</mx:Application>
Registering an event listener inline provides less flexibility than using the addEventListener() method to
register event listeners. The drawbacks are that you cannot set the useCapture or priority properties on the
Event object and that you cannot remove the listener once you add it.
The constants provide an easy way to refer to specific event types. You should use these constants instead of the
strings that they represent. If you misspell a constant name in your code, the compiler catches the mistake. If you
instead use strings and make a typographical error, it can be harder to debug and could lead to unexpected
behavior.
You should use the constants wherever possible. For example, when you are testing to see whether an Event object
is of a certain type, use the following code:
if (myEventObject.type == MouseEvent.CLICK) {/* your code here */}
Do not use the following code:
if (myEventObject.type == "click") {/* your code here */}
The event_listener argument is the function that handles the event. This argument is required.
The use_capture parameter of the addEventListener() method lets you control the phase in the event flow in
which your listener will be active. It sets the value of the useCapture property of the Event object. If useCapture
is set to true, your listener is active during the capturing phase of the event flow. If useCapture is set to false,
your listener is active during the targeting and bubbling phases of the event flow, but not during the capturing
phase. The default value is determined by the type of event, but is false in most cases.
To listen for an event during all phases of the event flow, you must call addEventListener() twice, once with the
useCapture parameter set to true, and again with use_capture set to false. This argument is optional. For
more information, see “Capturing phase” on page 88.
The priority parameter sets the priority for that event listener. The higher the number, the sooner that event
handler executes relative to other event listeners for the same event. Event listeners with the same priority are
executed in the order that they were added. This parameter sets the priority property of the Event object. The
default value is 0, but you can set it to negative or positive integer values. If several event listeners are added
without priorities, the earlier a listener is added, the sooner it is executed. For more information on setting prior-
ities, see “Event priorities” on page 94.
The weakRef parameter provides you with some control over memory resources for listeners. A strong reference
(when weakRef is false) prevents the listener from being garbage collected. A weak reference (when weakRef is
true) does not. The default value is false.
When you add a listener function and that function is invoked, Flex implicitly creates an Event object for you and
passes it to the listener function. You must declare the Event object in the signature of your listener function.
If you add an event listener by using the addEventListener() method, you are required to declare an event
object as a parameter of the listener_function, as the following example shows:
b1.addEventListener(MouseEvent.CLICK, performAction);
In the listener function, you declare the Event object as a parameter, as follows:
public function performAction(e:MouseEvent):void {
ADOBE FLEX 3 73
Adobe Flex 3 Developer Guide
...
}
The following example defines a new handler function myClickListener(). It then registers the click event of
the Button control with that handler. When the user clicks the button, Flex calls the myClickHandler() function.
<?xml version="1.0"?>
<!-- events/AddEventListenerExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="createListener()">
<mx:Script><![CDATA[
import mx.controls.Alert;
private function createListener():void {
b1.addEventListener(MouseEvent.CLICK, myClickHandler, false, 0);
}
private function myClickHandler(e:MouseEvent):void {
Alert.show("The button was clicked.");
}
]]></mx:Script>
<mx:Button label="Click Me" id="b1"/>
</mx:Application>
<mx:Button id='b1'
label="Click Me"
initialize='b1.addEventListener(MouseEvent.CLICK, myClickHandler, false, 1);'
/>
</mx:Application>
This is the equivalent of defining the event handler inline. However, defining a handler by using the
addEventListener() method rather than setting click="handler_function" lets you set the value of the
useCapture and priority properties of the Event object. Furthermore, you cannot remove a handler added
inline, but when you use the addEventListener() method to add a handler, you can call the
removeEventListener() method to remove that handler.
74 CHAPTER 4
]]></mx:Script>
<mx:Form width="107">
<mx:FormItem label="X">
<mx:TextInput id="ti1" text="10" width="37" textAlign="right"/>
</mx:FormItem>
<mx:FormItem label="Y" width="71">
<mx:TextInput id="ti2" text="20" width="38" textAlign="right"/>
</mx:FormItem>
<mx:Label id="label1" text="{answer}" width="71" textAlign="right"/>
</mx:Form>
The event_type and listener_function parameters are required. These are the same as the required param-
eters for the addEventListener() method.
The use_capture parameter is also identical to the parameter used in the addEventListener() method. Recall
that you can listen for events during all event phases by calling addEventListener() twice: once with
use_capture set to true, and again with it set to false. To remove both event listeners, you must call
removeEventListener() twice: once with use_capture set to true, and again with it set to false.
You can remove only event listeners that you added with the addEventListener() method in an ActionScript
block. You cannot remove an event listener that was defined in the MXML tag, even if it was registered using a
call to the addEventListener() method that was made inside a tag attribute.
The following sample application shows what type of handler can be removed and what type cannot:
<?xml version="1.0"?>
<!-- events/RemoveEventListenerExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="createHandler(event)">
<mx:Script><![CDATA[
import mx.controls.Alert;
private function createHandler(e:Event):void {
b1.addEventListener(MouseEvent.CLICK, myClickHandler);
}
private function removeMyHandlers(e:Event):void {
/* Remove listener for b1's click event because it was added
with the addEventListener() method. */
b1.removeEventListener(MouseEvent.CLICK, myClickHandler);
/* Does NOT remove the listener for b2's click event because it
was added inline in an MXML tag. */
b2.removeEventListener(MouseEvent.CLICK, myClickHandler);
}
private function myClickHandler(e:Event):void {
Alert.show("The button was clicked.");
}
]]></mx:Script>
To create a class that handles events, you usually import the flash.events.Event class. You also usually write an
empty constructor. The following ActionScript class file calls the Alert control’s show() method whenever it
handles an event with the handleAllEvents() method:
// events/MyEventHandler.as
import flash.events.Event;
import mx.controls.Alert;
public class MyEventHandler {
public function MyEventHandler() {
// Empty constructor.
}
</mx:Application>
The best approach is to define the event handler’s method as static. When you make the event handler method
static, you are not required to instantiate the class inside your MXML application. The following
createHandler() function registers the handleAllEvents() method as an event handler without instantiating
the
MyStaticEventHandler class:
<?xml version="1.0"?>
<!-- events/CustomHandlerStatic.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="createHandler()">
<mx:Script><![CDATA[
private function createHandler():void {
b1.addEventListener(MouseEvent.CLICK, MyStaticEventHandler.handleAllEvents);
}
78 CHAPTER 4
]]></mx:Script>
</mx:Application>
In the class file, you just add the static keyword to the method signature:
// events/MyStaticEventHandler.as
import flash.events.Event;
import mx.controls.Alert;
public class MyStaticEventHandler {
public function MyStaticEventHandler() {
// Empty constructor.
}
<mx:Button id="b1"
label="Do Both Actions"
click='submitForm(event); debugMessage(event);'
ADOBE FLEX 3 79
Adobe Flex 3 Developer Guide
/>
<mx:Label id="l1" text="{s}"/>
</mx:Application>
For events added with the addEventListener() method, you can add any number of handlers with additional
calls to the addEventListener() method. Each call adds a handler function that you want to register to the
specified object. The following example registers the submitForm() and debugMessage() handler functions
with b1’s click event:
<?xml version="1.0"?>
<!-- events/MultipleEventHandlersAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="createHandlers(event)">
<mx:Script><![CDATA[
[Bindable]
private var s:String = "";
]]></mx:Script>
</mx:Application>
You can mix the methods of adding event handlers to any component; alternatively, you can add handlers inline
and with the addEventListener() method. The following example adds a click event handler inline for the
Button control, which calls the performAction() method. It then conditionally adds a second click handler to
call the logAction() method, depending on the state of the CheckBox control.
<?xml version="1.0"?>
<!-- events/ConditionalHandlers.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="initApp(event)">
<mx:Script><![CDATA[
import mx.controls.Alert;
80 CHAPTER 4
</mx:Application>
You can set the order in which event listeners are called by using the priority parameter of the
addEventListener() method. You cannot set a priority for a listener function if you added the event listener
using MXML inline. For more information on setting priorities, see “Event priorities” on page 94.
]]></mx:Script>
ADOBE FLEX 3 81
Adobe Flex 3 Developer Guide
<mx:Button id="b1"
label="Click Me"
click="submitForm(event)"
/>
<mx:Button id="b2"
label="Click Me, Too"
click="submitForm(event)"
/>
</mx:Application>
When you use the addEventListener() method to register a single listener to handle the events of multiple
components, you must use a separate call to the addEventListener() method for each instance, as the following
example shows:
<?xml version="1.0"?>
<!-- events/OneHandlerTwoComponentsAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="createHandlers(event)">
<mx:Script><![CDATA[
import mx.controls.Alert;
</mx:Application>
When doing this, you should add logic to the event listener that processes the type of event. The event target (or
object that dispatched the event) is added to the Event object for you. No matter what triggered the event, you can
conditionalize the event processing based on the target or type properties of the Event object. Flex adds these
two properties to all Event objects.
The following example registers a single listener function (myEventHandler()) to the click event of a Button
control and the click event of a CheckBox control. To detect what type of object called the event listener, the
listener checks the className property of the target in the Event object in a case statement.
<?xml version="1.0"?>
<!-- events/ConditionalTargetHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.controls.Alert;
button1.addEventListener(MouseEvent.CLICK, myEventHandler);
cb1.addEventListener(MouseEvent.MOUSE_DOWN, myEventHandler);
}
</mx:Application>
</mx:Application>
</mx:Application>
You can also manually dispatch an event in an MXML tag. In the following example, moving the mouse pointer
over the button triggers the button’s click event:
<?xml version="1.0"?>
<!-- events/DispatchEventExampleInline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="createListener(event);">
<mx:Script><![CDATA[
import mx.controls.Alert;
<mx:Button id="b1"
label="Click Me"
mouseOver="b1.dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, false));"
/>
</mx:Application>
Your Flex application is not required to handle the newly dispatched event. If you trigger an event that has no
listeners, Flex ignores the event.
You can set properties of the Event object in ActionScript, but you cannot add new properties because the object
is not dynamic. The following example intercepts a click event. It then creates a new MouseEvent object and
dispatches it as a doubleClick event. In addition, it sets the value of the shiftKey property of the MouseEvent
object to true, to simulate a Shift-click on the keyboard.
<?xml version="1.0"?>
<!-- events/DispatchCustomizedEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="addListeners()">
<mx:Script><![CDATA[
private function customLogEvent(e:MouseEvent):void {
l1.text = String(e.currentTarget.id);
l2.text = String(e.type);
l3.text = String(e.shiftKey);
]]></mx:Script>
86 CHAPTER 4
</mx:Application>
If you want to add custom properties to an Event object, you must extend the Event object and define the new
properties in your own custom class. You can then manually dispatch your custom events with the
dispatchEvent() method, as you would any event.
If you create a custom ActionScript class that dispatches its own events but does not extend UIComponent, you
can extend the flash.events.EventDispatcher class to get access to the addEventListener(),
removeEventListener(), and dispatchEvent() methods.
For more information on creating custom classes, see Creating and Extending Adobe Flex 3 Components.
Event propagation
When events are triggered, there are three phases in which Flex checks whether there are event listeners. These
phases occur in the following order:
• Capturing
• Targeting
• Bubbling
During each of these phases, the nodes have a chance to react to the event. For example, assume the user clicks a
Button control that is inside a VBox container. During the capturing phase, Flex checks the Application object and
the VBox for listeners to handle the event. Flex then triggers the Button’s listeners in the target phase. In the
bubbling phase, the VBox and then the Application are again given a chance to handle the event but now in the
reverse order from the order in which they were checked in the capturing phase.
ADOBE FLEX 3 87
Adobe Flex 3 Developer Guide
In ActionScript 3.0, you can register event listeners on a target node and on any node along the event flow. Not all
events, however, participate in all three phases of the event flow. Some types of events are dispatched directly to
the target node and participate in neither the capturing nor the bubbling phases. All events can be captured unless
they are dispatched from the top node.
Other events may target objects that are not on the display list, such as events dispatched to an instance of the
Socket class. These event objects flow directly to the target node, without participating in the capturing or
bubbling phases. You can also cancel an event as it flows through the event model so that even though it was
supposed to continue to the other phases, you stopped it from doing so. You can do this only if the cancelable
property is set to true.
Capturing and bubbling happen as the Event object moves from node to node in the display list: parent-to-child
for capturing and child-to-parent for bubbling. This process has nothing to do with the inheritance hierarchy.
Only DisplayObject objects (visual objects such as containers and controls) can have a capturing phase and a
bubbling phase in addition to the targeting phase.
Mouse events and keyboard events are among those that bubble. Any event can be captured, but no DisplayObject
objects listen during the capturing phase unless you explicitly instruct them to do so. In other words, capturing is
disabled by default.
When a faceless event dispatcher, such as a Validator, dispatches an event, there is only a targeting phase, because
there is no visual display list for the Event object to capture or bubble through.
MouseEvent events bubble up the parent chain, and can be handled on any ancestor. As the event bubbles, the
value of the event.target property stays the same (UITextField), but the value of the event.currentTarget
property is set at each level to be the ancestor that is handling the event. Eventually, the currentTarget will be
Button, at which time the Button control’s event listener will handle the event. For this reason, you should use the
event.currentTarget property rather than the event.target property; for example:
<mx:Button label="OK" click="trace(event.currentTarget.label)"/>
In this case, in the Button event’s click event listener, the event.currentTarget property always refers to the
Button, while event.target might be either the Button or its UITextField, depending on where on the Button
control the user clicked.
Capturing phase
In the capturing phase, Flex examines an event’s ancestors in the display list to see which ones are registered as a
listener for the event. Flex starts with the root ancestor and continues down the display list to the direct ancestor
of the target. In most cases, the root ancestors are the Stage, then the SystemManager, and then the Application
object.
For example, if you have an application with a Panel container that contains a TitleWindow container, which in
turn contains a Button control, the structure appears as follows:
Application
Panel
TitleWindow
Button
If your listener is on the click event of the Button control, the following steps occur during the capturing phase
if capturing is enabled:
1 Check the Application container for click event listeners.
2 Check the Panel container for click event listeners.
3 Check the TitleWindow container for click event listeners.
During the capturing phase, Flex changes the value of the currentTarget property on the Event object to match
the current node whose listener is being called. The target property continues to refer to the dispatcher of the
event.
By default, no container listens during the capturing phase. The default value of the use_capture argument is
false. The only way to add a listener during this phase is to pass true for the use_capture argument when
calling the addEventListener() method, as the following example shows:
myPanel.addEventListener(MouseEvent.MOUSE_DOWN, clickHandler, true);
If you add an event listener inline with MXML, Flex sets this argument to false; you cannot override it.
ADOBE FLEX 3 89
Adobe Flex 3 Developer Guide
If you set the use_capture argument to true—in other words, if an event is propagated through the capturing
phase—the event can still bubble, but capture phase listeners will not react to it. If you want your event to traverse
both the capturing and bubbling phases, you must call addEventListener() twice: once with use_capture set
to true, and then again with use_capture set to false.
The capturing phase is very rarely used, and it can also be computationally intensive. By contrast, bubbling is
much more common.
Targeting phase
In the targeting phase, Flex invokes the event dispatcher’s listeners. No other nodes on the display list are
examined for event listeners. The values of the currentTarget and the target properties on the Event object
during the targeting phase are the same.
Bubbling phase
In the bubbling phase, Flex examines an event’s ancestors for event listeners. Flex starts with the dispatcher’s
immediate ancestor and continues up the display list to the root ancestor. This is the reverse of the capturing
phase.
For example, if you have an application with a Panel container that contains a TitleWindow container that
contains a Button control, the structure appears as follows:
Application
Panel
TitleWindow
Button
If your listener is on the click event of the Button control, the following steps occur during the bubble phase if
bubbling is enabled:
1 Check the TitleWindow container for click event listeners.
2 Check the Panel container for click event listeners.
3 Check the Application container for click event listeners.
An event only bubbles if its bubbles property is set to true. Mouse events and keyboard events are among those
that bubble; it is less common for higher-level events that are dispatched by Flex to bubble. Events that can be
bubbled include change, click, doubleClick , keyDown, keyUp, mouseDown, and mouseUp. To determine
whether an event bubbles, see the event’s entry in the Adobe Flex Language Reference.
During the bubbling phase, Flex changes the value of the currentTarget property on the Event object to match
the current node whose listener is being called. The target property continues to refer to the dispatcher of the
event.
90 CHAPTER 4
When Flex invokes an event listener, the Event object might have actually been dispatched by an object deeper in
the display list. The object that originally dispatched the event is the target. The object that the event is currently
bubbling through is the currentTarget . So, you should generally use the currentTarget property instead of
the target property when referring to the current object in your event listeners.
You can only register an event listener with an object if that object dispatches the event. For example, you cannot
register a Form container to listen for a click event, even though that container contains a Button control. Form
containers do not dispatch click events. Form containers do dispatch the mouseDown event, so you could put a
mouseDown event listener on the Form container tag. If you do that, your event listener is triggered whenever the
Button control or Form container receives a mouseDown event.
If you set the useCapture property to true—in other words, if an event is propagated through the capturing
phase—then it does not bubble, regardless of its default bubbling behavior. If you want your event to traverse both
the capturing and bubbling phases, you must call addEventListener() twice: once with useCapture set to
true, and then again with useCapture set to false.
An event only bubbles up the parent’s chain of ancestors in the display list. Siblings, such as two Button controls
inside the same container, do not intercept each other’s events.
<mx:Button id="b1"
label="Click Me"
click="showInfo(event)"
/>
</mx:Application>
ADOBE FLEX 3 91
Adobe Flex 3 Developer Guide
Stopping propagation
During any phase, you can stop the traversal of the display list by calling one of the following methods on the
Event object:
• stopPropagation()
• stopImmediatePropagation()
You can call either the event’s stopPropagation() method or the stopImmediatePropagation() method to
prevent an Event object from continuing on its way through the event flow. The two methods are nearly identical
and differ only in whether the current node’s remaining event listeners are allowed to execute. The
stopPropagation() method prevents the Event object from moving on to the next node, but only after any other
event listeners on the current node are allowed to execute.
The stopImmediatePropagation() method also prevents the Event objects from moving on to the next node,
but it does not allow any other event listeners on the current node to execute.
The following example creates a TitleWindow container inside a Panel container. Both containers are registered
to listen for a mouseDown event. As a result, if you click on the TitleWindow container, the showAlert() method
is called twice unless you add a call to the stopImmediatePropagation() method, as the following example
shows:
<?xml version="1.0"?>
<!-- events/StoppingPropagation.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init(event);">
<mx:Script><![CDATA[
import mx.controls.Alert;
import flash.events.MouseEvent;
import flash.events.Event;
p2.addEventListener(MouseEvent.MOUSE_DOWN,
showAlertWithoutStoppingPropagation);
tw2.addEventListener(MouseEvent.MOUSE_DOWN,
showAlertWithoutStoppingPropagation);
tw2.addEventListener(Event.CLOSE, closeWindow);
}
</mx:Application>
Examples
In the following example, the parent container’s click handler disables the target control after the target handles
the event. It shows that you can reuse the logic of a single listener (click the HBox container) for multiple events
(all the clicks).
<?xml version="1.0"?>
<!-- events/NestedHandlers.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
public function disableControl(event:MouseEvent):void {
// Use this same logic for all events.
event.currentTarget.enabled = false;
}
}
]]></mx:Script>
<mx:Button id="resetButton"
label="Reset"
click="hb1.enabled=true;b1.enabled=true;b2.enabled=true;b1.label='Click
Me';b2.label='Click Me';"
/>
</mx:Application>
By having a single listener on a parent control instead of many listeners (one on each child control), you can reduce
your code size and make your applications more efficient. Reducing the number of calls to the
addEventListener() method potentially reduces application startup time and memory usage.
The following example registers an event handler for the Panel container, rather than registering a listener for each
link. All children of the Panel container inherit this event handler. Since Flex invokes the handler on a bubbled
event, you use the target property rather than the currentTarget property. In this handler, the currentTarget
property would refer to the Panel control, whereas the target property refers to the LinkButton control, which
has the label that you want.
<?xml version="1.0"?>
<!-- events/SingleRegisterHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="createLinkHandler();">
<mx:Script><![CDATA[
private function linkHandler(event:MouseEvent):void {
var url:URLRequest = new URLRequest("http://finance.google.com/finance?q=" +
event.target.label);
navigateToURL(url);
}
private function createLinkHandler():void {
p1.addEventListener(MouseEvent.CLICK,linkHandler);
}
]]></mx:Script>
<mx:Panel id="p1" title="Click on a stock ticker symbol">
<mx:LinkButton label="ADBE"/>
<mx:LinkButton label="GE"/>
<mx:LinkButton label="IBM"/>
<mx:LinkButton label="INTC"/>
</mx:Panel>
</mx:Application>
94 CHAPTER 4
Event priorities
You can register any number of event listeners with a single event. Flex registers event listeners in the order in
which the addEventListener() methods are called. Flex then calls the listener functions when the event occurs
in the order in which they were registered. However, if you register some event listeners inline and some with the
addEventListener() method, the order in which the listeners are called for a single event can be unpredictable.
You can change the order in which Flex calls event listeners by using the priority parameter of the
addEventListener() method. It is the fourth argument of the addEventListener() method.
Flex calls event listeners in priority order, from highest to lowest. The highest priority event is called first. In the
following example, Flex calls the verifyInputData() method before the saveInputData() function. The
verifyInputData() method has the highest priority. The last method to be called is returnResult() because
the value of its priority parameter is lowest.
<?xml version="1.0"?>
<!-- events/ShowEventPriorities.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
private function returnResult(e:Event):void {
ta1.text += "returnResult() method called last (priority 1)\n";
}
The priority parameter of the addEventListener() method is not an official part of the DOM Level 3 events
model. ActionScript 3.0 provides it so that programmers can be more flexible when organizing their event
listeners.
Even if you give a listener a higher priority than other listeners, there is no way to guarantee that the listener will
finish executing before the next listener is called. You should ensure that listeners do not rely on other listeners
completing execution before calling the next listener. It is important to understand that Flash Player does not
necessarily wait until the first event listener finishes processing before proceeding with the next one.
If your listeners do rely on each other, you can call one listener function from within another, or dispatch a new
event from within the first event listener. For more information on manually dispatching events, see “Manually
dispatching events” on page 83.
<mx:TextInput id="myTextInput"/>
<mx:Text id="t1"/>
</mx:Application>
To run this example, you must first set the focus to something inside the application, such as the TextInput control,
by clicking on it.
Because any class that extends UIComponent dispatches the keyUp and keyDown events, you can also trap keys
pressed when the focus is on an individual component, as in the following example:
<?xml version="1.0"?>
<!-- events/TrapKeysOnTextArea.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp();">
<mx:Script><![CDATA[
private function initApp():void {
98 CHAPTER 4
myTextInput.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
}
<mx:TextInput id="myTextInput"/>
<mx:Text id="t1"/>
</mx:Application>
</mx:Application>
You can listen for specific keys or combinations of keys by using a conditional operator in the KeyboardEvent
handler. The following example listens for the combination of the Shift key plus the q key and prompts the user
to close the browser window if they press those keys at the same time:
<?xml version="1.0"?>
<!-- events/TrapQKey.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp();">
<mx:Script><![CDATA[
private function initApp():void {
application.addEventListener(KeyboardEvent.KEY_UP,keyHandler);
}
}
}
]]></mx:Script>
<mx:TextArea id="ta1" text="Focus here so that Shift+Q will quit the browser."/>
</mx:Application>
Notice that this application must have focus when you run it in a browser so that the application can capture
keyboard events.
<mx:VBox id="my_vbox">
<mx:TextInput id="my_textinput"/>
</mx:VBox>
</mx:Application>
When you examine the output, you will notice that the target property of the KeyboardEvent object stays the
same because it refers to the original dispatcher of the event (in this case, my_textinput). But the currentTarget
property changes depending on what the current node is during the bubbling (in this case, it changes from
my_textinput to my_vbox to the application itself).
ADOBE FLEX 3 101
Adobe Flex 3 Developer Guide
The order of calls to the event listener is determined by the object hierarchy and not the order in which the
addEventListener() methods were called. Child controls dispatch events before their parents. In this example,
for each key pressed, the TextInput control dispatches the event first, the VBox container next, and finally the
application.
When handling a key or key combination that the underlying operating system or browser recognizes, the
operating system or browser generally processes the event first. For example, in Microsoft Internet Explorer,
pressing Control+w closes the browser window. If you trap that combination in your Flex application, Internet
Explorer users never know it, because the browser closes before the ActiveX Flash Player has a chance to react to
the event.
Property Description
altKey Is set to true if the Alt key was held down when the user pressed the mouse button; otherwise, false.
ctrlKey Is set to true if the Control key was held down when the user pressed mouse button; otherwise, false.
shiftKey Is set to true if the Shift key was held down when the user pressed mouse button; otherwise, false.
The following example deletes Button controls, based on whether the user holds down the Shift key while pressing
the mouse button:
<?xml version="1.0"?>
<!-- events/DetectingShiftClicks.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp();">
<mx:Script><![CDATA[
import mx.controls.Button;
b1.addEventListener(MouseEvent.CLICK, removeButtons);
b2.addEventListener(MouseEvent.CLICK, removeButtons);
vb1.addChild(b1);
vb1.addChild(b2);
}
if (event.shiftKey) {
vb1.removeChild(Button(event.currentTarget));
} else {
event.currentTarget.toolTip = "Shift+click to remove this button.";
}
}
]]></mx:Script>
<mx:VBox id="vb1"/>
</mx:Application>
103
Topics
About data access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Comparing Flex data access to other technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
REST-style services
For REST-style services, you use a server resource such as a PHP page, JavaServer Page (JSP) or servlet, or
ColdFusion page that receives a POST or GET request from a Flex application using the HTTPService
component. That server resource then accesses a database using whatever means are traditional to the particular
server technology. The results of data access can be formatted as XML instead of HTML, as might be typical with
the server technology, and returned as the response to the Flex application. Flex, Adobe® Flash® Player, and Adobe
AIR™ have excellent XML- handling capabilities that let you manipulate the data for display in the Flex application
user interface. REST-style services provide an easy way to access a server resource without a more formalized API
such as those provided by web services or remote object services. These services can be implemented using any
number of server technologies that can get an HTTP request and return XML as the response.
Web services
SOAP-compliant web services are a standardized type of REST-style service. Rather than accessing a PHP, JSP, or
ColdFusion page specifically, a Flex application accesses a web service endpoint. Based on published specifica-
tions, a web service knows the format in which the data was sent and how to format a response. Many server
technologies provide the ability to interact with applications as web services. Because web services comply with a
standard, you don’t need to know the implementation details of the code with which a Flex application interacts.
This is particularly useful for applications, such as business-to-business applications, that require a high degree of
abstraction. However, SOAP is often very verbose and heavy across the wire, which can result in higher client-side
memory requirements and processing time than working with informal REST-style services.
HTTPService components
HTTPService components let you interact with HTTP services, which can be any HTTP URI that accepts HTTP
requests and sends responses. Although you can use the HTTPService component to consume different types of
responses, it is typically used to consume XML. You can use an HTTPService component with any kind of server-
side technology, including PHP pages, ColdFusion Pages, JavaServer Pages, Java servlets, Ruby on Rails, and
Microsoft ASP pages.
HTTPService components are a good option for working server-side technologies that are accessible over HTTP
and are not available as a web service or remoting service.
HTTPService components let you send HTTP GET, POST, HEAD, OPTIONS, PUT, TRACE, and DELETE
requests and include data from HTTP responses in a Flex application. Flex does not support mulitpart form
POSTs.
You can use an HTTPService component for CGI-like interaction in which you use HTTP GET, POST, HEAD,
OPTIONS, PUT, TRACE, or DELETE to send a request to a specified URI. When you call the HTTPService
object’s send() method, it makes an HTTP request to the URI specified in the url property, and an HTTP
response is returned. Optionally, you can pass request arguments to the specified URI.
The following example shows an HTTPService component that calls a PHP page. This HTTPService component
provides two request arguments, username and emailaddress. Additional code in the application calls the PHP
page to perform database queries and inserts, and to provide the data returned from the PHP page to the user
interface of the Flex application.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application>
...
<mx:HTTPService id="userRequest" url="http://server/myproj/request_post2.php"
useProxy="false" method="POST">
<mx:request xmlns="">
<username>{username.text}</username>
<emailaddress>{emailaddress.text}</emailaddress>
</mx:request>
106 CHAPTER 5
</mx:HTTPService>
</mx:Application>
For more information on creating HTTP services and accessing them with HTTPService components, see “Using
HTTPService components” on page 1163.
WebService components
WebService components let you access web services, which are software modules with methods, commonly
referred to as operations. Web service interfaces are defined by using XML. Web services provide a standards-
compliant way for software modules that are running on a variety of platforms to interact with each other. For
more information about web services, see the web services section of the World Wide Web Consortium site at
www.w3.org/2002/ws/.
Flex applications can interact with web services that define their interfaces in a Web Services Description
Language (WSDL) document, which is available as a URL. WSDL is a standard format for describing the messages
that a web service understands, the format of its responses to those messages, the protocols that the web service
supports, and where to send messages.
The Flex web service API generally supports SOAP 1.1, XML Schema 1.0 (versions 1999, 2000, and 2001), WSDL
1.1 rpc-encoded, rpc-literal, and document-literal (bare and wrapped style parameters). The two most common
types of web services use RPC-encoded or document-literal SOAP bindings; the terms encoded and literal indicate
the type of WSDL-to-SOAP mapping that a service uses.
Flex applications support web service requests and results that are formatted as SOAP messages and are trans-
ported over HTTP. SOAP provides the definition of the XML-based format that you can use for exchanging struc-
tured and typed information between a web service client, such as a Flex application, and a web service.
If web services are an established standard in your environment, you can use a WebService component to connect
to a SOAP-compliant web service.
The following example shows a WebService component that calls a web service. This WebService component calls
two web service operations, returnRecords() and insertRecord(). Additional code in the application calls the
web service to perform database queries and inserts and to provide the data returned from the web service to the
user interface of the Flex application.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application>
...
<mx:WebService
id="userRequest"
wsdl="http://server:8500/flexapp/returncfxml.cfc?wsdl">
<mx:operation name="returnRecords" resultFormat="object"
fault="mx.controls.Alert.show(event.fault.faultString)"
result="remotingCFCHandler(event)"/>
<mx:operation name="insertRecord"
result="insertCFCHandler()"
ADOBE FLEX 3 107
Adobe Flex 3 Developer Guide
fault="mx.controls.Alert.show(event.fault.faultString)"/>
</mx:WebService>
</mx:Application>
For more information about accessing web services with WebService components, see “Using WebService compo-
nents” on page 1172.
RemoteObject components
RemoteObject components let you access the methods of server-side objects, such as ColdFusion components
(CFCs), Java objects, PHP objects, and .NET objects, without configuring the objects as web services. You can use
RemoteObject components in MXML or ActionScript.
You can use RemoteObject components with LiveCycle Data Services ES, Vega, or ColdFusion. To access a remote
object, you specify its fully qualified classname or ColdFusion component name in the RemoteObject
component’s source property, or you use the destination property to specify a logical name that is mapped to
a fully qualified Java class name in a server-side configuration file, the remoting-config.xml file.
You can also use RemoteObject components with PHP and .NET objects in conjunction with third-party
software, such as the open source projects AMFPHP and SabreAMF, and Midnight Coders WebORB. Visit the
following websites for more information:
• AMFPHP http://amfphp.sourceforge.net/
• SabreAMF http://www.osflash.org/sabreamf
• Midnight Coders WebORB http://www.themidnightcoders.com/
When you use a RemoteObject tag, data is passed between your application and the server-side object in the
binary Action Message Format (AMF).
The following example shows a RemoteObject component that calls a web service. This WebService component
calls two web service operations, returnRecords() and insertRecord(). Additional code in the application
calls the web service to perform database queries and inserts and to provide the data returned from the web
service to the user interface of the Flex application.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application>
...
<mx:RemoteObject
id="userRequest"
destination="ColdFusion"
source="flexapp.returncfxml">
<mx:method name="returnRecords" result="returnHandler(event)"
fault="mx.controls.Alert.show(event.fault.faultString)"/>
<mx:method name="insertRecord" result="insertHandler()"
fault="mx.controls.Alert.show(event.fault.faultString)"/>
</mx:RemoteObject>
</mx:Application>
108 CHAPTER 5
For more information about creating remoting services and accessing them with RemoteObject components, see
“Using RemoteObject components” on page 1190.
<mx:TextInput id="input"/>
</mx:Application>
The following example shows JSP code for calling a web service using a JSP custom tag. When a user requests this
JSP, the web service request is made on the server instead of on the client, and the result is used to generate content
in the HTML page. The application server regenerates the entire HTML page before sending it back to the user’s
web browser.
<%@ taglib prefix="web" uri="webservicetag" %>
operation="GetRate"
resulttype="double"
result="myresult">
<web:param name="fromCurr" value="<%=str1%>"/>
<web:param name="ToCurr" value="<%=str2%>"/>
</web:invoke>
<!-- Display the web service result. -->
<%= pageContext.getAttribute("myresult") %>
Topics
About visual components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Class hierarchy for visual components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Using the UIComponent class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Sizing visual components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Handling events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Applying styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Applying behaviors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Applying skins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Changing the appearance of a component at run time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Extending components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Object
EventDispatcher
DisplayObject
InteractiveObject
DisplayObjectContainer
Sprite
UIComponent
All components
ADOBE FLEX 3 115
Adobe Flex 3 Developer Guide
All visual components are derived from the UIComponent class and its superclasses, the Flash Sprite through
Object classes, and inherit the properties and methods of their superclasses. In addition, visual components
inherit other characteristics of the superclasses, including event, style, and behavior definitions.
doubleClickEnabled Boolean Setting to true lets the component dispatch a doubleClickEvent when a user presses and
releases the mouse button twice in rapid succession over the component.
enabled Boolean Setting to true lets the component accept keyboard focus and mouse input. The default value is
true.
If you set enabled to false for a container, Flex dims the color of the container and all of its chil-
dren, and blocks user input to the container and to all its children.
In MXML tags, but not in ActionScript, you can set this property as a percentage of available space
by specifying a value such as 70%; in ActionScript, you must use the percentHeight property.
The property always returns a number of pixels. In ActionScript, you use the perCent
id String Specifies the component identifier. This value identifies the specific instance of the object and
should not contain any white space or special characters. Each component in a Flex document
must have a unique id value. For example, if you have two custom components, each component
can include one, and only one Button control with the id "okButton".
percentHeight Number The height of the component as a percentage of its parent container, or for <mx:Application>
tags, the full height of the browser. Returns NaN if a percent-based width has never been set or if
a width property was set after the percentWidth was set.
percentWidth Number The width of the component as a percentage of its parent container, or for <mx:Application>
tags, the full span of the browser. Returns NaN if a percent-based width has never been set or if a
width property was set after the percentWidth was set.
116 CHAPTER 6
styleName String Specifies the style class selector to apply to the component.
toolTip String Specifies the text string displayed when the mouse pointer hovers over that component.
visible Boolean Specifies whether the container is visible or invisible. The default value is true, which specifies
that the container is visible.
In MXML tags, but not in ActionScript, you can set this property as a percentage of available space
by specifying a value such as 70%; in ActionScript, you must use the percentWidth property.
x Number The component’s x position within its parent container. Setting this property directly has an
effect only if the parent container uses absolute positioning.
y Number The component’s y position within its parent container. Setting this property directly has an effect
only if the parent container uses absolute positioning.
Configure a component
1 Set the value of a component property, event, style, or behavior declaratively in an MXML tag, or at run time
in ActionScript code.
2 Call a component’s methods at run time in ActionScript code. The methods of an ActionScript class are not
exposed in the MXML API.
The following example creates a Button control in MXML. When the user clicks the Button control, it updates the
text of a TextArea control by using an ActionScript function.
<?xml version="1.0"?>
<!-- components\ButtonApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function handleClick():void {
text1.text="Thanks for the click!";
}
]]>
</mx:Script>
ADOBE FLEX 3 117
Adobe Flex 3 Developer Guide
<mx:Button id="button1"
label="Click here!"
width="100"
fontSize="12"
click="handleClick();"/>
<mx:TextArea id="text1"/>
</mx:Application>
This example has the following elements:
• The id property is inherited by the Button control from the UIComponent class. You use it to specify an
identifier for the component. This property is optional, but you must specify it if you want to access the
component in ActionScript.
• The label property is defined by the Button control. It specifies the text that appears in the button.
• The width property is inherited from the UIComponent class. It optionally specifies the width of the button,
in pixels.
• The Button control dispatches a click event when a user presses and releases the main mouse button. The
MXML click attribute specifies the ActionScript code to execute in response to the event.
• The fontSize style is inherited from the UIComponent class. It specifies the font size of the label text, in
pixels.
Note: The numeric values specified for font size in Flex are actual character sizes in the chosen units. These values are
not equivalent to the relative font size specified in HTML by using the <font> tag.
The click event attribute can also take ActionScript code directly as its value, without your having to specify it
in a function. Therefore, you can rewrite this example as the following code shows:
<?xml version="1.0"?>
<!-- components\ButtonAppAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Button id="button1"
label="Click here!"
width="100"
fontSize="12"
click="text1.text='Thanks for the click!';"/>
<mx:TextArea id="text1"/>
</mx:Application>
Both of these examples result in the following image, after the button is clicked:
118 CHAPTER 6
Note: Although you can specify multiple lines of ActionScript code (separated by semicolons) as the value of the click
event attribute, for readability you should limit the click event to only one or two lines of code.
<mx:Script>
<![CDATA[
private function initDate():void {
label1.text += new Date();
}
]]>
</mx:Script>
<mx:Box borderStyle="solid">
<mx:Label id="label1"
text="Today's Date: "
initialize="initDate();"/>
</mx:Box>
</mx:Application>
ADOBE FLEX 3 119
Adobe Flex 3 Developer Guide
You can also express the previous example without a function call by adding the ActionScript code in the
component’s definition. The following example does the same thing, but without an explicit function call:
<?xml version="1.0"?>
<!-- components\LabelInitAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Box borderStyle="solid">
<mx:Label id="label1"
text="Today's Date:"
initialize="label1.text += new Date();"/>
</mx:Box>
</mx:Application>
As with other calls that are embedded within component definitions, you can add multiple ActionScript state-
ments to the initialize MXML attribute by separating each function or method call with a semicolon. The
following example calls the initDate() function and writes a message in the flexlog.txt file when the label1
component is instantiated:
<?xml version="1.0"?>
<!-- components\LabelInitASAndEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function initDate():void {
label1.text += new Date();
}
]]>
</mx:Script>
<mx:Box borderStyle="solid">
<mx:Label id="label1"
text="Today's Date:"
initialize="initDate(); trace('The label is initialized!');"/>
</mx:Box>
</mx:Application>
120 CHAPTER 6
Read-only You cannot use a read-only property as an To get the value of a read-only property:
property attribute in MXML.
var theClass:String=mp1.className;
var currentPaddingTop:Number =
tile1.getStyle("paddingTop");.
var currentShowEffect:String =
tile1.getStyle("showEffect");
ADOBE FLEX 3 121
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
private function logSizes():void {
trace("HBox: "+ hb1.width);
trace("Label: "+ lb1.width);
trace("Image: "+ img1.width);
trace("Button: "+ b1.width);
}
]]>
</mx:Script>
<mx:HBox id="hb1" width="250">
<mx:Label id="lb1"
text="Hello"
width="50"/>
<mx:Image id="img1"
source="@Embed(source='assets/flexlogo.jpg')"
width="75%"/>
<mx:Button id="b1"
label="Button"
width="25%"/>
</mx:HBox>
</mx:Application>
The application consists of a 250-pixel-wide HBox container that contains a 50-pixel-wide label, an image that
requests 75% of the container width, and a button that requests 25% of the container width. The component sizes
are determined as follows:
1 Flex reserves 50 pixels for the explicitly sized Label control.
2 Flex puts an 8-pixel gap between components by default, so it reserves 16 pixels for the gaps; this leaves 184
pixels available for the two percentage-based components.
3 The minimum width of the Button component, if you do not specify an explicit width, fits the label text plus
padding around it. In this case, the minimum size is 65 pixels. This value is larger than 25% of the component, so
Flex does not use the percentage request, and reserves 65 pixels for the Button control.
4 The percentage-based image requests 75% of 250 pixels, or 187 pixels, but the available space is only 119
pixels, which it takes.
ADOBE FLEX 3 123
Adobe Flex 3 Developer Guide
If you change the button and image size properties to 50%, the minimum button size is smaller than the
requested size, so the percentage-sized controls each get 50% of the available space, or 92 pixels.
The following example uses explicit sizing for the Image control and default sizing for the Button control, and
yields the same results as the initial example:
<?xml version="1.0"?>
<!-- components\CompSizingExplicit.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="logSizes();">
<mx:Script>
<![CDATA[
private function logSizes():void {
trace("HBox: "+ hb1.width);
trace("Label: "+ lb1.width);
trace("Image: "+ img1.width);
trace("Button: "+ b1.width);
}
]]>
</mx:Script>
<mx:Script>
<![CDATA[
private function logSizes():void {
trace("HBox: "+ hb1.width);
trace("Label: "+ lb1.width);
trace("Image: "+ img1.width);
trace("Button: "+ b1.width);
}
]]>
</mx:Script>
124 CHAPTER 6
<mx:HBox width="100%">
<mx:HBox id="hb1" width="40%" borderStyle="solid">
<mx:Label id="lb1"
text="Hello"
width="50"/>
<mx:Image id="img1"
source="@Embed(source='assets/flexlogo.jpg')"
width="60%"/>
<mx:Button id="b1"
label="Button"
width="40%"
click="logSizes();"/>
</mx:HBox>
Handling events
Flex applications are event driven. Events let a programmer know when the user has interacted with an interface
component, and also when important changes have happened in the appearance or life cycle of a component, such
as the creation or destruction of a component or its resizing.
When an instance of a component dispatches an event, objects that have registered as listeners for that event are
notified. You define event listeners, also called event handlers, in ActionScript to process events. You register event
listeners for events either in the MXML declaration for the component or in ActionScript. For additional examples
of the event handling, see “Initializing components at run time” on page 118.
The following example registers an event listener in MXML that is processed when you change views in an
Accordion container.
<?xml version="1.0"?>
<!-- components\CompIntroEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="300"
height="280">
<mx:Script>
ADOBE FLEX 3 125
Adobe Flex 3 Developer Guide
<![CDATA[
import mx.controls.Alert;
private function handleAccChange():void {
Alert.show("You just changed views.");
}
]]>
</mx:Script>
You can pass an event object, which contains information about the event, from the component to the event
listener.
For the Accordion container, the event object passed to the event listener for the change event is of class Index-
ChangedEvent. You can write your event listener to access the event object, as the following example shows:
<?xml version="1.0"?>
<!-- components\CompIntroEventAcc.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="300"
height="280">
<mx:Script>
<![CDATA[
126 CHAPTER 6
c Flex dispatches the creationComplete event on the component. The component has been sized and
processed for layout and all properties are set. This event is dispatched only once when the component is
created.
d Flex dispatches the updateComplete event on the component. Flex dispatches additional
updateComplete events whenever the position, size, or other visual characteristic of the component changes
and the component has been updated for display.
You can later remove a component from a container by using the removeChild() method. The removed child’s
parent property is set to null. If you add the removed child to another container, it retains its last known state.
If there are no references to the component, it is eventually deleted from memory by the garbage collection
mechanism of Adobe® Flash® Player.
Given this sequence of actions, you should use the events as follows:
• The preinitialize event occurs too early in the component life cycle for most initialization activities. It is
useful, however, in the rare situations where you must set the properties on a parent before the children are
created.
• To configure a component before Flex has determined its visual appearance, use the initialize event. For
example, use this for setting properties that affect its appearance, height, or width.
• Use the creationComplete event for actions that rely on accurate values for the component’s size or position
when the component is created. If you use this event to perform an action that changes the visual appearance of
the component, Flex must recalculate its layout, which adds unnecessary processing overhead to your application.
• Use the updateComplete event for actions that must be performed each time a component’s characteristics
change, not just when the component is created.
Applying styles
Flex defines styles for setting some of the characteristics of components, such as fonts, padding, and alignment.
These are the same styles as those defined and used with Cascading Style Sheets (CSS). Each visual component
inherits many of the styles of its superclasses, and can define its own styles. Some styles in a superclass might not
be used in a subclass. To determine the styles that a visual component supports, see the styles section of the page
for the component in the Adobe Flex Language Reference.
You can set all styles in MXML as tag attributes. Therefore, you can set the padding between the border of a Box
container and its contents by using the paddingTop and paddingBottom properties, as the following example
shows:
<?xml version="1.0"?>
<!-- components\MXMLStyles.mxml -->
ADOBE FLEX 3 129
Adobe Flex 3 Developer Guide
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox id="myVBox2"
borderStyle="solid"
paddingTop="12"
paddingBottom="12" >
<mx:Button label="Submit"/>
</mx:VBox>
</mx:Application>
You can also configure styles in ActionScript by using the setStyle() method, or in MXML by using the
<mx:Style> tag. The setStyle() method takes two arguments: the style name and the value. The following
example is functionally identical to the previous example:
<?xml version="1.0"?>
<!-- components\ComponentsASStyles.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function initVBox():void {
myVBox2.setStyle("paddingTop", 12);
myVBox2.setStyle("paddingBottom", 12);
}
]]>
</mx:Script>
<mx:VBox id="myVBox2"
borderStyle="solid"
initialize="initVBox();">
<mx:Button label="Submit"/>
</mx:VBox>
</mx:Application>
When you use the <mx:Style> tag, you set the styles by using CSS syntax or a reference to an external file that
contains style declarations, as the following example shows:
<?xml version="1.0"?>
<!-- components\TagStyles.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myStyle {paddingTop: 12; paddingBottom: 12;}
</mx:Style>
</mx:VBox>
<mx:VBox id="myVBox2"
styleName="myStyle"
borderStyle="solid">
<mx:Button label="Submit"/>
</mx:VBox>
</mx:Application>
A class selector in a style definition, defined as a label preceded by a period, defines a new named style, such as
myClass in the preceding example. After you define it, you can apply the style to any component by using the
styleName property. In the preceding example, you apply the style to the second VBox container.
A type selector applies a style to all instances of a particular component type.
The following example defines the top and bottom margins for all Box containers:
<?xml version="1.0"?>
<!-- components\TypeSelStyles.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Box {paddingTop: 12; paddingBottom: 12;}
</mx:Style>
<mx:VBox id="myVBox" borderStyle="solid">
<mx:Button label="Submit"/>
</mx:VBox>
For more information on styles, see “Using Styles and Themes” on page 589.
ADOBE FLEX 3 131
Adobe Flex 3 Developer Guide
Applying behaviors
A behavior is a combination of a trigger paired with an effect. A trigger is an action similar to an event, such as a
mouse click on a component, a component getting focus, or a component becoming visible. An effect is a visible
or audible change to the component that occurs over a period of time, measured in milliseconds. Examples of
effects are fading, resizing, or moving a component. You can define multiple effects for a single trigger.
Flex trigger properties are implemented as CSS styles. In the Adobe Flex Language Reference, triggers are listed
under the heading “Effects.” Flex effects are classes, such as the mx.effects.Fade class.
Behaviors let you add animation, motion, and sound to your application in response to some user or program-
matic action. For example, you can use behaviors to cause a dialog box to bounce slightly when it receives focus,
or to play a sound when the user enters an invalid value.
Because effect triggers are implemented as CSS styles, you can set the trigger properties as tag attributes in MXML,
in <mx:Style> tags, or in ActionScript by using the setStyle function.
To create the behavior, you define a specific effect with a unique ID and bind it to the trigger. For example, the
following code creates a fade effect named myFade and uses an MXML attribute to bind the effect to the
creationCompleteEffect trigger of an Image control:
<?xml version="1.0"?>
<!-- components\CompIntroBehaviors.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="110"
height="100"
backgroundImage="">
For detailed information on using behaviors, see “Using Behaviors” on page 545.
132 CHAPTER 6
Applying skins
Skins are graphical style elements that a component uses to control its appearance. Flex components can have one
or more skins. For example, the Button component has eight skins, each for a different button state, such as up,
down, disabled, selected, down, and so on. A control can also have different skins for different subcomponents:
for example, the scroll bar has several skins each for the down arrow, up arrow, and thumb.
For more information on skinning, see “Creating Skins” on page 689.
<mx:Script>
<![CDATA[
public function moveButton():void {
myButton.x += 15;
myButton.y += 15;
}
]]>
</mx:Script>
<mx:Button id="myButton"
x="15"
y="15"
ADOBE FLEX 3 133
Adobe Flex 3 Developer Guide
label="Move"
click="moveButton();"/>
</mx:Application>
The following example shows the initial image and the results after the user clicks the button each of two times:
In this application, you can move the Button control without concern for other components. However, moving a
component in an application that contains multiple components, or modifying one child of a container that
contains multiple children, can cause one component to overlap another, or in some other way affect the layout of
the application. Therefore, you should be careful when you perform run-time modifications to container layout.
You can set the width and height properties for a component in any type of container. The following example
increases the width and height of a Button control by 15 pixels each time the user selects it:
<?xml version="1.0"?>
<!-- components\ButtonSize.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="150"
height="150">
<mx:Script>
<![CDATA[
public function resizeButton():void {
myButton.height = myButton.height + 15;
myButton.width = myButton.width + 15;
}
]]>
</mx:Script>
<mx:VBox
borderStyle="solid"
height="80"
width="100" >
<mx:Button id="myButton"
label="Resize"
click="resizeButton();"/>
</mx:VBox>
</mx:Application>
134 CHAPTER 6
This example results in the following progression when the user clicks the button:
If the container that holds the Button does not use absolute positioning, it repositions its children based on the
new size of the Button control. The Canvas container and Panel and Application containers with
layout="absolute" perform no automatic layout, so changing the size of one of their children does not change
the position or size of any of the other children.
Note: The stored values of width and height are always in pixels regardless of whether the values were originally set
as fixed values, as percentages, or not set at all.
Extending components
Flex SDK provides several ways for you to extend existing components or to create components. By extending a
component, you can add new properties or methods to it.
For example, the following MXML component, defined in the file MyComboBox.mxml, extends the standard
ComboBox control to initialize it with the postal abbreviations of the states in New England:
<?xml version="1.0"?>
<!-- components\myComponents\MyComboBox.mxml -->
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:dataProvider>
<mx:String>CT</mx:String>
<mx:String>MA</mx:String>
<mx:String>ME</mx:String>
<mx:String>NH</mx:String>
<mx:String>RI</mx:String>
<mx:String>VT</mx:String>
</mx:dataProvider>
</mx:ComboBox>
This example also shows how the MXML compiler lets you use some coding shortcuts. Flex expects the dataPro-
vider to be an array, so you do not have to specify a <mx:Array> tag.
After you create it, you can use your new component anywhere in your application by specifying its filename as
its MXML tag name, as the following example shows:
<?xml version="1.0"?>
<!-- components\MainMyComboBox.mxml -->
ADOBE FLEX 3 135
Adobe Flex 3 Developer Guide
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComps="myComponents.*"
width="150"
height="150">
<MyComps:MyComboBox id="stateNames"/>
</mx:Application>
In this example, the new component is in the myComponents subdirectory. The myComponents.* namespace is
mapped to the MyComps identifier.
Flex lets you create custom components by using either of the following methods. The method you choose
depends on your application and the requirements of your component:
• Create components as MXML files and use them as custom tags in other MXML files. MXML components
provide an easy way to extend an existing component, particularly to modify the behavior of an existing
component or add a basic feature to an existing component.
• Create components as ActionScript files by subclassing the UIComponent class or any of its subclasses, and
use the resulting classes as custom tags. ActionScript components provide a powerful tool for creating new visual
or nonvisual components.
For detailed information on creating custom components, see Creating and Extending Adobe Flex 3 Components.
136 CHAPTER 6
137
Topics
About collections and data provider components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Using simple data access properties and methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Working with data views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Collection events and manual change notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Hierarchical data objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Remote data in data provider components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Data providers and the uid property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
About collections
Collections are objects that provide a uniform way to access and represent the data contained in a data source
object, such as an Array or an XMLList object. Collections provide a level of abstraction between Flex components
and the data objects that you use to populate them.
The standard collection types in the Flex framework, the ArrayCollection and the XMLListCollection classes,
extend the mx.collections.ListCollectionView class, which implements the mx.collections.ICollectionView and
mx.collections.IList interfaces. These interfaces provide the underlying functionality for viewing and modifying
data objects. An ArrayCollection object takes an Array as its source object. An XMLListCollection object take an
XMLList object as its source object.
Collections provide the following features:
• Ensure that a component is properly updated when the underlying data changes. Components are not
updated when noncollection data objects change. (They are updated to reflect the new data the next time they are
refreshed.) If the data provider is a collection, the components are updated immediately after the collection
change occurs.
• Provide mechanisms for handling paged data from remote data sources that may not initially be available and
may arrive over a period of time.
• Provide a consistent set of operations on the data, independent of those provided by the raw data source. For
example, you can insert and delete objects by using an index into the collection, independently of whether the
underlying data is, for example, in an Array or an Object.
• Provide a specific view of the data that can be in sorted order, or filtered by a developer-supplied method. This
is only a view of the data; it does not change the data.
• Use a single collection to populate multiple components from the same data source.
• Use collections to switch data sources for a component at run time, and to modify the content of the data
source so that changes are reflected by all components that use the data source.
• Use collection methods to access data in the underlying data source.
Note: If you use a raw data object, such as an Array, as a control’s data provider, Flex automatically wraps the object
in a collection wrapper. The control does not automatically detect changes that are made directly to the raw object. A
change in the length of an array, for example, does not result in an update of the control. You can, however, use an
object proxy, a listener interface, or the itemUpdated property to notify the view of certain changes.
ADOBE FLEX 3 139
Adobe Flex 3 Developer Guide
Collection interfaces
Collections use the following interfaces to define how a collection represents data and provides access to it. The
standard Flex framework collections, the ArrayCollection and XMLListCollection classes, implement both the
ICollectionView interface and the IList interface. The IList and ICollectionView interfaces provide alternate
methods for accessing and changing data. The IList interface is simpler; it provides add, set, get, and remove
operations that operate directly on linear data.
Interface Description
IList A direct representation of items organized in an ordinal fashion. The interface presents the data from the source
object in the same order as it exists in that object, and provides access and manipulation methods based on an
index. The IList class does not provide sorting, filtering, or cursor functionality.
ICollectionView A view of a collection of items. You can modify the view to show the data in sorted order and to show a subset
of the items in the source object, as specified by a filter function. A class that implements this interface can use
an IList interface as the underlying collection.
The interface provides access to an IViewCursor object for access to the items.
IViewCursor Enumerates an object that implements the ICollectionView interface bidirectionally. The view cursor provides
find, seek, and bookmarking capabilities, and lets you modify the underlying data (and the view) by inserting
and removing items.
The ICollectionView interface (also called the collection view) provides a more complex set of operations than the
IList interface, and is appropriate when the underlying data is not organized linearly. Its data access techniques,
however, are more complex than those of the IList interface, so you should use the IList interface if you need only
simple, indexed access to a linear collection. The collection view can represent a subset of the underlying data, as
determined by a sort or filter operation.
140 CHAPTER 7
Collection classes
The following table describes the public classes in the mx.collections package. It does not include constant, event,
and error classes. For complete reference information on collection-related classes, see the collections and collec-
tions.errors packages, and the CollectionEvent and CollectionEventKind classes in the Adobe Flex Language
Reference.
Class Description
ArrayCollection A standard collection for working with Arrays. Implements the IList and ICollectionView interfaces.
XMLListCollection A standard collection for working with XMLList objects. Implements the IList and ICollectionView interfaces,
and a subset of XMLList methods.
You can save a view cursor position in a CursorBookmark object and use the object to return the view cursor
to the position at a later time.
SortField Provides properties and methods that determine how a specific field affects data sorting in a collection.
ItemResponder (Used only if the data source is remote.) Handles cases when requested data is not yet available.
ListCollectionView Superclass of the ArrayCollection and XMLListCollection classes. Adapts an object that implements the IList
interface to the ICollectionView interface so that it can be passed to anything that expects an IList or an ICol-
lectionView.
• HorizontalList
• LinkBar
• List
• Menu
• MenuBar
• PopUpMenuButton
• Repeater
• TabBar
• TileList
• ToggleButtonBar
• Tree
Although raw data objects, such as an Array of strings or objects, are wrapped in collections when you use them
as the value of a dataProvider property, using collections explicitly is a better practice. Using collections
explicitly ensures data synchronization and provides both simpler and more sophisticated data access and manip-
ulation tools than are available when you are using raw objects directly as data providers. Collections can also
provide a consistent interface for accessing and managing data of different types. For more information about
collections, see “About collections and data provider components” on page 137.
Although raw data objects are automatically wrapped in an ArrayCollection object or XMLListCollection object
when used as the value of a data provider component’s dataProvider property, they are subject to the following
limitations:
• Raw objects are often not sufficient if you have data that changes, because the data provider component does
not receive a notification of any changes to the base object. The component therefore does not get updated until
it must be redrawn due to other changes in the application, or if the data provider is reassigned. At that time, it
gets the data again from the updated raw object.
• Raw objects do not provide advanced tools for accessing, sorting, or filtering data. For example, if you use an
Array as the data provider, you must use the native Adobe® Flash® Array methods to manipulate the data.
For detailed descriptions of the individual controls, see the pages for the controls in the Adobe Flex Language
Reference. For information on programming with many of the data provider components, see “Using Data-Driven
Controls” on page 373.
142 CHAPTER 7
Data objects
The Flex framework supports the following types of data objects for populating data provider components:
Linear or list-based data objects are flat data structures consisting of some number of objects, each of which has
the same structure; they are often one-dimensional Arrays or ActionScript object graphs, or simple XML struc-
tures. You can specify one of these data structures in an ArrayCollection object’s or XMLListCollection object’s
source property or as the value of a data provider control’s dataProvider property.
You can use list-based data objects with all data provider controls, but you do not typically use them with Tree and
most menu-based controls, which typically use hierarchical data structures. For data that can change dynamically,
you typically use an ArrayCollection object or XMLListCollection object to represent and manipulate these data
objects rather than the raw data object. You can also use a custom object that implements the ICollectionView and
IList interfaces.
Hierarchical data objects consist of cascading levels of often asymmetrical data. Often, the source of the data is
an XML object, but the source can be a generic Object tree or trees of typed objects. You typically use hierarchical
data objects with Flex controls that are designed to display hierarchical data:
• Tree
• Menu
• MenuBar
• PopUpMenuButton
A hierarchical data object matches the layout of a tree or cascading menu. For example, a tree often has a root
node, with one or more branch or leaf child nodes. Each branch node can hold additional child branch or leaf
nodes, but a leaf node is an endpoint of the tree.
The Flex hierarchical data provider controls use data descriptor interfaces to access and manipulate hierarchical
data objects, and the Flex framework provides one class, the DefaultDataDescriptor class, which implements the
required interfaces. If your data object does not conform to the structural requirements of the default data
descriptor, you can create your own data descriptor class that implements the required interfaces.
You can use an ArrayCollection object or XMLListCollection object, or a custom object that implements the
ICollectionView and IList interfaces to access and manipulate dynamic hierarchical data.
You can also use a hierarchical data object with controls that take linear data, such as the List control and the
DataGrid control, by extracting specific data for linear display.
For more information on using hierarchical data providers, see “Hierarchical data objects” on page 167.
ADOBE FLEX 3 143
Adobe Flex 3 Developer Guide
<mx:HBox>
<mx:Label text="Select a department:"/>
<mx:ComboBox id="dept" width="150">
ADOBE FLEX 3 145
Adobe Flex 3 Developer Guide
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<mx:Object label="Engineering" data="ENG"/>
<mx:Object label="Product Management" data="PM"/>
<mx:Object label="Marketing" data="MKT"/>
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:ComboBox>
<mx:Button label="Get Employee List"
click="employeeRO.getList.send()"/>
</mx:HBox>
<mx:DataGrid dataProvider="{employeeAC}" width="100%">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="phone" headerText="Phone"/>
<mx:DataGridColumn dataField="email" headerText="Email"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
The following example shows a ComboBox control that takes a static Array as its dataProvider value. As noted
previously, using raw objects as data providers is not a best practice and should be considered only for data objects
that will not change.
<?xml version="1.0"?>
<!-- dpcontrols/StaticComboBox.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var myArray:Array = ["AL", "AK", "AR"];
]]>
</mx:Script>
<mx:ComboBox id="myCB0" dataProvider="{myArray}"/>
</mx:Application>
In the preceding example, because the Array specified as the dataProvider is automatically wrapped in an
ArrayCollection object but the ArrayCollection does not have an id property, you can use ArrayCollection
methods and properties directly through the dataProvider property, as the following example shows:
<mx:Button label="Add AZ"
click="myCBO.dataProvider.addItem({'label':'AZ','data':'Phoenix'});"/>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var DGArray:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted', Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners', Price:11.99}]);
<mx:DataGrid id="myGrid">
<mx:columns>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
ADOBE FLEX 3 147
Adobe Flex 3 Developer Guide
</mx:columns>
</mx:DataGrid>
</mx:Application>
In this example, you use the intialize event to set the dataProvider property of the DataGrid control.
In some situations, you might set the dataProvider property, and then immediately attempt to perform an action
on the control based on the setting of the dataProvider property, as the following example shows:
<?xml version="1.0"?>
<!-- dpcontrols/DataGridValidateNowSelindex.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initData();">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var DGArray:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted', Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners', Price:11.99}]);
<mx:DataGrid id="myGrid">
<mx:columns>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
In this example, setting the selectedindex to 1 might fail because the DataGrid control is in the process of
setting the dataProvider property. Therefore, you insert the validateNow() method after setting the data
provider. The validateNow() method validates and updates the properties and layout of the control, and then
redraws it, if necessary.
Do not insert the validateNow() method every time you set the dataProvider property because it can affect
the performance of your application; it is only required in some situations when you attempt to perform an
operation on the control immediately after setting its dataProvider property.
148 CHAPTER 7
<mx:HBox width="100%">
<!-- A ComboBox populated by the underlying Array object.
This control shows that Array retains its original order
and MD is inserted at the end of the Array. -->
<mx:ComboBox id="cb2" rowCount="10" dataProvider="{myArray}"/>
ADOBE FLEX 3 149
Adobe Flex 3 Developer Guide
The code includes comments that describe the changes to the data object.
<?xml version="1.0"?>
<!-- dpcontrols\UseIList.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initData()">
<mx:Script>
<![CDATA[
import mx.collections.*;
</mx:Application>
Sorting
A Sort object lets you sort data in a collection. You can specify multiple fields to use in sorting the data, require
that the resulting entries be unique, and specify a custom comparison function to use for ordering the sorted
output. You can also use a Sort object to find items in a collection. When you create a Sort object, or change its
properties, you must call the refresh() method on the collection to show the results.
152 CHAPTER 7
You use SortField objects to specify the fields to use in the sort. You create SortField objects and put them in the
Sort class object’s fields array.
The following example shows a function to sort a collection. In this example, myAC is an ArrayCollection that
contains an Array with label and name fields. The primary sort is a descending, case-insensitive sort on the area
field, and the secondary sort is an ascending, case-sensitive sort on the label field. You might call it as the initialize
event handler for a control that must display a specific sorted view of a collection.
//Sort the collection in descending order.
public function sortAC():void {
//Create a Sort object.
var sortA:Sort = new Sort();
// Sort first on the area field, then the label field.
// The second parameter specifies that the sort is case-insensitive.
// A true third parameter specifies a descending sort.
sortA.fields=[new SortField("area", true, true),
new SortField("label")];
myAC.sort=sortA;
//Refresh the collection to show the sort.
myAC.refresh();
}
Filtering
You use a filter function to limit the data view in the collection to a subset of the source data object. The function
must take a single Object parameter, which corresponds to a collection item, and must return a Boolean value
specifying whether to include the item in the view. As with sorting, when you specify or change the filter function,
you must call the refresh() method on the collection to show the filtered results. To limit a collection view of
an array of strings to contain only strings starting with M, for example, use the following filter function:
public function stateFilterFunc(item:Object):Boolean
{
return item >= "M" && item < "N";
}
sortA.fields=[new SortField("label")];
myAC.sort=sortA;
//Refresh the collection view to show the sort.
myAC.refresh();
}
]]>
</mx:Script>
<!-- Buttons to filter, sort, or reset the view in the second ComboBox
control. -->
<mx:HBox width="100%">
<mx:Button id="sortButton" label="Sort" click="sortAC();"/>
<mx:Button id="filterButton" label="Filter" click="filterAC();"/>
<mx:Button id="resetButton" label="Reset" click="resetAC();"/>
</mx:HBox>
<mx:VBox width="550" height="143" borderStyle="solid" paddingTop="10"
paddingLeft="10">
<mx:Label text="This box retains original order and contents of the Array:"/>
<!-- A ComboBox populated by the underlying Array object.
This control shows that Array retains its original order. -->
<mx:ComboBox id="cb2" rowCount="10" dataProvider="{myArray}"/>
154 CHAPTER 7
<mx:HRule/>
<mx:Label text="This box reflects the changes to the Array:"/>
<!-- A ComboBox populated by the collection view of the Array. -->
<mx:ComboBox id="cb1" rowCount="10" dataProvider="{myAC}"/>
</mx:VBox>
</mx:Application>
For a more complex example of sorting a DataGrid control, which does both an initial sort of the data and a
custom sort when you click a column heading, see “Example: Sorting a DataGrid on multiple columns” on
page 402.
2 The findAny(), findFirst(), and findLast() methods move the cursor to an item that matches the
parameter. Before you can use these methods, you must apply a Sort to the collection (because the functions use
Sort methods).
If it is not important to find the first occurrence of an item or the last occurrence of an item in a nonunique index,
the findAny() method can be somewhat more efficient than either the findFirst() or the findLast()
method.
If the associated data is from a remote source, and not all of the items are cached locally, the find methods begin
an asynchronous fetch from the remote source; if a fetch is already in progress, they wait for it to complete before
making another fetch request.
The following example finds an item inside a collection of simple objects—in this case, an ArrayCollection of state
ZIP code strings. It creates a default Sort object, applies it to an ArrayCollection object, and finds the first instance
of the string "MZ" in a simple array of strings:
var sortD:Sort = new Sort();
// The null first parameter on the SortField constructor specifies a
// collection of simple objects (String, numeric, or Boolean values).
// The true second parameter specifies a case-insensitive sort.
sortD.fields = [new SortField(null, true)];
myAC.sort=sortD;
myAC.refresh();
myCursor.findFirst("MZ");
To find a complex object, you can use the findFirst() method to search on multiple sort fields. You cannot,
however, skip fields in the parameter of any of the find methods. If an object has three fields, for example, you can
specify any of the following field combinations in the parameter: 1, 1,2, or 1,2,3, but you cannot specify only fields
1 and 3.
Both of the following lines find an object with the label value "ME" and data value "Augusta":
myCursor.findFirst({label:"ME"});
myCursor.findFirst({label:"ME", data:"Augusta"});
3 The seek() method moves the cursor to a position relative to a bookmark. You use this method to move the
cursor to the first or last item in a view, or to move to a bookmark position that you have saved. For more infor-
mation on using bookmarks and the seek() method, see “Using bookmarks” on page 156.
• The remove() method removes the item at the current cursor location; if the removed item is not the last
item, the cursor points to the location after the removed item.
The following example shows the results of using insert() and remove() on the current property:
<?xml version="1.0"?>
<!-- dpcontrols\GetAddRemoveItems.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initData();">
<mx:Script>
<![CDATA[
import mx.collections.*;
public var myArray:Array = [{label:"MA", data:"Massachusetts"},
{label:"MN", data:"Minnesota"}, {label:"MO", data:"Missouri"}];
[Bindable]
public var myAC:ArrayCollection;
public var myCursor:IViewCursor;
Using bookmarks
You use a bookmark to save a cursor location for later use. You can also use the built-in FIRST and LAST bookmark
properties to move the cursor to the first or last item in the data view.
ADOBE FLEX 3 157
Adobe Flex 3 Developer Guide
// Initialize variables.
public function run():void {
// Initialize the cursor.
myCursor=myAC.createCursor();
// The findFirst() method, used in
// countFromSelection() requires a
// sorted view.
var sort:Sort = new Sort();
sort.fields=[new SortField("label")];
myAC.sort=sort;
//You must refresh the view to apply the sort.
myAC.refresh();
}
initialize="initData();">
<mx:Script>
<![CDATA[
import mx.collections.*;
// The data provider is an array of Strings.
public var myArray:Array = ["AZ", "MA", "MZ", "MN", "MO", "MS"];
// Declare an ArrayCollection that represents the Array.
// The variable must be bindable so the ComboBox can update properly.
[Bindable]
public var myAC:ArrayCollection;
//Boolean flag to ensure the update routine hasn't been run before.
public var runBefore:Boolean=false;
myCursor.insert("MI");
}
//Reset the Array and update the display to run the example again.
public function resetView():void {
myArray = ["AZ", "MA", "MZ", "MN", "MO", "MS"];
myAC = new ArrayCollection(myArray);
ta1.text="Reset";
runBefore=false;
}
ADOBE FLEX 3 161
Adobe Flex 3 Developer Guide
]]>
</mx:Script>
Collection events
Collections use CollectionEvent, PropertyChangeEvent, and FlexEvent objects in the following ways:
• Collections dispatch a CollectionEvent (mx.events.CollectionEvent) event whenever the collection changes.
All collection events have the type property value CollectionEvent.COLLECTION_CHANGE.
• The CollectionEvent object includes a kind property that indicates the way in which the collection changed.
You can determine the change by comparing the kind property value with the CollectionEventKind constants; for
example, UPDATE.
• The CollectionEvent object includes an items property that is an Array of objects whose type varies
depending on the event kind. For ADD and REMOVE kind events, the array contains the added or removed
items. For UPDATE events, the items property contains an Array of PropertyChangeEvent event objects. This
object’s properties indicate the type of change and the property value before and after the change.
• The PropertyChangeEvent class kind property indicates the way in which the property changed. You can
determine the change type by comparing the kind property value with the PropertyChangeEventKind constants;
for example, UPDATE.
• View cursor objects dispatch a FlexEvent class event with the type property value of
mx.events.FlexEvent.CURSOR_UPDATE when the cursor position changes.
You use collection events to monitor changes to a collection to update the display. For example, if a custom control
uses a collection as its data provider, and you want the control to be updated dynamically and to display the revised
data each time the collection changes, the control can monitor the collection events and update accordingly.
162 CHAPTER 7
You could, for example, build a simple rental-car reservation system that uses collection events. This application
uses COLLECTION_CHANGE event type listeners for changes to its reservations and cars data collections.
The CollectionEvent listener method, named reservationsChanged, tests the event kind field and does the
following:
• If the event kind property is ADD, iterates through the objects in the event’s items property and calls a function
to update the reservation information display with boxes that display the time span of each reservation.
• If the event kind property is REMOVE, iterates through the objects in the event’s items property and calls a
function to remove the reservation box for each item.
• If the event kind property is UPDATE, iterates through the PropertyChangeEvent objects in the event’s items
property and calls the update function to update each item.
• If the event kind property is RESET, calls a function to reset the reservation information.
The following example shows the reservationsChanged CollectionEvent event listener function:
private function reservationsChanged(event:CollectionEvent):void {
switch (event.kind) {
case CollectionEventKind.ADD:
for (var i:uint = 0; i < event.items.length; i++) {
updateReservationBox(Reservation(event.items[i]));
}
break;
case CollectionEventKind.REMOVE:
for (var i:uint = 0; i < event.items.length; i++) {
removeReservationBox(Reservation(event.items[i]));
}
break;
case CollectionEventKind.UPDATE:
for (var i:uint = 0; i < event.items.length; i++) {
if (event.items[i] is PropertyChangeEvent) {
if (PropertyChangeEvent(event.items[i]) != null) {
updateReservationBox(Reservation(PropertyChangeEvent(
event.items[i]).source));
}
}
else if (event.items[i] is Reservation) {
updateReservationBox(Reservation(event.items[i]));
}
}
break;
case CollectionEventKind.RESET:
refreshReservations();
break;
}
}
ADOBE FLEX 3 163
Adobe Flex 3 Developer Guide
The updateReservationBox() method either shows or hides a box that shows the time span of the reservation.
The removeReservationBox() method removes a reservation box. The refreshReservations() method
redisplays all current reservation information.
For more information on the application and the individual methods, see the sample code.
The most common use of t he itemUpdate() method is to notify a collection of changes to a custom class data
source that you cannot make bindable or modify to implement the IEventDispatcher interface. The following
schematic example shows how you could use the itemUpdated() method in such a circumstance.
Assume you have a class that you do not control or edit and that looks like the following:
public class ClassICantEdit {
public var field1:String;
public var field2:String;
}
You have an ArrayCollection that uses these objects, such as the following, which you populate with
classICantEdit objects:
public var myCollection:ArrayCollection = new ArrayCollection();
You have a DataGrid control such as the following:
<mx:DataGrid dataProvider="{myCollection}"/>
When you update a field in the myCollection ArrayCollection, as follows, the DataGrid control is not automat-
ically updated:
myCollection.getItemAt(0).field1="someOtherValue";
To update the DataGrid control, you must use the collection’s itemUpdated() method:
myCollection.itemUpdated(collectionOfThoseClasses.getItemAt(0));
<mx:Script>
<![CDATA[
import mx.events.*;
import mx.collections.*;
<mx:TextInput id="lastInput"/>
</mx:FormItem>
<mx:FormItem label="Email">
<mx:TextInput id="emailInput"/>
</mx:FormItem>
</mx:Form>
<mx:HBox>
<!-- Buttons to initiate operations on the collection. -->
<mx:Button label="Add New" click="addPerson()"/>
<mx:Button label="Update Selected" click="updatePerson()"/>
<mx:Button label="Remove Selected" click="removePerson()"/>
<!-- Clear the text input fields. -->
<mx:Button label="Clear" click="clearInputs()"/>
</mx:HBox>
Objects can be any set of nested Objects or Object subclasses (including Arrays or ArrayCollection objects) that
have a structure where the children of a node are in a children field. For more information, see “Creating a
custom data descriptor” on page 172. You can also use the <mx:Model> compile-time tag to create nested objects
that support data binding, but you must follow the structure defined in “Using the <mx:Model> tag with Tree and
menu-based controls” on page 171.
You can add support for other hierarchical data provider structures, such as nested Objects where the children
might be in fields with varying names.
hasChildren(node, [model]) A Boolean value indicating For XML, returns true if the node has at least one child element.
whether the node is a
branch with children. For other objects, returns true if the node has a nonempty children field.
getChildren(node, [collection]) A node’s children. For XML, returns an XMLListCollection with the child elements.
For other Objects, returns the contents of the node’s children field.
isBranch(node, [collection]) Whether a node is a For XML, returns true if the node has at least one child, or if it has an
branch. isBranch attribute.
For other Objects, returns true if the node has an isBranch field.
addChildAt(node, child, index, A Boolean value indicating For all cases, inserts the node as a child object before the node currently in the
[model]) whether the operation index location.
succeeded.
removeChildAt A Boolean value indicating For all cases, removes the child of the node in the index location.
(node, index, [model]) whether the operation
succeeded.
getType(node) A String with the menu For XML, returns the value of the type attribute of the node.
node type. Meaningful
(IMenuDataDescriptor only) values are check, radio, For other Objects, returns the contents of the node’s type field.
and separator.
isEnabled(node) A Boolean value indicating For XML, returns the value of the enabled attribute of the node.
whether a menu node is
(IMenuDataDescriptor only) enabled. For other Objects, returns the contents of the node’s enabled field.
setEnabled(node, value) For XML, sets the value of the enabled attribute of the node to true or
false.
(IMenuDataDescriptor only)
For other Objects, sets the contents of the node’s enabled field.
170 CHAPTER 7
isToggled(node) A Boolean value indicating Returns the value of the node’s toggled attribute.
whether a menu node is
(IMenuDataDescriptor only) selected
setToggled(node, value) For XML, sets the value of the selected attribute of the node to true or
false.
(IMenuDataDescriptor only)
For other Objects, sets the contents of the node’s enabled field.
getGroupName(node) The name of the radio For XML, returns the value of the groupName attribute of the node.
button group to which the
(IMenuDataDescriptor only) node belongs. For other Objects, returns the contents of the node’s groupName field.
The following example Object follows the default data provider structure for a Tree control, and is correctly
handled by the DefaultDataDescriptor class:
[Bindable]
public var fileSystemStructure:Object =
{label:"mx", children: [
{label:"Containers", children: [
{label:"Accordian", children:[]},
{label:"DividedBox", children: [
{label:"BoxDivider.as", data:"BoxDivider.as"},
{label:"BoxUniter.as", data:"BoxUniter.as"}]},
{label: "Grid", children:[]}]},
{label: "Controls", children: [
{label: "Alert", data: "Alert.as"},
{label: "Styles", children: [
{label: "AlertForm.as", data:"AlertForm.as"}]},
{label: "Tree", data: "Tree.as"},
{label: "Button", data: "Button.as"}]},
{label: "Core", children:[]}
]};
For objects, the root is the Object instance, so there must always be a single root (as with XML). You could also
use an Array containing nested Arrays as the data provider. In this case the provider has no root; each element in
the top level array appears at the top level of the control.
The DefaultDataDescriptor can properly handle well-formed XML nodes. The isBranch() method, however,
returns true only if the parameter node has child nodes or if the node has an isBranch attribute with the value
true. Therefore, if your XML object uses any technique other than a true isBranch attribute to indicate empty
branches, you must create a custom data descriptor.
The DefaultDataDescriptor handles collections properly. For example, if a node’s children property is an
ICollectionView instance, the getChildren() method returns the children as an ICollectionView object.
ADOBE FLEX 3 171
Adobe Flex 3 Developer Guide
import mx.controls.Menu;
public var productMenu:Menu;
]]>
</mx:Script>
<mx:Model id="Products">
<Root>
<Department label="Toys">
<children label="Teddy Bears"/>
<children label="Action Figures"/>
172 CHAPTER 7
The following code shows the MyCustomTreeDataDescriptor class, which implements only the ITreeDataDe-
scriptor interface, so it supports Tree controls but not menu-based controls. The custom class supports tree nodes
whose children field is either an ArrayCollection or an Object. When getting a node’s children, if the children
object is an ArrayCollection, it returns the object; otherwise, it wraps the children object in an ArrayCollection
before returning it. When adding a node, it uses a different method to add the node, depending on the children
field type.
package myComponents
// myComponents/MyCustomTreeDataDescriptor.as
{
import mx.collections.ArrayCollection;
import mx.collections.CursorBookmark;
import mx.collections.ICollectionView;
import mx.collections.IViewCursor;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
import mx.controls.treeClasses.*;
}
catch (e:Error) {
trace("[Descriptor] exception checking for isBranch");
}
return false;
}
// The hasChildren method Returns true if the
// node actually has children.
public function hasChildren(node:Object, model:Object=null):Boolean {
if (node == null)
return false;
var children:ICollectionView = getChildren(node, model);
try {
if (children.length > 0)
return true;
}
catch (e:Error) {
}
return false;
}
// The getData method simply returns the node as an Object.
public function getData(node:Object, model:Object=null):Object {
try {
return node;
}
catch (e:Error) {
}
return null;
}
// The addChildAt method does the following:
// If the parent parameter is null or undefined, inserts
// the child parameter as the first child of the model parameter.
// If the parent parameter is an Object and has a children field,
// adds the child parameter to it at the index parameter location.
// It does not add a child to a terminal node if it does not have
// a children field.
public function addChildAt(parent:Object, child:Object, index:int,
model:Object=null):Boolean {
var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
event.kind = CollectionEventKind.ADD;
event.items = [child];
event.location = index;
if (!parent) {
var iterator:IViewCursor = model.createCursor();
iterator.seek(CursorBookmark.FIRST, index);
iterator.insert(child);
}
else if (parent is Object) {
if (parent.children != null) {
if(parent.children is ArrayCollection) {
parent.children.addItemAt(child, index);
if (model){
model.dispatchEvent(event);
model.itemUpdated(parent);
}
return true;
ADOBE FLEX 3 175
Adobe Flex 3 Developer Guide
}
else {
parent.children.splice(index, 0, child);
if (model)
model.dispatchEvent(event);
return true;
}
}
}
return false;
}
}
}
176 CHAPTER 7
The following example uses the MyCustomTreeDataDescriptor to handle hierarchical nested ArrayCollections
and objects. When you click the button, it adds a node to the tree by calling the data descriptor’s addChildAt()
method. Notice that you would not normally use the addChildAt() method directly. Instead, you would use the
methods of a Tree or menu-based control, which in turn use the data descriptor methods to modify the data
provider.
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- dpcontrols\CustDataDescriptor.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
creationComplete="initCollections()">
<mx:Script>
<![CDATA[
import mx.collections.*;
import mx.controls.treeClasses.*;
import myComponents.*;
]]>
</mx:Script>
<mx:Label text="These two Tree controls appear identical, although their data sources
are different."/>
<mx:HBox>
<!-- When you use an XML-based data provider with a tree
you must specify the label field, even if it
is "label". The XML object includes the root,
so you must set showRoot="false". Remember that
the Tree will not, by default, reflect dynamic changes
to the XML object. -->
<mx:Tree id="Tree1" dataProvider="{capitals}" labelField="@label"
showRoot="false" width="300"/>
<!-- The XMLListCollection does not include the XML root. -->
<mx:Tree id="Tree2" dataProvider="{capitalColl}" labelField="@label"
width="300"/>
</mx:HBox>
</mx:Application>
This example shows two important features of using a hierarchical data provider with a Tree control:
ADOBE FLEX 3 179
Adobe Flex 3 Developer Guide
• ECMAScript for XML (E4X) objects must have a single root node, which might not be appropriate for
displaying in the Tree. Also, trees can have multiple elements at their highest level. To prevent the tree from
displaying the root node, set the showRoot property to false. (The default showRoot value for the Tree control
is true.) XMLList collections, however, do not have a single root, and you typically do not need to use the
showRoot property.
• When you use an XML, XMLList, or XMLListCollection object as the tree data provider, you must specify the
labelField property, even if it is “label”, if the field is an XML attribute. You must do this because you must use
the @ sign to signify an attribute.
XMLListCollection objects
XMLListCollection objects provide collection functionality to an XMLList object and make available some of the
XML manipulation methods of the native XMLList class, such as the attributes(), children(), and
elements() methods. For details of the supported methods, see XMLListCollection in the Adobe Flex Language
Reference.
The following simple example uses an XMLListCollection object as the data provider for a List control. It uses
XMLListCollection methods to dynamically add items to and remove them from the data provider and its repre-
sentation in the List control. The example uses a Tree control to represent a selection of shopping items and a List
collection to represent a shopping list.
Users add items to the List control by selecting an item in a Tree control (which uses a static XML object as its data
provider) and clicking a button. When the user clicks the button, the event listener uses the XMListCollection
addItem() method to add the selected XML node to the XMLListCollection. Because the data provider is a
collection, the List control is updated to show the new data.
Users remove items in a similar manner, by selecting an item in the list and clicking the Remove button. The event
listener uses the XMListCollection removeItemAt() method to remove the item from the data provider and its
representation in the List control.
<?xml version="1.0"?>
<!-- dpcontrols\XMLListCollectionWithList.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
import mx.collections.ArrayCollection;
<mx:HBox>
<mx:Tree id="prodTree" dataProvider="{myData}" width="200"
showRoot="false" labelField="@name"/>
<mx:VBox>
<mx:Button id="treeSelect" label="Add to List"
click="doTreeSelect()"/>
<mx:Button id="listRemove" label="Remove from List"
click="doListRemove()"/>
</mx:VBox>
<mx:List id="prodList" dataProvider="{listDP}" width="200"
labelField="@name"/>
</mx:HBox>
</mx:Application>
To use a remote data source to provide data, you represent the result of the remote service with the appropriate
object, as follows:
• A RemoteObject component automatically returns an ArrayCollection for any data that is represented on the
server as a java.util.List object, and you can use the returned object directly.
• For HTTPService and WebService results, cast the result data to a collection class if the data changes or if you
use the same result in multiple places (the latter case is more efficient). As a general rule, use an ArrayCollection
for serialized (list-based) objects and an XMLListCollection for XML data.
The following code snippet shows this use, casting a list returned by a web service to an Array in an ArrayCol-
lection:
<mx:WebService id="employeeWS" wsdl"http://server.com/service.wsdl"
showBusyCursor="true"
fault="alert(event.fault.faultstring)">
<mx:operation name="getList">
<mx:request>
<deptId>{dept.selectedItem.data}</deptId>
</mx:request>
</mx:operation>
.
.
</mx:WebService>
<mx:ArrayCollection id="ac"
source="mx.utils.ArrayUtil.toArray(employeeWS.getList.lastResult)"/>
<mx:DataGrid dataProvider="{ac}" width="100%">
For more information on using data access component, see “Accessing Server-Side Data with Flex” on page 1163.
Note: When Flex creates a UID for an object, such as an item in an ArrayCollection, it adds the UID as an
mx_internal_uid property of the item. Flex creates mx_internal_uid properties for any objects that are dynamic
and do not have bindable properties. To avoid having Flex create mx_internal_uid properties, the object class
should do any of the following things: have at least one property with a [Bindable] metadata tag; implement the
IUID interface; or have a uid property with a value.
If Flex must consider two or more different objects to be identical, the objects must implement the IUID interface
so that you can assign the same uid value to multiple objects. A typical case where you must implement the IUID
interface is an application that uses paged collections. As the cursor moves through the collection, a particular
item might be pulled down from the server and released from memory repeatedly. Every time the item is pulled
into memory, a new object is created to represent the item. If you need to compare items for equality, Flex should
consider all objects that represent the same item to be the same “thing.”
More common than the case where you must implement the IUID interface is the case where you can improve
processing efficiency by doing so. As a general rule, you do not implement the IUID interface if the data provider
elements are members of dynamic classes. Flex can automatically create a uid property for these classes. There is
still some inefficiency, however, so you might consider implementing the IUID interface if processing efficiency
is particularly important.
In all other cases, Flex uses the Dictionary mechanism to manage the uid, which might not be as efficient as
supplying your own UID.
The IUID interface contains a single property, uid, which is a unique identifier for the class member, and no
methods. Flex provides a UIDUtil class that uses a pseudo-random-number generator to create an identifier that
conforms to the standard GUID format. Although this identifier is not guaranteed to be universally unique, it
should be unique among all members of your class. To implement a class that uses the UIDUtil class, such as a
Person class that has fields for a first name, last name, and ID, you can use the following pattern:
package {
import mx.core.IUID;
import mx.utils.UIDUtil;
[Bindable]
public class Person implements IUID {
public var id:String;
public var firstName:String;
public var lastName:String;
private var _uid:String;
[Bindable]
public class Person implements IUID {
public var employee_id:String;
public var firstName:String;
public var lastName:String;
Topics
About sizing and positioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Sizing components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Positioning and laying out controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Using constraints to control component layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
• The content area and content coordinate system include all of the component’s contents, and do not include
the visual elements. They include any regions that are currently clipped from view and must be accessed by
scrolling the component. The content area of a scrolling TextArea control, for example, includes the region of text
that is currently scrolled off the screen.
Flex uses the viewable area when it determines percentage-based sizes and when it performs constraint-based
layout.
Flex component x and y properties, which you use to specify absolute positioning, are in the content coordinate
system.
Note: Flex coordinates increase from the upper-left corner of the frame of reference. Thus, an x,y position of 100,300
in the local coordinate system is 100 pixels to the right and 300 pixels down from the component’s upper-left corner.
For more information on Flex coordinate systems, see “Using Flex coordinates” on page 436.
Absolute positioning: General layout: Children of the container do not interact. That is, children can overlap and the position of
Canvas, container or one child does not affect the position of any other child. You specify the child positions explicitly or use
Application or Panel constraints to anchor the sides, baselines, or centers of the children relative to the parent container.
container with
layout="absolute"
Default sizing: The measurement pass finds the child with the lowest bottom edge and the child with the
rightmost edge, and uses these values to determine the container size.
Percentage-based children: Sizing uses different rules depending on whether you use constraint-based
layout or x- and y- coordinate positioning. See “Sizing percentage-based children of a container with abso-
lute positioning” on page 201.
Controls that arrange all General layout: All children of the container are arranged in a single row or column. Each child’s height
children linearly, such as and width can differ from all other children’s heights or widths.
Box, HBox, VBox
Default sizing: The container fits the default or explicit sizes of all children and all gaps, borders, and
padding.
Percentage based children: If children with percentage-based sizing request more than the available
space, the actual sizes are set to fit in the space, proportionate to the requested percentages.
190 CHAPTER 8
Grid General layout: The container is effectively a VBox control with rows of HBox child controls, where all items
are constrained to align with each other. The heights of all the cells in a single row are the same, but each row
can have a different height. The widths of all cells in a single column are the same, but each column can have
a different width. You can define a different number of cells for each row or each column of the Grid container,
and individual cells can span columns or rows.
Default sizing: The grid fits the individual rows and children at their default sizes.
Percentage-based children: If children use percentage-based sizing, the sizing rules fit the children Grid-
Item components within their rows, and GridRow components within the grid size according to linear
container sizing rules.
Tile General layout: The container is a grid of equal-sized cells. The cells can be in row-first or column-first
order.
If you do not specify explicit or percentage-based dimensions, the control has as close as possible to an equal
number of rows and columns, with the direction property determining the orientation with the larger
number of items, if necessary.
Default sizing: If you do not specify tileWidth and tileHeight properties, the container uses the
measured or explicit size of the largest child cell for the size of each child cell.
Percentage based children: The percentage-based sizes of a child component specify a percentage of the
individual cell, not of the Tile container.
Navigators: ViewStack, General layout: The container displays one child at a time.
Accordion, TabNavigator
Default sizing: The container size is determined by the measured or explicit dimensions of the initially
selected child, and thereafter, all children are forced to be that initial size. If you set the resizeToChild
property to true the container resizes to accommodate the measured or explicit size of each child, as that
child appears.
Percentage based children: As a general rule, you either use 100% for both height and width, which
causes the children to fill the navigator bounds, or do not use percentage-based sizing.
• Flex first determines all components’ measured (default) or explicitly set sizes up, from the innermost child
controls to the outermost (Application) control. This is done in the measurement pass.
• After the measurement pass, Flex determines all percentage-based sizes and lays out components down, from
the outermost container to the innermost controls. This is done in the layout pass.
• Sizes that you set to a pixel value are mandatory and fixed, and override any maximum or minimum size
specifications that you set for the component.
• The default sizes determined in the measurement pass specify the sizes of components that do not have
explicit or percentage-based sizes (or use constraint-based layout), and are fixed.
• Percentage-based size specifications are advisory. The layout algorithms satisfy the request if possible, and use
the percentage values to determine proportional sizes, but the actual sizes can be less than the requested sizes.
Percentage-based sizes are always within the component’s maximum and minimum sizes, and, subject to those
bounds, don’t cause a container’s children to exceed the container size.
Sizing components
Flex provides several ways for controlling the size of components. You can do the following tasks:
• SetFlex to automatically determine and use default component sizes.
• Specify pixel sizes.
• Specify component size as a percentage of the parent container.
• Combine layout and sizing by specifying a constraint-based layout.
For information on constraint-based layout, see “Using constraints to control component layout” on page 213.
Actual dimensions Returned by the height and The height and width of the displayed control, in pixels, as determined by
width properties. the layout phase.
If you set any explicit values, they determine the corresponding actual
values.
Explicit dimensions explicitHeight, A dimension that you specifically set as a number of pixels. These dimen-
explicitWidth sions cannot be overridden.
Setting the height and width Application developers typically use the height and width properties to
properties to integer values also set explicit dimensions.
sets the explicitHeight and
explicitWidth properties. You cannot have both an explicit dimension and a percentage-based
dimension; setting one unsets the other.
Percentage-based percentHeight, A dimension that you specifically set as a number in the range 0-100, as a
dimensions percentWidth percentage of the viewable area of the parent container.
In MXML tags only, setting the If you set a percentage-based dimension, the component is resizable, and
height and width properties to grows or shrinks if the parent dimension changes.
percentage string values, such as
“50%”, also sets the
percentHeight and
percentWidth properties.
Minimum dimen- minHeight, minWidth Setting The minimum dimensions a component can have.
sions the explicit minimum dimensions
also sets the minHeight and By default, Flex sets these dimensions to the values of the minimum default
minWidth properties. dimensions.
Maximum dimen- maxHeight, maxWidth Setting The maximum dimensions a component can have.
sions the explicit maximum dimensions
also sets the maxHeight and The default values of these properties are component-specific, but often are
maxWidth properties. 10000 pixels.
• If you set the height or width property to a percentage value in an MXML tag, you actually set the
percentage-based value, that is, the percentHeight or percentWidth property, not the explicit value. In Action-
Script, you cannot set the height or width property to a percentage value; instead, you must set the
percentHeight or percentWidth property.
• When you get the height and width properties, the value is always the actual height or width of the control.
Note: Setting a component’s includeInLayout property to false does not prevent Flex from laying out or
displaying the component; it only prevents Flex from considering the component when it lays out other components.
As a result, the next component or components in the display list overlap the component. To prevent Flex from
displaying the component, also set the visible property to false.
When Flex lays out the application, it sets the first and third button widths to the default values, 66, and the second
button size to the minimum width, 70. It ignores the percentage-based specifications when calculating the final
layout.
<?xml version="1.0"?>
<!-- components\HBoxSize.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HBox id="hb1">
<mx:Button id="b1"
label="Label 1"
width="50%"/>
<mx:Button id="b2"
label="Label 2"
width="40%"
minWidth="70"/>
<mx:Button id="b3"
label="Label 3"/>
</mx:HBox>
<mx:Form>
<mx:FormItem label="HBox:">
<mx:Label text="{hb1.width}"/>
</mx:FormItem>
<mx:FormItem label="Button #1:">
<mx:Label text="{b1.width}"/>
</mx:FormItem>
<mx:FormItem label="Button #2:">
<mx:Label text="{b2.width}"/>
</mx:FormItem>
<mx:FormItem label="Button #3">
<mx:Label text="{b3.width}"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
In the following example, the HBox width is now 276 pixels, 50% of 552 pixels, where 552 is the Application
container width of 600 minus 48 pixels for the 24-pixel left and right container padding. The button sizes are 106,
85, and 66 pixels, respectively. The third button uses the default size. The variable width button sizes are five-
ninths and four-ninths of the remaining available space after deducting the default-width button and the gaps, and
the 1-pixel-wide border.
If you set the HBox width property to 20%, however, the HBox width is not 120 pixels, 20% of the Application
container width, because this value is too small to fit the HBox container’s children. Instead it is 200, the sum of
66 pixels (the default size) for buttons 1 and 3, 50 pixels (the specified minimum size) for button 2, 16 pixels for
the gaps between buttons, and 2 pixels for the border. The buttons are 66, 50, and 66 pixels wide, respectively.
<?xml version="1.0"?>
<!-- components\HBoxSizePercent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600">
<mx:HBox id="hb1" width="50%" borderStyle="solid">
<mx:Button id="b1"
label="Label 1"
width="50%"/>
198 CHAPTER 8
<mx:Button id="b2"
label="Label 2"
width="40%"
minWidth="50"/>
<mx:Button id="b3"
label="Label 3"/>
</mx:HBox>
<mx:Form>
<mx:FormItem label="HBox:">
<mx:Label text="{hb1.width}"/>
</mx:FormItem>
<mx:FormItem label="Button #1:">
<mx:Label text="{b1.width}"/>
</mx:FormItem>
<mx:FormItem label="Button #2:">
<mx:Label text="{b2.width}"/>
</mx:FormItem>
<mx:FormItem label="Button #3">
<mx:Label text="{b3.width}"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
For more information and examples showing sizing of containers and children, see “Flex component sizing
techniques” on page 198. For detailed information on percentage-based sizing, see “Using percentage-based
sizing” on page 200.
Notice the empty space to the right of the third button, because the sum of the default sizes is less than the available
space.
<mx:HBox id="myHBox">
<mx:TextInput id="myInput"
text="This TextInput control is 200 by 40 pixels."
width="200"
height="40"/>
</mx:HBox>
</mx:Application>
In this example, Flex sets the component sizes to 200 by 40 pixels.
The following example shows setting the sizes of a container and its child:
<?xml version="1.0"?>
<!-- components\ExplicitHBoxSize.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HBox id="myHBox"
width="150"
height="150"
borderStyle="solid" paddingLeft="5" paddingTop="5" paddingRight="5"
>
<mx:TextInput id="myInput"
text="Enter the zip code"
width="200"
height="40"
/>
</mx:HBox>
</mx:Application>
200 CHAPTER 8
Because the specified TextInput control size is larger than that of its parent HBox container, Flex clips the
TextInput control at the container boundary and displays a scroll bar (if you do not disable it) so that you can scroll
the container to the clipped content. For more information on scroll bar sizing considerations, see “Dealing with
components that exceed their container size” on page 205.
4 If available space (parent container size minus all reserved space, including borders, padding, and gaps)
cannot accommodate the percentage requests, divides the available space in proportion to the specified
percentages.
5 If a minimum or maximum height or width specification conflicts with a calculated value, uses the minimum
or maximum value, and recalculates all other percentage-based components based on the reduced available space.
6 Rounds the size down to the next integer.
The following examples show how the requested percentage can differ from the size when the component is laid
out:
• Suppose that 50% of a HBox parent is available after reserving space for all explicit-sized and default-sized
components, and for all gaps and padding. If one component requests 20% of the parent, and another component
requests 60%, the first component is sized to 12.5% ((20 / 20+ 60) * 50%) of the parent container and the second
component is sized to 37.5% of the parent container.
• If any component, for example, a Tile container, requests 100% of its parent Application container’s space, it
occupies all of the container except for the Application’s 24-pixel-wide top, bottom, left, and right padding, unless
you explicitly change the padding settings of the Application container.
<mx:Canvas
202 CHAPTER 8
width="200" height="75"
borderStyle="solid">
<mx:HBox
x="20" y="10"
width="100%" height="25"
backgroundColor="#666666"/>
</mx:Canvas>
<mx:Canvas
width="200" height="75"
borderStyle="solid">
<mx:HBox
left="20" top="10"
width="100%" height="25"
backgroundColor="#666666"/>
</mx:Canvas>
</mx:Application>
Flex draws the following application:
<mx:HBox width="400">
<mx:Button label="Label 1" width="25%"/>
<mx:Button label="Label 2" width="40%"/>
<mx:Button label="Label 3"/>
</mx:HBox>
</mx:Application>
In this example, the default width of the third button is 66 pixels. The HBox container has no padding by default,
but it does put a 8-pixel horizontal gap between each component. Because this application has three components,
these gaps use 16 pixels, so the available space is 384. The first button requests 25% of the available space, or 96
pixels. The second button requests 40% of 384 pixels, rounded down to 153 pixels. There is still unused space to
the right of the third button.
ADOBE FLEX 3 203
Adobe Flex 3 Developer Guide
Now change the percentage values requested to 50% and 40%, respectively:
<?xml version="1.0"?>
<!-- components\PercentHBoxChildren5040.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HBox width="400">
<mx:Button label="Label 1"
width="50%"/>
<mx:Button label="Label 2"
width="40%"/>
<mx:Button label="Label 3"/>
</mx:HBox>
</mx:Application>
In this example, the first button requests 50% of the available HBox space, or 192 pixels. The second button still
requests 40%, or 153 pixels, for a total of 345 pixels. However, the HBox only has 318 pixels free after reserving 66
pixels for the default-width button and 16 pixels for the gaps between components. Flex divides the available space
proportionally between the two buttons, giving .5/(.5 + .4) * 318 = 176 pixels, to the first button and .4/(.5 + .4) *
318 = 141 pixels, to the second button. (All calculated values are rounded down to the nearest pixel.)
Flex draws the following application:
<mx:HBox width="400">
<mx:Button label="Label 1"
width="50%"/>
<mx:Button label="Label 2"
width="40%"
minWidth="150"/>
<mx:Button label="Label 3"/>
</mx:HBox>
</mx:Application>
204 CHAPTER 8
To determine the widths of the percentage-based button sizes, Flex first determines the sizes as described in the
second example in “Examples: Using percentage-based children of an HBox container” on page 202, which results
in requested values of 176 for the first button and 141 for the second button. However, the minimum width of the
second button is 150, so Flex sets its size to 150 pixels, and reduces the size of the first button to occupy the
remaining available space, which results in a width of 168 pixels.
Flex draws the following application:
<mx:HBox width="400">
<mx:Button label="Label 1"
width="50%"
minWidth="200"/>
<mx:Button label="Label 2"
width="40%"
minWidth="150"/>
<mx:Button label="Label 3"/>
</mx:HBox>
</mx:Application>
In this example, the default width of the fixed-size button is 66 pixels, so there are 324 pixels of space available for
the percentage-based buttons after accounting for the gap between components. The minimum widths of the first
and second buttons are greater than the percentage-based values, so Flex assigns those buttons the set widths of
200 and 150 pixels, even though the HBox container only has 324 pixels free. The HBox container uses scroll bars
to provide access to its contents because they now consume more space than the container itself.
Notice that the addition of the scroll bar doesn’t increase the height of the container from its initial value. Flex
considers scroll bars in its sizing calculations only if you explicitly set the scroll policy to ScrollPolicy.ON. So,
if you use an auto scroll policy (the default), the scroll bar overlaps the buttons. To prevent this behavior, you can
set the height property for the HBox container or allow the HBox container to resize by setting a percentage-
based width. Remember that changing the height of the HBox container causes other components in your appli-
cation to move and resize according to their own sizing rules. The following example adds an explicit height and
permits you to see the buttons and the scroll bar:
206 CHAPTER 8
<?xml version="1.0"?>
<!-- components\ScrollHBoxExplicitHeight.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
Alternatively, you can set the HBox control’s horizontalScrollPolicy property to ScrollPolicy.ON. This
reserves space for the scroll bar during the initial layout pass, so it fits without overlapping the buttons or setting
an explicit height. This also correctly handles the situation where the scroll bars change their size when you change
skinning or styles. This technique places an empty scroll bar area on the container if it does not need scrolling,
however.
<mx:HBox id="myHBox"
width="150"
height="150"
borderStyle="solid"
backgroundColor="#996666"
clipContent="false">
<mx:TextInput id="myInput"
width="200" height="40"
backgroundColor="#99FF99"/>
</mx:HBox>
</mx:Application>
ADOBE FLEX 3 207
Adobe Flex 3 Developer Guide
The following image shows the application, with the TextInput control extending past the right edge of the HBox
control:
To ensure that components fit in the container, reduce the sizes of the child components. You can do this by setting
explicit sizes that fit in the container, or by specifying percentage-based sizes. If you set percentage-based sizes,
Flex shrinks the children to fit the space, or their minimum sizes, whichever is larger. By default, Flex sets the
minimum height and width of most components to 0. You can set these components’ minimum properties to
nonzero values to ensure that they remain readable.
<mx:HBox
width="400"
borderStyle="solid"
paddingLeft="5"
paddingRight="5"
horizontalGap="5">
<mx:Button label="Label 1"
width="50%"/>
<mx:Button label="Label 2"
width="40%"
minWidth="150"/>
<mx:Button label="Label 3"/>
208 CHAPTER 8
</mx:HBox>
</mx:Application>
The default width of the fixed-size button is 66 pixels. All horizontal padding and gaps in the HBox control are 5
pixels wide, so the Flex application reserves 5 pixels for the left padding, 5 pixels for the right padding, and 10
pixels total for the two gaps between components, which leaves 314 pixels free for the two percentage-based
components. Flex reserves 66 pixels for the default-sized (third) button; the second button requires its minimum
size, 150 pixels; and the padding and gap take 20 pixels; this leaves 164 pixels available for the first button. The
first button requests 200 pixels; therefore, it uses all available pixels and is 164 pixels wide.
Flex draws the following application:
Automatic positioning
For most containers, Flex automatically positions the container children according to the container’s layout rules,
such as the layout direction, the container padding, and the gaps between children of that container.
For containers that use automatic positioning, setting the x or y property directly or calling move() has no effect,
or only a temporary effect, because the layout calculations set the x position to the calculation result, not the
specified value. You can, however, specify absolute positions for the children of these containers under some
circumstances; for more information, see “Disabling automatic positioning temporarily” on page 209.
You can control aspects of the layout by specifying container properties; for details on the properties, see the
property descriptions for the container in the Adobe Flex Language Reference. You also control the layout by
controlling component sizes and by using techniques such as adding spacers.
In the following example, you use a percentage-based Spacer control to push the Button control to the right so
that it is aligned with the right edge of the HBox container:
<?xml version="1.0"?>
<!-- components\SpacerHBox.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Embed(source="assets/flexlogo.jpg")]
[Bindable]
public var imgCls:Class;
]]>
</mx:Script>
<mx:HBox width="400">
<mx:Image source="{imgCls}"/>
<mx:Label text="Company XYZ"/>
<mx:Spacer width="100%"/>
<mx:Button label="Close"/>
</mx:HBox>
</mx:Application>
In this example, the Spacer control is the only percentage-based component in the HBox container. Flex sizes the
Spacer control to occupy all available space in the HBox container that is not required for other components. By
expanding the Spacer control, Flex pushes the Button control to the right edge of the container.
You can use all sizing and positioning properties with the Spacer control, such as width, height, maxWidth,
maxHeight, minWidth, and minHeight.
Even when you set the autoLayout property of a container to false, Flex updates the layout when you add or
remove a child. Application initialization, deferred instantiation, and the <mx:Repeater> tag add or remove
children, so layout updates always occur during these processes, regardless of the value of the autoLayout
property. Therefore, during container initialization, Flex defines the initial layout of the container children
regardless of the value of the autoLayout property.
The following example disables layout updates for a VBox container:
<?xml version="1.0"?>
<!-- components\DisableVBoxLayout.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox autoLayout="false"
width="200"
height="200"
>
<mx:Button id="b1"
label="Button 1"
/>
<mx:Button id="b2"
label="Button 2"
click="b2.x += 10;"
/>
<mx:Button id="b3"
label="Button 3"
creationComplete="b3.x = 100; b3.y = 75;"
/>
</mx:VBox>
</mx:Application>
In this example, Flex initially lays out all three Button controls according to the rules of the VBox container. The
creationComplete event listener for the third button is dispatched after the VBox control has laid out its children,
but before Flex displays the buttons. Therefore, when the third button appears, it is at the x and y positions
specified by the creationComplete listener. After the buttons appear, Flex shifts the second button 10 pixels to the
right each time a user clicks it.
Setting the autoLayout property of a container to false prohibits Flex from updating a container’s layout after
a child moves or resizes, so you should set it to false only when absolutely necessary. You should always test your
application with the autoLayout property set to the default value of true, and set it to false only as necessary
for the specific container and specific actions of the children in that container.
For more information on effects, see “Using Behaviors” on page 545.
ADOBE FLEX 3 211
Adobe Flex 3 Developer Guide
<mx:VBox>
<mx:Panel id="p1"
title="Panel 1"
backgroundColor="#FF0000"/>
<mx:Panel id="p2"
title="Panel 2"
backgroundColor="#00FF00"/>
<mx:Panel id="p3"
title="Panel 3"
backgroundColor="#0000FF"/>
</mx:VBox>
<mx:HBox>
<mx:Button label="Toggle Panel 2 Visible"
click="{p2.visible=!p2.visible;}"/>
<mx:Button label="Toggle Panel 2 in Layout"
click="{p2.includeInLayout=!p2.includeInLayout;}"/>
</mx:HBox>
</mx:Application>
Run this application and click the buttons to see the results of different combinations of visible and
includeInLayout properties. The example shows the following behaviors:
212 CHAPTER 8
• If you include the second Panel control in the layout and make it invisible, Flex reserves space for it; you see
the background of its VBox container in its place.
• If you do not include the second Panel control in the layout, the VBox resizes and the HBox with the buttons
moves up. If you then include it in the layout, the VBox resizes again, and the HBox and buttons move down.
• If you do not include the second Panel control in the layout and make it visible, Flex still draws it, but does
not consider it in laying out the third Panel control, so the two panels overlap. Because the title of a Panel control
has a default alpha of 0.5, you see the combination of the second and third Panel controls in the second Panel
position.
Absolute positioning
Three containers support absolute positioning:
• Application and Panel controls use absolute positioning if you specify the layout property as "absolute"
(ContainerLayout.ABSOLUTE).
• The Canvas container always uses absolute positioning.
With absolute positioning, you specify the child control position by using its x and y properties, or you specify a
constraint-based layout; otherwise, Flex places the child at position 0,0 of the parent container. When you specify
the x and y coordinates, Flex repositions the controls only when you change the property values. The following
example uses absolute positioning to place a VBox control inside a Canvas control:
<?xml version="1.0"?>
<!-- components\CanvasLayout.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundGradientColors="[#FFFFFF, #FFFFFF]">
<mx:Canvas
width="100" height="100"
backgroundColor="#999999">
<mx:VBox id="b1"
width="80" height="80"
x="20" y="20"
backgroundColor="#A9C0E7">
</mx:VBox>
</mx:Canvas>
</mx:Application>
This example produces the following image:
ADOBE FLEX 3 213
Adobe Flex 3 Developer Guide
When you use absolute positioning, you have full control over the locations of the container’s children. This lets
you overlap components. The following example adds a second VBox to the previous example so that it partially
overlaps the initial box.
<?xml version="1.0"?>
<!-- components\CanvasLayoutOverlap.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundGradientColors="[#FFFFFF, #FFFFFF]">
<mx:Canvas
width="100" height="100"
backgroundColor="#999999">
<mx:VBox id="b1"
width="80" height="80"
x="20" y="20"
backgroundColor="#A9C0E7">
</mx:VBox>
<mx:VBox id="b2"
width="50" height="50"
x="0" y="50"
backgroundColor="#FF0000">
</mx:VBox>
</mx:Canvas>
</mx:Application>
This example produces the following image:
Note: If you use percentage-based sizing for the children of a control that uses absolute positioning, the percentage-
based components resize when the parent container resizes, and the result may include unwanted overlapping of
controls.
Constraint rows and columns let you subdivide a container into vertical and horizontal constraint regions to
control the size and positioning of child components with respect to each other and within the parent container.
• A size determined by constraint-based layout overrides any explicit or percentage-based size specifications. If
you specify left and right constraints, for example, the resulting constraint-based width overrides any width
set by a width or percentWidth property.
<!-- Anchor the top of the form at the top of the canvas.
Anchor the form sides 20 pixels from the canvas sides. -->
<mx:Form id="myForm"
backgroundColor="#DDDDDD"
216 CHAPTER 8
top="0"
left="20"
right="20">
<mx:FormItem label="Date">
<mx:DateField/>
</mx:FormItem>
<mx:FormItem width="100%"
direction="horizontal"
label="Hours:">
<mx:TextInput width="75"/>
<mx:Label text="Minutes" width="48"/>
<mx:TextInput width="75"/>
</mx:FormItem>
</mx:Form>
<!-- Anchor the box with the buttons 20 pixels from the canvas
right edge and 10 pixels from the bottom. -->
<mx:HBox id="okCancelBox"
right="20"
bottom="10">
<mx:Button label="OK"/>
<mx:Button label="Cancel"/>
</mx:HBox>
</mx:Canvas>
</mx:Application>
The following example shows a Canvas container partitioned into two vertical regions and two horizontal regions.
The first constraint column occupies 212 pixels from the leftmost edge of the Canvas. The second constraint
column occupies 100% of the remaining Canvas width. The rows in this example occupy 80% and 20% of the
Canvas container’s height from top to bottom, respectively.
<?xml version="1.0"?>
<!-- constraints\BasicRowColumn.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Canvas>
<mx:constraintColumns>
<mx:ConstraintColumn id="col1" width="212"/>
<mx:ConstraintColumn id="col2" width="100%"/>
</mx:constraintColumns>
<mx:constraintRows>
<mx:ConstraintRow id="row1" height="80%"/>
<mx:ConstraintRow id="row2" height="20%"/>
</mx:constraintRows>
</mx:Canvas>
</mx:Application>
Constraint rows and columns do not have to occupy 100% of the available area in a container. The following
example shows a single constraint column that occupies 20% of the Canvas width; 80% of the container is unallo-
cated:
<?xml version="1.0"?>
<!-- constraints\BasicColumn_20Percent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Canvas>
<mx:constraintColumns>
<mx:ConstraintColumn id="col1" width="20%"/>
</mx:constraintColumns>
</mx:Canvas>
</mx:Application>
• Fixed size means the space allocated to the constraint region is a fixed pixel size. In the following example, you
set the fixed with of a ConstraintColumn instance to 100 pixels:
<mx:ConstraintColumn id="col1" width="100"/>
As the parent container grows or shrinks, the ConstraintColumn instance remains 100 pixels wide.
• Percent size means that the space allocated to the constraint row or column is calculated as a percentage of the
space remaining in the parent container after the space allocated to fixed and content size child objects has been
deducted from the available space.
In the following example, you set the with of a ConstraintColumn instance to 80%:
<mx:ConstraintColumn id="col1" width="80%"/>
As the parent container grows or shrinks, the ConstraintColumn always takes up 80% of the available width.
A best practice in specifying percent constraints is to ensure that the sum of all percent constraints is less than
or equal to 100%. However, if the total value of percent specifications is greater than 100%, the actual allocated
percentages are calculated so that the proportional values for all constraints total 100%. For example, if the
percentages for two constraint objects are specified as 100% and 50%, the values are adjusted to 66.6% and
33.3% (two-thirds for the first value and one-third for the second).
• Content size (default) means that the space allocated to the region is dictated by the size of the child objects in
that space. As the size of the content changes, so does the size of the region. Content sizing is the default when you
do not specify either fixed or percentage sizing parameters.
In the following example, you specify content size by omitting any explicit width setting:
<mx:ConstraintColumn id="col1"/>
The width of this ConstraintColumn is determined by the width of its largest child. When children span
multiple content sized constraint rows or constraint columns, Flex divides the space consumed by the children
among the rows and columns.
For the ConstraintColumn class, you can also use the maxWidth and minWidth properties to limit the width of
the column. For the ConstraintRow class, you can use the maxHeight and minHeight properties to limit the
height of the row. Minimum and maximum sizes for constraint columns and rows limit how much the constraint
regions grow or shrink when you resize their parent containers. If the parent container with a constraint region
shrinks to less than the minimum size for that region when you resize the container, scrollbars appear to show
clipped content.
Note: Minimum and maximum limits are only applicable to percentage and content sized constraint regions. For
fixed size constraint regions, minimum and maximum values, if specified, are ignored.
ADOBE FLEX 3 219
Adobe Flex 3 Developer Guide
<mx:constraintColumns>
<mx:ConstraintColumn id="col1" width="100"/>
<mx:ConstraintColumn id="col2" width="100"/>
</mx:constraintColumns>
<mx:constraintRows>
<mx:ConstraintRow id="row1" height="100"/>
<mx:ConstraintRow id="row2" height="100"/>
</mx:constraintRows>
<mx:constraintColumns>
<mx:ConstraintColumn id="col1" width="30%"/>
220 CHAPTER 8
Chapter 9: Controls
Controls are user-interface components such as Button, TextArea, and ComboBox controls. Adobe® Flex® has two
types of controls: basic and data provider. For information on data provider controls, see “Using Data-Driven
Controls” on page 373.
Topics
About controls. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Working with controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Button control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
PopUpButton control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
ButtonBar and ToggleButtonBar controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
LinkBar control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
TabBar control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
CheckBox control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
RadioButton control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
NumericStepper control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
DateChooser and DateField controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
LinkButton control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
HSlider and VSlider controls. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
SWFLoader control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Image control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
VideoDisplay control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
ColorPicker control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
Alert control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
ProgressBar control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
HRule and VRule controls. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
ScrollBar control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
224 CHAPTER 9
About controls
Controls are user-interface components, such as Button, TextArea, and ComboBox controls. You place controls in
containers, which are user-interface components that provide a hierarchical structure for controls and other
containers. Typically, you define a container, and then insert controls or other containers in it.
At the root of a Flex application is the <mx:Application> tag, which represents a base container that covers the
entire Adobe® Flash® Player or Adobe AIR™ drawing surface. You can place controls or containers directly under
the <mx:Application> tag or in other containers. For more information on containers, see “Introducing
Containers” on page 419.
Most controls have the following characteristics:
• MXML API for declaring the control and the values of its properties and events
• ActionScript API for calling the control’s methods and setting its properties at run time
• Customizable appearance by using styles, skins, and fonts
ADOBE FLEX 3 225
Adobe Flex 3 Developer Guide
The MXML and ActionScript APIs let you create and configure a control. The following MXML code example
creates a TextInput control in a Form container:
<?xml version="1.0"?>
<!-- controls\TextInputInForm.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
Although you commonly use MXML as the language for building Flex applications, you can also use ActionScript
to configure controls. For example, the following code example populates a DataGrid control by providing an
Array of items as the value of the DataGrid control’s dataProvider property:
<?xml version="1.0"?>
<!-- controls\DataGridConfigAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
<mx:DataGrid id="myGrid"
width="350" height="150"
color="#7B0974"
creationComplete="myGrid_initialize();"/>
</mx:Application>
This example produces the following image:
ADOBE FLEX 3 227
Adobe Flex 3 Developer Guide
Text controls
Several Flex components display text or take text input, as the following table shows:
RichTextEditor Compound control that contains a multiline text field and controls that let you format text by selecting such char-
acteristics as font, size, weight, and alignment
These controls can display plain text that all has the same appearance. The controls can also display rich text
formatted by using a subset of the standard HTML formatting tags. For information on using text controls, see
“Using Text Controls” on page 315.
Menu controls
Several Flex controls create or interact with menus, as the following table shows:
Control Description
For information on menu controls, see “Using Menu-Based Controls” on page 347.
Flex controls
The following table lists all the controls available with Flex:
Button Displays a variable-size button that can include a “Button control” on page 233
label, an icon image, or both.
ButtonBar Displays a row of related buttons with a common “ButtonBar and ToggleButtonBar controls” on page 240
appearance.
CheckBox Shows whether a particular Boolean value is true “CheckBox control” on page 248
(checked) or false (unchecked).
ComboBox Displays a drop-down list attached to a text field that “ComboBox control” on page 388
contains a set of values.
ColorPicker Displays a selectable drop-down color swatch panel “DateChooser and DateField controls” on page 255
(palette).
DateChooser Displays a full month of days to let you select a date. “DateChooser and DateField controls” on page 255
DateField Displays the date with a calendar icon on its right “DateChooser and DateField controls” on page 255
side. When a user clicks anywhere inside the control,
a DateChooser control pops up and displays a
month of dates.
HRule/VRule Displays a single horizontal rule (HRule) or vertical “HRule and VRule controls” on page 309
rule (VRule).
HSlider/VSlider Lets users select a value by moving a slider thumb “HSlider and VSlider controls” on page 267
between the end points of the slider track.
Image Imports GIF, JPEG, PNG, SVG, and SWF files. “Image control” on page 278
Label Displays a noneditable single-line field label. “LinkButton control” on page 265
LinkBar Displays a horizontal row of LinkButton controls that “LinkBar control” on page 243
designate a series of link destinations.
Menu Displays a pop-up menu of individually selectable “Menu control events” on page 354
choices, much like the File or Edit menu of most soft-
ware applications.
MenuBar Displays a horizontal menu bar that contains one or “MenuBar control” on page 365
more submenus of Menu controls.
NumericStepper Displays a dual button control that you can use to “NumericStepper control” on page 253
increase or decrease the value of the underlying vari-
able.
ProgressBar Provides visual feedback of how much time remains “ProgressBar control” on page 306
in the current operation.
RadioButton Displays a set of buttons of which exactly one is “RadioButton control” on page 249
selected at any time.
RadioButton Group Displays a group of RadioButton controls with a “Creating a group by using the <mx:RadioButtonGroup>
single click event listener. tag” on page 251
RichTextEditor Includes a multiline editable text field and controls “RichTextEditor control” on page 340
for specifying text formatting.
ScrollBar Displays horizontal and vertical scroll bars. “ScrollBar control” on page 312
(HScrollBar and
VScrollBar)
SWFLoader Displays the contents of a specified SWF file or JPEG “SWFLoader control” on page 274
file.
Text Displays a noneditable multiline text field. “TextInput control” on page 336
TextArea Displays an editable text field for user input that can “Using Text Controls” on page 315
accept more than a single line of input.
TextInput Displays an editable text field for a single line of user “TextInput control” on page 336
input. Can contain alphanumeric data, but input is
interpreted as a String data type.
TileList Displays a tiled list of items. The items are tiled in “TileList control” on page 385
vertical columns or horizontal rows.
ToggleButtonBar Displays a row of related buttons with a common “ButtonBar and ToggleButtonBar controls” on page 240
appearance.
Tree Displays hierarchical data arranged as an expand- “Tree control” on page 405
able tree.
VideoDisplay Incorporates streaming media into Flex applications. “VideoDisplay control” on page 287
Sprite
UIComponent
Controls
ADOBE FLEX 3 231
Adobe Flex 3 Developer Guide
The Sprite and UIComponent classes are the base classes for all Flex components. Subclasses of the UIComponent
class can have shape, draw themselves, and be invisible. Each subclass can participate in tabbing, accept low-level
events like keyboard and mouse input, and be disabled so that it does not receive mouse and keyboard input.
For information on the interfaces inherited by controls from the Sprite and UIComponent classes, see “Using Flex
Visual Components” on page 113.
Sizing controls
All controls define rules for determining their size in a Flex application. For example, a Button control sizes itself
to fit its label text and optional icon image, while an Image control sizes itself to the size of the imported image.
Each control has a default height and a default width. The default size of each standard control is specified in the
description of each control.
The default size of a control is not necessarily a fixed value. For example, for a Button control, the default size is
large enough to fit its label text and optional icon image. At run time, Flex calculates the default size of each control
and, by default, does not resize a control from its default size.
Set the height and width attributes in MXML to percentages, such as 50%, or the percentHeight and
percentWidth properties in ActionScript to percentage values, such as 50, to allow Flex to resize the control in
the corresponding direction. Flex attempts to fit the control to the percentage of its parent container that you
specify. If there isn’t enough space available, the percentages are scaled, while retaining their relative values.
For example, you can set the width of a comments box to scale with its parent container as the parent container
changes size:
<mx:TextInput id="comments" width="100%" height ="20"/>
You can also specify explicit sizes for a control. In MXML or ActionScript by setting the its height and width
properties to numeric pixel values. The following example sets the height and width of the addr2 TextInput
control to 20 pixels and 100 pixels, respectively:
<mx:TextInput id="addr2" width="100" height ="20"/>
To resize a control at run time, use ActionScript to set its width and height properties. For example, the click
event listener for the following Button control sets the width property of the addr2 TextInput control to increase
its width by 10 pixels:
<mx:Button id="button1" label="Slide" height="20"
click="addr2.width+=10;"/>
Note: The preceding technique works even if the width property was originally set as a percentage value. The stored
values of the width and height properties are always in pixels.
232 CHAPTER 9
Many components have arbitrarily large maximum sizes, which means that Flex can make them as large as
necessary to fit the requirements of your application. While some components have a defined nonzero minimum
size, most have a minimum size of 0. You can use the maxHeight, maxWidth , minHeight, and minWidth
properties to set explicit size ranges for each component.
For more information on sizing components, see “Sizing and Positioning Components” on page 185.
Positioning controls
You place controls inside containers. Most containers have predefined layout rules that automatically determine
the position of their children. The Canvas container absolutely positions its children, and the Application and
Panel containers optionally let you use absolute or container-relative positioning.
To absolutely position a control, you set its x and y properties to specific horizontal and vertical pixel coordinates
within the container. These coordinates are relative to the upper-left corner of the container, where the upper-left
corner is at coordinates (0,0). Values for x and y can be positive or negative integers. You can use negative values
to place a control outside of the visible area of the container, and then use ActionScript to move the child to the
visible area, possibly as a response to an event.
The following example places the TextInput control 150 pixels to the right and 150 pixels down from the upper-
left corner of a Canvas container:
<mx:TextInput id="addr2" width="100" height ="20" x="150" y="150"/>
To reposition a control within an absolutely-positioned container at run time, you set its x and y properties. For
example, the click event listener for the following Button control moves the TextInput control down 10 pixels
from its current position:
<mx:Button id="button1" label="Slide" height="20" x="0" y="250"click="addr2.y =
addr2.y+10;"/>
For detailed information about control positioning, including container-relative positioning, see “Sizing and
Positioning Components” on page 185.
A theme defines the look and feel of a Flex application. A theme can define something as simple as the color
scheme or common font for an application, or it can be a complete reskinning of all the Flex components. The
current theme for your application defines the styles that you can set on the controls within it. That means some
style properties might not always be settable. For more information, see “Using Styles and Themes” on page 589.
Button control
The Button control is a commonly used rectangular button. Button controls look like they can be pressed, and
have a text label, an icon, or both on their face. You can optionally specify graphic skins for each of several Button
states.
You can create a normal Button control or a toggle Button control. A normal Button control stays in its pressed
state for as long as the mouse button is down after you select it. A toggle Button controls stays in the pressed state
until you select it a second time.
Buttons typically use event listeners to perform an action when the user selects the control. When a user clicks the
mouse on a Button control, and the Button control is enabled, it dispatches a click event and a buttonDown
event. A button always dispatches events such as the mouseMove, mouseOver, mouseOut, rollOver, rollOut,
mouseDown, and mouseUp events whether enabled or disabled.
The following example shows a Button control:
You can use customized graphic skins to customize your buttons to match your application’s look and function-
ality. You can give the Button control different image skins for the up, down, and disabled states, and the skins for
these states can differ depending on whether the button is selected or not selected. The control can change the
image skins dynamically.
The following example shows seven Button controls to control video recording and playback arranged in an HBox
layout container. All buttons are in their up state:
234 CHAPTER 9
<mx:Button
label="Icon Button"
icon="@Embed(source='assets/logo.jpg')"
height="36"
/>
</mx:Application>
The icon is in the assets subdirectory of the directory containing the application file. This results in a button with
the icon displayed to the left of the label text:
If a Button control is disabled, it displays its disabled appearance, regardless of user interaction. In the disabled
state, all mouse or keyboard interaction is ignored.
textRollOverColor="0xAAAA55"
textSelectedColor="0xFFFF00"
upSkin="@Embed(source='assets/buttonUp.gif')"
overSkin="@Embed(source='assets/buttonOver.gif')"
downSkin="@Embed(source='assets/buttonDown.gif')"
disabledSkin="@Embed(source='assets/buttonDisabled.gif')"
icon="@Embed(source='assets/logo.gif')"/>
</mx:Application>
PopUpButton control
The PopUpButton control consists of two horizontal buttons: a main button, and a smaller button called the pop-
up button, which only has an icon. The main button is a Button control.
The pop-up button, when clicked, opens a second control called the pop-up control. Clicking anywhere outside
the PopUpButton control, or in the pop-up control, closes the pop-up control
The PopUpButton control adds a flexible pop-up control interface to a Button control. One common use for the
PopUpButton control is to have the pop-up button open a List control or a Menu control that changes the function
and label of the main button, as the following example shows by using a Menu control:
In this example, the user can choose whether the button puts mail in the Inbox, the Sent Items folder, or the Trash
folder, by selecting from the pop-up menu that appears when the user clicks the small pop-up button to the right
of the main button. The text on the main button indicates the action it performs, and the text changes each time
the user selects a different item from the menu.
The PopUpButton control is not limited to displaying menus; it can display any Flex control as the pop-up control.
A workflow application that lets users send a document for review, for example, could use a Tree control as a visual
indication of departmental structure. The PopUpButton control’s pop-up button would display the tree, from
which the user could pick the message recipients.
238 CHAPTER 9
The control that pops up does not have to affect the main button’s appearance or action; it can have an
independent action instead. You could create an undo PopUpButton control, for example, where the main button
undoes only the last action, and the pop-up control is a List control that lets users undo multiple actions by
selecting them.
The PopUpButton control is a subclass of the Button control and inherits all of its properties, styles, events, and
methods, with the exception of the toggle property and the styles used for a selected button.
The control has the following characteristics:
• The popUp property specifies the pop-up control (for example, List or Menu).
• The open() and close() methods lets you open and close the pop-up control programmatically, rather than
by using the pop-up button.
• The open and close events are dispatched when the pop-up control opens and closes.
• You use the popUpSkin and arrowButtonWidth style properties to define the PopUpButton control’s
appearance.
For detailed descriptions, see PopUpButton in Adobe Flex Language Reference.
// Define the event listener for the Menu control's change event.
private function changeHandler(event:MenuEvent):void {
var label:String = event.label;
popTypeB.text=String("Moved to " + label);
popB.label = "Put in: " + label;
popB.close();
}
]]>
</mx:Script>
<mx:VBox>
<mx:Label text="Main button mimics the last selected menuItem."/>
<mx:PopUpButton id="popB"
label="Edit"
width="135"
creationComplete="initMenu();"/>
<mx:Spacer height="50"/>
<mx:TextInput id="popTypeB"/>
</mx:VBox>
</mx:Application>
User interaction
You navigate the PopUpButton control in the following ways:
• Moving the mouse over any part of the PopUpButton control highlights the button border and the main
button or the pop-up button.
• Clicking the button dispatches the click event.
• Clicking the pop-up button pops up the pop-up control and dispatches an open event.
• Clicking anywhere outside the PopUpButton control, or in the pop-up control, closes the pop-up control and
dispatches a close event.
The following keystrokes let users navigate the PopUpButton control:
Key Use
Control+Down Arrow Opens the pop-up control and initiates an open event. The pop-up control’s keyboard handling takes
effect.
Control+Up Arrow Closes the pop-up control and initiates a close event.
240 CHAPTER 9
Note: You cannot use the Tab key to leave an opened pop-up control; you must make a selection or close the control
with the Control+Up Arrow key combination.
The following image shows an example of a ToggleButtonBar control that defines a set of buttons, where the
Dreamweaver button is the currently selected button in the control:
<mx:String>ColdFusion</mx:String>
</mx:dataProvider>
</mx:ButtonBar>
</mx:Application>
This example creates a row of four Button controls, as shown in the image in “ButtonBar and ToggleButtonBar
controls” on page 240.
To create a ToggleButtonBar control, replace the <mx:ButtonBar> tag with the <mx:ToggleButtonBar> tag. For
the ToggleButtonBar control, the selectedIndex property determines which button is selected when the control
is created. The default value for selectedIndex is 0 and selects the leftmost button in the bar. Setting the
selectedIndex property to -1 deselects all buttons in the bar. Otherwise, the syntax is the same for both controls.
The dataProvider property specifies the labels of the four buttons. You can also populate the dataProvider
property with an Array of Objects, where each object can have up to three fields: label, icon, and toolTip.
In the following example, an Array of Objects specifies a label and icon for each button:
<?xml version="1.0"?>
<!-- controls\bar\BBarLogo.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
The ToggleButtonBar control in the following example defines an event listener, named clickHandler(), for the
itemClick event.
<?xml version="1.0"?>
<!-- controls\bar\BBarEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
import mx.events.ItemClickEvent;
<mx:ToggleButtonBar
borderStyle="solid"
horizontalGap="5"
itemClick="clickHandler(event);"
toggleOnClick="true"
selectedIndex="-1">
<mx:dataProvider>
<mx:String>Flash</mx:String>
<mx:String>Director</mx:String>
<mx:String>Dreamweaver</mx:String>
<mx:String>ColdFusion</mx:String>
</mx:dataProvider>
</mx:ToggleButtonBar>
LinkBar control
A LinkBar control defines a horizontal or vertical row of LinkButton controls that designate a series of link desti-
nations. You typically use a LinkBar control to control the active child container of a ViewStack container, or to
create a standalone set of links.
The following shows an example of a LinkBar control that defines a set of links:
<mx:LinkBar borderStyle="solid"
itemClick="navigateToURL(new URLRequest('http://www.adobe.com/' +
String(event.label).toLowerCase()), '_blank');">
<mx:dataProvider>
<mx:String>Flash</mx:String>
<mx:String>Director</mx:String>
<mx:String>Dreamweaver</mx:String>
<mx:String>ColdFusion</mx:String>
</mx:dataProvider>
</mx:LinkBar>
</mx:Application>
In this example, you use the <mx:dataProvider> and <mx:Array> tags to define the label text. The event object
passed to the itemClick handler contains the label selected by the user. The handler for the itemClick event
constructs an HTTP request to the Adobe website based on the label, and opens that page in a new browser
window.
You can also bind data to the <mx:dataProvider> tag to populate the LinkBar control, as the following example
shows:
<?xml version="1.0"?>
<!-- controls\bar\LBarBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
244 CHAPTER 9
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var linkData:ArrayCollection = new ArrayCollection([
"Flash", "Director", "Dreamweaver", "ColdFusion"
]);
]]>
</mx:Script>
<mx:LinkBar
horizontalAlign="right"
borderStyle="solid"
itemClick="navigateToURL(new URLRequest('http://www.adobe.com/' +
String(event.label).toLowerCase()), '_blank');">
<mx:dataProvider>
{linkData}
</mx:dataProvider>
</mx:LinkBar>
</mx:Application>
In this example, you define the data for the LinkBar control as a variable in ActionScript, and then you bind that
variable to the <mx:dataProvider> tag. You could also bind to the <mx:dataProvider> tag from a Flex data
model, from a web service response, or from any other type of data model.
A LinkBar control creates LinkButton controls based on the value of its dataProvider property. Even though
LinkBar is a subclass of Container, do not use methods such as Container.addChild() and
Container.removeChild() to add or remove LinkButton controls. Instead, use methods such as addItem()
and removeItem() to manipulate the dataProvider property. A LinkBar control automatically adds or removes
the necessary children based on changes to the dataProvider property.
TabBar control
A TabBar control defines a horizontal or vertical row of tabs. The following shows an example of a TabBar control:
As with the LinkBar control, you can use a TabBar control to control the active child container of a ViewStack
container. The syntax for using a TabBar control to control the active child of a ViewStack container is the same
as for a LinkBar control. For an example, see “ViewStack navigator container” on page 529.
While a TabBar control is similar to a TabNavigator container, it does not have any children. For example, you use
the tabs of a TabNavigator container to select its visible child container. You can use a TabBar control to set the
visible contents of a single container to make that container’s children visible or invisible based on the selected tab.
ADOBE FLEX 3 245
Adobe Flex 3 Developer Guide
<mx:TabBar>
<mx:dataProvider>
<mx:String>Alabama</mx:String>
<mx:String>Alaska</mx:String>
<mx:String>Arkansas</mx:String>
</mx:dataProvider>
</mx:TabBar>
</mx:Application>
The <mx:String> tags define the text for each tab in the TabBar control.
You can also use the <mx:Object> tag to define the entries as an array of objects, where each object contains a
label property and an associated data value, as the following example shows:
<?xml version="1.0"?>
<!-- controls\bar\TBarObject.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:TabBar>
<mx:dataProvider>
<mx:Object label="Alabama" data="Montgomery"/>
<mx:Object label="Alaska" data="Juneau"/>
<mx:Object label="Arkansas" data="Little Rock"/>
</mx:dataProvider>
</mx:TabBar>
</mx:Application>
The label property contains the state name and the data property contains the name of its capital. The data
property lets you associate a data value with the text label. For example, the label text could be the name of a
color, and the associated data value could be the numeric representation of that color.
By default, Flex uses the value of the label property to define the tab text. If the object does not contain a label
property, you can use the labelField property of the TabBar control to specify the property name containing the
tab text, as the following example shows:
<?xml version="1.0"?>
<!-- controls\bar\TBarLabel.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:TabBar labelField="state">
246 CHAPTER 9
<mx:dataProvider>
<mx:Object state="Alabama" data="Montgomery"/>
<mx:Object state="Alaska" data="Juneau"/>
<mx:Object state="Arkansas" data="Little Rock"/>
</mx:dataProvider>
</mx:TabBar>
</mx:Application>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var STATE_ARRAY:ArrayCollection = new ArrayCollection([
{label:"Alabama", data:"Montgomery"},
{label:"Alaska", data:"Juneau"},
{label:"Arkansas", data:"LittleRock"}
]);
]]>
</mx:Script>
<mx:TabBar >
<mx:dataProvider>
{STATE_ARRAY}
</mx:dataProvider>
</mx:TabBar>
</mx:Application>
You can also bind a Flex data model to the dataProvider property. For more information on using data models,
see “Storing Data” on page 1257.
ADOBE FLEX 3 247
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.events.ItemClickEvent;
import mx.controls.TabBar;
import mx.collections.ArrayCollection;
[Bindable]
private var STATE_ARRAY:ArrayCollection = new ArrayCollection([
{label:"Alabama", data:"Montgomery"},
{label:"Alaska", data:"Juneau"},
{label:"Arkansas", data:"LittleRock"}
]);
CheckBox control
The CheckBox control is a commonly used graphical control that can contain a check mark or be unchecked
(empty). You can use CheckBox controls wherever you need to gather a set of true or false values that aren’t
mutually exclusive.
You can add a text label to a CheckBox control and place it to the left, right, top, or bottom. Flex clips the label of
a CheckBox control to fit the boundaries of the control.
The following image shows a checked CheckBox control:
For the code used to generate this example, see “Creating a CheckBox control” on page 248.
When a user clicks a CheckBox control or its associated text, the CheckBox control changes its state from checked
to unchecked, or from unchecked to checked.
A CheckBox control can have one of two disabled states, checked or unchecked. By default, a disabled CheckBox
control displays a different background and check mark color than an enabled CheckBox control.
RadioButton control
The RadioButton control is a single choice in a set of mutually exclusive choices. A RadioButton group is
composed of two or more RadioButton controls with the same group name. Only one member of the group can
be selected at any given time. Selecting an unselected group member deselects the currently selected RadioButton
control in the group.
For the code used to generate this example, see “Creating a RadioButton control” on page 249.
<mx:RadioButton groupName="cardtype"
id="americanExpress"
label="American Express"
width="150"/>
<mx:RadioButton groupName="cardtype"
id="masterCard"
label="MasterCard"
width="150"/>
<mx:RadioButton groupName="cardtype"
id="visa"
label="Visa"
width="150"/>
</mx:Application>
This code results in the application shown in “About the RadioButton control” on page 249.
For each RadioButton control in the group, you can optionally define an event listener for the button’s click
event. When a user selects a RadioButton control, Flex calls the event listener associated with the button for the
click event, as the following code example shows:
<?xml version="1.0"?>
<!-- controls\button\RBEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import flash.events.Event;
<mx:RadioButton groupName="cardtype"
id="americanExpress"
label="American Express"
width="150"
click="handleAmEx(event);"/>
<mx:RadioButton groupName="cardtype"
id="masterCard"
label="MasterCard"
width="150"
click="handleMC(event);"/>
ADOBE FLEX 3 251
Adobe Flex 3 Developer Guide
<mx:RadioButton groupName="cardtype"
id="visa"
label="Visa"
width="150"
click="handleVisa(event);"/>
<mx:TextArea id="myTA"/>
</mx:Application>
Key Action
Control+Arrow keys Move focus among the buttons without selecting a button.
<mx:Script>
<![CDATA[
import mx.events.ItemClickEvent;
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.ItemClickEvent;
label="MasterCard"
width="150"/>
<mx:RadioButton groupName="cardtype"
id="visa"
value="Visa"
label="Visa"
width="150"/>
</mx:Application>
This code results in the following output when you select the American Express button:
In the itemClick event listener, the selectedValue property of the RadioButtonGroup control in the event
object is set to the value of the value property of the selected RadioButton control. If you omit the value property,
Flex sets the selectedValue property to the value of the label property.
You can still define a click event listener for the individual buttons, even though you also define one for the
group.
NumericStepper control
You can use the NumericStepper control to select a number from an ordered set. The NumericStepper control
consists of a single-line input text field and a pair of arrow buttons for stepping through the valid values; you can
also use the Up Arrow and Down Arrow keys to cycle through the values.
The following example shows a NumericStepper control:
For the code used to create this image, see “Creating a NumericStepper control” on page 254.
254 CHAPTER 9
If the user clicks the up arrow, the value displayed is increased by one unit of change. If the user holds down the
arrow, the value increases or decreases until the user releases the mouse button. When the user clicks the arrow,
it is highlighted to provide feedback to the user.
Users can also type a legal value directly into the text field. Although editable ComboBox controls provide similar
functionality, NumericStepper controls are sometimes preferred because they do not require a drop-down list that
can obscure important data.
NumericStepper control arrows always appear to the right of the text field.
</mx:Application>
User interaction
If the user clicks the up or down arrow button, the value displayed is increased by one unit of change. If the user
presses either of the arrow buttons for more than 200 milliseconds, the value in the input field increases or
decreases, based on step size, until the user releases the mouse button or the maximum or minimum value is
reached.
ADOBE FLEX 3 255
Adobe Flex 3 Developer Guide
Keyboard navigation
The NumericStepper control has the following keyboard navigation features:
Key Description
Left Arrow Moves the insertion point to the left within the NumericStepper control’s text field.
Right Arrow Moves the insertion point to the right within the Numeric Stepper control’s text field.
In order to use the keyboard to navigate through the stepper, it must have focus.
Changing the displayed month does not change the selected date. Therefore, the currently selected date might not
always be visible. The DateChooser control resizes as necessary to accommodate the width of the weekday
headings. Therefore, if you use day names, instead of letters, as headings, the calendar will be wide enough to show
the full day names.
You can use the DateField control anywhere you want a user to select a date. For example, you can use a DateField
control in a hotel reservation system, with certain dates selectable and others disabled. You can also use the
DateField control in an application that displays current events, such as performances or meetings, when a user
selects a date.
<mx:Script>
<![CDATA[
import mx.events.CalendarLayoutChangeEvent;
wholeDate.text= (eventObj.currentTarget.selectedDate.getMonth() + 1) +
"/" + (eventObj.currentTarget.selectedDate.getDate() +
"/" + eventObj.currentTarget.selectedDate.getFullYear());
}
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="Day of week">
<mx:TextInput id="day" width="100"/>
</mx:FormItem>
<mx:FormItem label="Day of month">
<mx:TextInput id="date" width="100"/>
</mx:FormItem>
258 CHAPTER 9
<mx:FormItem label="Month">
<mx:TextInput id="month" width="100"/>
</mx:FormItem>
<mx:FormItem label="Year">
<mx:TextInput id="year" width="100"/>
</mx:FormItem>
<mx:FormItem label="Date">
<mx:TextInput id="wholeDate" width="100"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
Notice that the first line of the event listener determines if the selectedDate property is null. This check is
necessary because selecting the currently selected date while holding down the Control key deselects it, sets the
selectedDate property to null, then dispatches the change event.
Note: The code that determines the value of the wholeDate field adds 1 to the month number because the
DateChooser control uses a zero-based month system, where January is month 0 and December is month 11.
</mx:Script>
<mx:Style>
.myHeaderStyle{
color:#6666CC;
font-family:Times New Roman, Times, serif;
font-size:16px; font-weight:bold;}
.myTodayStyle{
color:#CC6633;
font-family:Times New Roman, Times, serif;
font-size:12px; font-weight:bold;}
.myDayStyle{
color:#006600;
font-family:Courier New, Courier, mono;
font-size:15px; font-style:italic; font-weight:bold;}
</mx:Style>
<mx:DateChooser
headerStyleName="myHeaderStyle"
todayStyleName="myTodayStyle"
todayColor="#CCCCCC"
weekDayStyleName="myDayStyle"/>
</mx:Application>
260 CHAPTER 9
Property Description
disabledDays An array of days of the week that the user cannot select. Often used to disable weekend days.
disabledRange An array of dates that the user cannot select. The array can contain individual Date objects, objects specifying date
ranges, or both.
selectableRange A single range of dates that the user can select. The user can navigate only among the months that include this
range; in these months any dates outside the range are disabled. Use the disabledRange property to disable
dates within the selectable range.
The following example shows a DateChooser control that has the following characteristics:
• The selectableRange property limits users to selecting dates in the range January 1 - March 15, 2006. Users
can only navigate among the months of January through March 2006.
• The disabledRanges property prevents users from selecting January 11 or any day in the range January 23 -
February 10.
• The disabledDays property prevents users from selecting Saturdays or Sundays.
<?xml version="1.0"?>
<!-- controls\date\DateChooserSelectable.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:DateChooser
selectableRange="{{rangeStart: new Date(2006,0,1),
rangeEnd: new Date(2006,2,15)}}"
disabledRanges="{[new Date(2006,0,11),
{rangeStart: new Date(2006,0,23), rangeEnd: new Date(2006,1,10)}]}"
disabledDays="{[0,6]}"/>
</mx:Application>
<mx:disabledDays>
<mx:Number>0</mx:Number>
<mx:Number>6</mx:Number>
</mx:disabledDays>
</mx:DateField>
<mx:Script>
<![CDATA[
import mx.events.DateChooserEvent;
<mx:DateChooser id="myDC"
width="200"
creationComplete="dateChooser_init();"
scroll="onScroll();"/>
</mx:Application>
To set the selectableRange property, the code creates two Date objects that represent the first date and last date
of the range. Users can only select dates within the specified range. This example also changes the fontStyle of
the DateChooser control to italics after the first time the user scrolls it.
You can select multiple dates in a DateChooser control by using the selectedRanges property. This property
contains an Array of objects. Each object in the Array contains two dates: a start date and an end date. By setting
the dates within each object to the same date, you can select any number of individual dates in the DateChooser.
The following example uses an XML object to define the date for the DateChooser control. It then iterates over
the XML object and creates a new object for each date. These objects are then used to determine what dates to
select in the DateChooser:
262 CHAPTER 9
</mx:Application>
In the following example, you select a value for the formatString property from the drop-down list:
<?xml version="1.0"?>
<!-- controls\date\DateFieldFormat.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:HBox>
<mx:ComboBox id="cb1">
<mx:ArrayCollection>
<mx:String>MM/DD/YY</mx:String>
<mx:String>MM/DD/YYYY</mx:String>
<mx:String>DD/MM/YY</mx:String>
<mx:String>DD/MM/YYYY</mx:String>
<mx:String>DD MM, YYYY</mx:String>
</mx:ArrayCollection>
</mx:ComboBox>
<mx:DateField id="date2"
editable="true"
width="100"
formatString="{cb1.selectedItem}"
/>
</mx:HBox>
</mx:Application>
The DateField control also lets you specify a formatter function that converts the date to a string in your preferred
format for display in the control’s text field. The DateField labelFunction property and the DateFormatter class
help you format dates.
By default, the date in the DateField control text field is formatted in the form "MM/DD/YYYY". You use the
labelFunction property of the DateField control to specify a function to format the date displayed in the text
field, and return a String containing the date. The function has the following signature:
public function formatDate(currentDate:Date):String {
...
return dateString;
}
You can choose a different name for the function, but it must take a single argument of type Date and return the
date as a String for display in the text field. The following example defines the function formatDate() to display
the date in the form yyyy/mm/dd, such as 2005/11/24. This function uses a DateFormatter object to do the
formatting:
<?xml version="1.0"?>
<!-- controls\date\DateChooserFormatter.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function formatDate(date:Date):String {
return dfconv.format(date);
}
]]>
</mx:Script>
User interaction
The date chooser includes arrow buttons that let users move between months. Users can select a date with the
mouse by clicking the desired date.
Clicking a forward month arrow advances a month; clicking the back arrow displays the previous month. Clicking
forward a month on December, or back on January, moves to the next (or previous) year. Clicking a date selects
it. By default, the selected date is indicated by a green background around the date and the current day is indicated
by a black background with the date in white. Clicking the currently selected date deselects it.
The following keystrokes let users navigate DateChooser and DateField controls:
Key Use
Left Arrow Moves the selected date to the previous enabled day in the month. Does not move to the previous month.
Right Arrow Moves the selected date to the next enabled day in the month. Does not move to the next month.
Up Arrow Moves the selected date up the current day of week column to the previous enabled day. Does not move
to the previous month.
Down Arrow Moves the selected date down the current day of week column to next enabled day. Does not move to the
next month.
Key Use
Home Moves the selection to the first enabled day of the month.
End Moves the selection to the last enabled day of the month.
Enter DateField only: selects the date and closes the DateChooser control.
Note: The user must select the control before using navigation keystrokes. In a DateField control, all listed keystrokes
work only when the date chooser is displayed.
LinkButton control
The LinkButton control creates a single-line hypertext link that supports an optional icon. You can use a
LinkButton control to open a URL in a web browser.
The following example shows three LinkButton controls:
<?xml version="1.0"?>
<!-- controls\button\LBURL.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:LinkButton label="ADBE"
width="100"
click="navigateToURL(new URLRequest('http://quote.yahoo.com/q?s=ADBE'),
'quote')"/>
</mx:Application>
This example uses the navigateToURL() method to open the URL.
The LinkButton control automatically provides visual cues when you move your mouse pointer over or click the
control. The previous code example contains no link handling logic but does change color when you move your
mouse pointer over or click a link.
The following code example contains LinkButton controls for navigating in a ViewStack navigator container:
<?xml version="1.0"?>
<!-- controls\button\LBViewStack.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox>
<!-- Put the links in an HBox container across the top. -->
<mx:HBox>
<mx:LinkButton label="Link1"
click="viewStack.selectedIndex=0;"/>
<mx:LinkButton label="Link2"
click="viewStack.selectedIndex=1;"/>
<mx:LinkButton label="Link3"
click="viewStack.selectedIndex=2;"/>
</mx:HBox>
A. HSlider control B. HSlider control with data tip C. Label D. Tick mark E. Track F. Thumb G. VSlider control
This example includes the data tip, slider thumb, track, tick marks, and labels. You can optionally show or hide
data tips, tick marks, and labels.
The following code example reproduces this image (without annotations):
<?xml version="1.0"?>
<!-- controls\slider\HSliderSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HBox>
<mx:VBox>
<mx:HSlider
tickInterval="2"
labels="['min', 'max']" height="150"/>
<mx:HSlider/>
</mx:VBox>
<mx:VSlider
tickInterval="2"
labels="['min', 'max']"/>
ADOBE FLEX 3 269
Adobe Flex 3 Developer Guide
</mx:HBox>
</mx:Application>
<mx:VBox>
<mx:HSlider
maximum="100"/>
<mx:HSlider
maximum="100"
snapInterval="5"/>
<mx:HSlider
maximum="100"
snapInterval="5"
tickInterval="25"/>
<mx:HSlider
maximum="100"
snapInterval="5"
tickInterval="25"
labels="[0,25,50,75,100]"/>
</mx:VBox>
</mx:Application>
270 CHAPTER 9
<mx:HBox>
<mx:VSlider
maximum="100"/>
<mx:VSlider
maximum="100"
snapInterval="5"/>
<mx:VSlider
maximum="100"
snapInterval="5"
tickInterval="25"/>
<mx:VSlider
maximum="100"
snapInterval="5"
tickInterval="25"
labels="[0,25,50,75,100]"/>
</mx:HBox>
</mx:Application>
This code results in the following application:
ADOBE FLEX 3 271
Adobe Flex 3 Developer Guide
You can bind the value property of a slider to another control to display the current value of the slider. The
following example binds the value property to a Text control:
<?xml version="1.0"?>
<!-- controls\slider\HSliderBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
Event Description
change Dispatches when the user moves the thumb. If the liveDragging property is true, the event is dispatched contin-
uously as the user moves the thumb. If liveDragging is false, the event is dispatched when the user releases the
slider thumb.
thumbPress Dispatches when the user selects a thumb by using the mouse pointer.
thumbRelease Dispatches when the user releases the mouse pointer after a thumbPress event occurs.
The following code example uses a change event to show the current value of the slider in a TextArea control
when the user releases the slider thumb:
<?xml version="1.0"?>
<!-- controls\slider\HSliderEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.SliderEvent;
import mx.controls.sliderClasses.Slider;
private function sliderChange(event:SliderEvent):void {
var currentSlider:Slider=Slider(event.currentTarget);
thumb.text=String(currentSlider.value);
272 CHAPTER 9
}
]]>
</mx:Script>
<mx:HSlider change="sliderChange(event);"/>
<mx:TextArea id="thumb"/>
</mx:Application>
By default, the liveDragging property of the slider control is set to false, which means that the control
dispatches the change event when the user releases the slider thumb. If you set liveDragging to true, the
control dispatches the change event continuously as the user moves the thumb, as the following example shows:
<?xml version="1.0"?>
<!-- controls\slider\HSliderEventLiveDrag.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.SliderEvent;
import mx.controls.sliderClasses.Slider;
<mx:HSlider
liveDragging="true"
change="sliderChangeLive(event);"/>
<mx:TextArea id="thumbLive"/>
</mx:Application>
var ct:Slider=Slider(event.currentTarget);
thumbTwoA.text=String(ct.values[0]);
thumbTwoB.text=String(ct.values[1]);
thumbIndex.text=String(event.thumbIndex);
}
]]>
</mx:Script>
<mx:HSlider thumbCount="2"
change="sliderChangeTwo(event);"/>
<mx:TextArea id="thumbTwoA"/>
<mx:TextArea id="thumbTwoB"/>
<mx:TextArea id="thumbIndex"/>
</mx:Application>
This example also uses the thumbIndex property of the event object. This property has a value of 0 if the user
modified the position of the first thumb, and a value of 1 if the user modified the position of the second thumb.
<mx:Script>
<![CDATA[
private function myDataTipFunc(val:String):String {
return "Current value: " + String(val);
}
]]>
</mx:Script>
<mx:HSlider
height="80"
dataTipFormatFunction="myDataTipFunc"/>
</mx:Application>
This code produces the following image:
274 CHAPTER 9
In this example, the data tip function prepends the data tip text with the String "Current value:". You can modify
this example to insert a dollar sign ($) prefix on the data tip for a slider that controls the price of an item.
Keyboard navigation
The HSlider and VSlider controls have the following keyboard navigation features when the slider control has
focus:
Key Description
Left Arrow Decrement the value of an HSlider control by 1 snap interval or, if you do not specify a snap interval, by 1 pixel.
Right Arrow Increment the value of a HSlider control by 1 snap interval or, if you do not specify a snap interval, by 1 pixel.
Up Arrow Increment the value of an VSlider control by 1 snap interval or, if you do not specify a snap interval, by 1 pixel.
Down Arrow Decrement the value of a VSlider control by 1 snap interval or, if you do not specify a snap interval, by 1 pixel.
Page Down Moves the thumb of a VSlider control to its minimum value.
SWFLoader control
The SWFLoader control lets you load one Flex application into another Flex application as a SWF file. It has
properties that let you scale its contents. It can also resize itself to fit the size of its contents. By default, content is
scaled to fit the size of the SWFLoader control. The SWFLoader control can also load content on demand
programmatically, and monitor the progress of a load operation.
The SWFLoader control also lets you load the contents of a GIF, JPEG, PNG, SVG, or SWF file into your appli-
cation, where the SWF file does not contain a Flex application, or a ByteArray representing a SWF, GIF, JPEG, or
PNG.
Note: For more information on the Image control, see “Image control” on page 278. For more information on using
the SWFLoader control to load a Flex application, see “Externalizing application classes” on page 277.
Note: Flex also includes the Image control for loading GIF, JPEG, PNG, SVG, or SWF files. You typically use the Image
control for loading static graphic files and SWF files, and use the SWFLoader control for loading Flex applications as
SWF files. The Image control is also designed to be used in custom cell renderers and item editors.
ADOBE FLEX 3 275
Adobe Flex 3 Developer Guide
A SWFLoader control cannot receive focus. However, content loaded into the SWFLoader control can accept
focus and have its own focus interactions.
<mx:Script>
<![CDATA[
[Bindable]
public var varOne:String = "This is a public variable.";
276 CHAPTER 9
</mx:Application>
You compile this example into the file FlexApp.SWF, and then use the SWFLoader control to load it into another
Flex application, as the following example shows:
<?xml version="1.0"?>
<!-- controls\swfloader\SWFLoaderInteract.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.managers.SystemManager;
import mx.controls.Label;
[Bindable]
public var loadedSM:SystemManager;
<mx:Label id="lbl"/>
<mx:SWFLoader id="myLoader" width="300"
source="FlexApp.swf"
ADOBE FLEX 3 277
Adobe Flex 3 Developer Guide
creationComplete="initNestedAppProps();"/>
Note: If you externalize the loaded application’s dependencies by using the load-externs option, your loaded appli-
cation might not be compatible with future versions of Adobe Flex. Therefore, you might be required to recompile the
application. To ensure that a future Flex application can load you application, compile that module with all the classes
it requires.
For more information, see “Using the Flex Compilers” on page 125 in Building and Deploying Adobe Flex 3 Appli-
cations.
Image control
Adobe Flex supports several image formats, including GIF, JPEG, PNG, SVG, and SWF files. You can import these
images into your applications by using the Image control.
Note: Flex also includes the SWFLoader control for loading Flex applications. You typically use the Image control for
loading static graphic files and SWF files, and use the SWFLoader control for loading Flex applications. The Image
control is also designed to be used in custom item renderers and item editors. For more information on the
SWFLoader control, see “SWFLoader control” on page 274.
The alternative to embedding a resource is to load the resource at run time. You can load a resource from the local
file system in which the SWF file runs, or you can access a remote resource, typically though an HTTP request
over a network. These images are independent of your Flex application, so you can change them without causing
a recompile operation as long as the names of the modified images remain the same. The referenced images add
no additional overhead to an application’s initial loading time. However, you might experience a delay when you
use the images and load them into Adobe Flash Player or AIR.
A SWF file can access one type of external resource only, either local or over a network; it cannot access both types.
You determine the type of access allowed by the SWF file by using the use-network flag when you compile your
application. When use-network flag is set to false, you can access resources in the local filesystem, but not over
the network. The default value is true, which allows you to access resources over the network, but not in the local
filesystem.
For more information on the use-network flag, see “Using the Flex Compilers” on page 125 in Building and
Deploying Adobe Flex 3 Applications.
When you load images at run time, you should be aware of the security restrictions of Flash Player or AIR. For
example, you can reference an image by using a URL, but the default security settings only permit Flex applica-
tions to access resources stored on the same domain as your application. To access images on other servers, you
must use a crossdomain.xml file.
For more information on application security, see “Applying Flex Security” on page 29 in Building and Deploying
Adobe Flex 3 Applications.
• Sizing an image
• Positioning the image in a Canvas container
• Setting visibility
The following example stores all images in an assets subdirectory of the application directory:
<?xml version="1.0"?>
<!-- controls\image\ImageSimpleAssetsDir.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Image id="image1"
source="http://localhost:8100/flex/assets/logo.jpg"/>
</mx:Application>
Note: You can use relative URLs for images hosted on the same web server as the Flex application, but you must load
these images over the Internet rather than access them locally.
Sizing an image
Flex sets the height and width of an imported image to the height and width settings in the image file. By default,
Flex does not resize the image.
282 CHAPTER 9
To set an explicit height or width for an imported image, set its height and width properties of the Image control.
Setting the height or width property prevents the parent from resizing it. The scaleContent property has a
default value of true; therefore, Flex scales the image as it resizes it to fit the specified height and width. The aspect
ratio is maintained by default, so the image may not completely fill the designated space. Set the scaleContent
property to false to disable scaling. Set the maintainAspectRatio property to false to allow an image to fill
all available space regardless of its dimensions. For more information about image aspect ratios, see “Maintaining
aspect ratio when sizing” on page 282.
To let Flex resize the image as part of laying out your application, set the height and width properties to a
percentage value. Flex attempts to resize components with percentage values for these properties to the specified
percentage of their parent container. You can also use the maxHeight and maxWidth and minHeight and
minWidth properties to limit resizing. For more information on resizing, see “Introducing Containers” on
page 419.
One common use for resizing an image is to create image thumbnails. In the following example, the image has an
original height and width of 100 by 100 pixels. By specifying a height and width of 20 by 20 pixels, you create a
thumbnail of the image.
<?xml version="1.0"?>
<!-- controls\image\ImageSimpleThumbnail.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Image id="image1"
source="@Embed(source='logo.jpg')"
width="20" height="20"/>
<mx:Image id="image2"
source="@Embed(source='logo.jpg')"/>
</mx:Application>
In this example, you do not specify a square area for the resized image. Flex maintains the aspect ratio of an image
by default; therefore, Flex sizes the image to 150 by 150 pixels, the largest possible image that maintains the aspect
ratio and conforms to the size constraints. The other 50 by 150 pixels remain empty. However, the <mx:Image>
tag reserves the empty pixels and makes them unavailable to other controls and layout elements.
You can use a Resize effect to change the width and height of an image in response to a trigger. As part of config-
uring the Resize effect, you specify a new height and width for the image. Flex maintains the aspect ratio of the
image by default, so it resizes the image as much as possible to conform to the new size, while maintaining the
aspect ratio. For example, place your mouse pointer over the image in this example to enlarge it, and then move
the mouse off the image to shrink it to its original size:
<?xml version="1.0"?>
<!-- controls\image\ImageResize.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Resize id="resizeBig"
widthFrom="22" widthTo="44"
heightFrom="27" heightTo="54"
/>
<mx:Resize id="resizeSmall"
widthFrom="44" widthTo="22"
heightFrom="54" heightTo="27"
/>
For more information on the Resize effect, see “Using Behaviors” on page 545.
If you do not want to preserve the aspect ratio when you resize an image, you can set the maintainAspectRatio
property to false. By default, maintainAspectRatio is set to true to enable the preservation of the aspect ratio.
The following example resizes the Flex logo to the exact values of the height and width properties without regard
for its aspect ratio:
<?xml version="1.0"?>
<!-- controls\image\ImageResizeMaintainAR.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Image id="image1"
source="@Embed('logo.jpg')"
width="250" height="100"
maintainAspectRatio="false"/>
</mx:Application>
284 CHAPTER 9
By choosing not to maintain the aspect ratio, you allow for the possibility of a distorted image. For example, the
Adobe logo is 136 by 47 pixels by default. In the following example, it is distorted because the aspect ratio is not
maintained when the image is resized:
<mx:Canvas id="canvas0"
borderStyle="solid"
width="200"
height="200">
<mx:Image id="img0"
source="@Embed('logo.jpg')"
x="40" y="40"/>
</mx:Canvas>
</mx:Application>
Setting visibility
The visible property of the Image control lets you load an image but render it invisible. By default, the image is
visible. To make an image invisible, set the visible property to false. The following example loads an image but
does not make it visible:
<?xml version="1.0"?>
<!-- controls\image\ImageVisible.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox id="vbox0" borderStyle="solid">
<mx:Image id="img0"
visible="{cb1.selected}"
source="@Embed(source='logo.jpg')"
/>
ADOBE FLEX 3 285
Adobe Flex 3 Developer Guide
</mx:VBox>
<mx:CheckBox id="cb1" label="Visible"/>
</mx:Application>
The VBox container still allocates space for the image when it lays out its children. Thus, the VBox is the same
size as the image file and, if your application contained a Button control after the <mx:Image> tag, the button
would appear in the same location as if the image were visible.
If you want to make the image invisible, and have its parent container ignore the image when sizing and
positioning its other children, set the includeInLayout property of the Image control to false. By default, the
includeInLayout property is true, so that even when the image is invisible, the container sizes and positions it
as if it were visible.
Often, you use the visible property to mark all images invisible, except one image. For example, assume that you
have an area of your application dedicated to showing one of three possible images based on some user action.
You set the visible property set to true for only one of the possible images; you set the visible property set
to false for all other images, which makes them invisible.
You can use ActionScript to set image properties. In the following example, when the user clicks the button, the
action sets the visible property of the image to true to make it appear:
<?xml version="1.0"?>
<!-- controls\image\ImageAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function toggleImage():void {
if (image1.visible)
image1.visible=false
else
image1.visible=true;
}
]]>
</mx:Script>
<mx:VBox id="vbox0">
<mx:Image id="image1"
visible="false"
source="@Embed(source='logo.jpg')"/>
<mx:Button id="myButton"
label="Toggle Image" click="toggleImage();"/>
</mx:VBox>
</mx:Application>
If you set the visible property, you can control when images are loaded. By allocating space but making images
invisible when a page loads, you ensure that any slower performance occurs during the initialization stage when
users expect it, rather than as they interact with the application and perform actions that require the image. By
setting the visible property, you can also prevent resizing and relayout within your application at seemingly
random intervals.
286 CHAPTER 9
<mx:Script>
<![CDATA[
private var imageSmall:String = "logo.jpg";
private var imageLarge:String = "logowithtext.jpg";
<mx:VBox id="vbox0">
<mx:Button id="myButton"
label="Toggle Image"
click="toggleImage();"
/>
<mx:Image id="image1"/>
ADOBE FLEX 3 287
Adobe Flex 3 Developer Guide
</mx:VBox>
</mx:Application>
Notice in this example that the application accesses the images in the local file system; they are not embedded or
accessed by URL. Therefore, you have to compile this application with the use-network flag set to false.
The container that holds the image does not adjust the layout of its children when you call the load() method.
Therefore, you typically replace one image with another image of the same size. If the new image is significantly
larger than the original, it can overlay other components in the container.
You can make the selection of the replacement image based on a user action in your application. For example, you
might want to load an image based on a user selection in a list box or data grid.
In the next example, you use the index number of the selected item in a data grid to determine the image to load.
In this example, images are named 1.jpg, 2.jpg, 3.jpg, and so on, corresponding to items in the grid.
// Retrieve the image associated with the item selected in the grid
private function getImage():void {
var cartGrid:DataGrid = dgrid;
var imageSource:String = 'images/' + cartGrid.getSelectedIndex() + '.jpg';
image1.load(imageSource);
}
In this example, the images are stored in the images directory. The complete path to an image is the directory
name, the index number, and the file suffix .jpg.
You register this function as the event listener for a change event in the data grid, as follows:
<mx:DataGrid id="dgrid" height="200" width="350" change="getImage();"/>
When a user changes the currently selected item in the data grid, Flex calls the getImage() function to update
the displayed image.
You could modify this example to use information about the selected item to determine the image to load, rather
than by using the selected item’s index. For example, the grid could contain a list of objects, where each object has
a property that contains the image name associated with it.
In addition to the load() method, you can also access other properties of the SWFLoader control, including
percentLoaded. The percentLoaded property is particularly useful because it lets you to display a progress bar
so users know that the application did not become unresponsive. For a complete list of the SWFLoader properties
and methods, see the Adobe Flex Language Reference.
VideoDisplay control
Flex supports the VideoDisplay control to incorporate streaming media into Flex applications. Flex supports the
Flash Video File (FLV) file format with this control.
288 CHAPTER 9
If you omit both width and height properties for the control, Flex makes the control the size of the playing
media. If you specify only one property, and the maintainAspectRatio property is false, the size of the playing
media determines the value of the other property. If the maintainAspectRatio property is true, the media
retains its aspect ratio when resizing.
The following example creates a VideoDisplay control:
<?xml version="1.0"?>
<!-- controls\videodisplay\VideoDisplaySimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox>
<mx:VideoDisplay
source="../assets/MyVideo.flv"
height="250"
width="250"
/>
</mx:VBox>
</mx:Application>
By default, Flex sizes the VideoDisplay control to the size of the media. If you specify the width or height
property of the control, and either is smaller than the media’s dimensions, Flex does not change the size of the
component. Instead, Flex sizes the media to fit within the component. If the control’s playback area is smaller than
the default size of the media, Flex shrinks the media to fit inside the control.
<mx:VBox>
<mx:VideoDisplay id="myVid"
source="../assets/MyVideo.flv"
cuePointManagerClass="mx.controls.videoClasses.CuePointManager"
cuePoint="cpHandler(event);"
height="250"
width="250"
>
<mx:cuePoints>
<mx:Object name="first" time="5"/>
<mx:Object name="second" time="10"/>
</mx:cuePoints>
</mx:VideoDisplay>
<mx:Label text="{myVid.playheadTime}"/>
<mx:TextArea id="cp" height="100" width="250"/>
</mx:VBox>
<mx:HBox>
<mx:Button label="||" click="myVid.pause();"/>
<mx:Button label=">" click="myVid.play();"/>
</mx:HBox>
</mx:Application>
In this example, the event listener writes a String to the TextArea control when the control reaches a cue point.
The String contains the name and time of the cue point.
ADOBE FLEX 3 291
Adobe Flex 3 Developer Guide
[Bindable]
private var myCuePoints:Array = [
{ name: "first", time: 5},
{ name: "second", time: 10}
];
<mx:VBox>
<mx:VideoDisplay id="myVid"
cuePointManagerClass="mx.controls.videoClasses.CuePointManager"
source="../assets/MyVideo.flv"
cuePoint="cpHandler(event);"
height="250"
width="250"
/>
<mx:Label text="{myVid.playheadTime}"/>
<mx:TextArea id="cp" height="100" width="250"/>
</mx:VBox>
<mx:HBox>
<mx:Button label=">" click="cp.text='';initCP();myVid.play();"/>
</mx:HBox>
</mx:Application>
292 CHAPTER 9
<mx:Script>
<![CDATA[
<mx:VideoDisplay id="myVid"
width="320" height="240"
creationComplete="initCamera();"/>
</mx:Application>
In this example, you create a Camera object in the event handler for the creationComplete event of the Video-
Display control, then pass the Camera object as the argument to the attachCamera() method.
<mx:HBox>
<mx:Label text="RTMP FMS 2.0"/>
<mx:VideoDisplay
autoBandWidthDetection="false"
source="rtmp://localhost/videodisplay/bike.flv"/>
</mx:HBox>
</mx:Application>
In this example, you place the bike.flv file in the directory Flash Media Server 2\applications\video-
display\streams\_definst_.
ADOBE FLEX 3 293
Adobe Flex 3 Developer Guide
Notice that you explicitly set the autoBandWidthDetection property to false, its default value. When the
autoBandWidthDetection property is true, you must create the server-side file main.asc in the directory Flash
Media Server 2\applications\videodisplay\scripts, which implements the following functions:
application.onConnect = function(p_client, p_autoSenseBW) {}
application.calculateClientBw = function(p_client) {}
Client.prototype.getStreamLength = function(p_streamName) {}
The following example shows an implementation of main.asc:
application.onConnect = function(p_client, p_autoSenseBW) {
//Add security code here.
this.acceptConnection(p_client);
if (p_autoSenseBW)
this.calculateClientBw(p_client);
else
p_client.call("onBWDone");
}
Client.prototype.getStreamLength = function(p_streamName) {
return Stream.length(p_streamName);
}
application.calculateClientBw = function(p_client) {
// Add code to set the clients BandWidth.
// Use p_client.getStats() which returns bytes_in
// and bytes_Out and check your bandWidth using
// p_client.call("onBWCheck", result, p_client.payload).
p_client.call("onBWDone");
}
For more information on main.asc, see the Flash Media Server 2 documentation.
ColorPicker control
The ColorPicker control lets users select a color from a drop-down swatch panel (palette). It initially appears as a
preview sample with the selected color. When a user selects the control, a color swatch panel appears. The panel
includes a sample of the selected color and a color swatch panel. By default, the swatch panel displays the web-safe
colors (216 colors, where each of the three primary colors has a value that is a multiple of 33, such as #CC0066).
For complete reference information, see ColorPicker in the Adobe Flex Language Reference.
Flex populates the color swatch panel and the text box from a data provider. By default, the control uses a data
provider that includes all the web-safe colors. If you use your own data provider you can specify the following:
The colors to display You must specify the colors if you use your own dataProvider.
ADOBE FLEX 3 295
Adobe Flex 3 Developer Guide
Labels to display in the text box for the colors If you do not specify text labels, Flex uses the hexadecimal color
values.
Additional information for each color This information can include any information that is of use to your appli-
cation, such as IDs or descriptive comments.
The following image shows an expanded ColorPicker control that uses a custom data provider that includes color
label values. It also uses styles to set the sizes of the display elements:
Note: You can also specify the data for the ColorPicker control by using a <mx:dataProvider> child tag; for an
example, see “Using custom field names” on page 298.
You typically use events to handle user interaction with a ColorPicker control. The following example adds an
event listener for a change event and an open event to the previous example ColorPicker control:
<?xml version="1.0"?>
<!-- controls\colorpicker\CPEvents.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
//Import the event classes.
import mx.events.DropdownEvent;
import mx.events.ColorPickerEvent;
[Bindable]
public var simpleDP:Array = ['0x000000', '0xFF0000', '0xFF8800',
'0xFFFF00', '0x88FF00', '0x00FF00', '0x00FF88', '0x00FFFF',
'0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF', '0xFFFFFF'];
The index of items in the ColorPicker control is zero-based, which means that values are 0, 1, 2, ... , n - 1, where
n is the total number of items; therefore, the target.selectedIndex value is zero-based, and a value of 2 in the
preceding example refers to the data provider entry with color 0xFF8800.
<mx:Script>
<![CDATA[
import mx.events.ColorPickerEvent;
import mx.events.DropdownEvent;
[Bindable]
public var complexDPArray:Array = [
{label:"Yellow", color:"0xFFFF00",
descript:"A bright, light color."},
{label:"Hot Pink", color:"0xFF66CC",
descript:"It's HOT!"},
{label:"Brick Red", color:"0x990000",
descript:"Goes well with warm colors."},
{label:"Navy Blue", color:"0x000066",
descript:"The conservative favorite."},
{label:"Forest Green", color:"0x006600",
descript:"Great outdoorsy look."},
{label:"Grey", color:"0x666666",
descript:"An old reliable."}]
<mx:Style>
.myStyle {
swatchWidth:25;
swatchHeight:25;
textFieldWidth:95;
}
</mx:Style>
<mx:VBox>
<mx:TextArea id="descriptBox"
width="150" height="50"/>
<mx:ColorPicker id="cp"
height="50" width="150"
dataProvider="{complexDP}"
change="changeEvt(event);"
open="openEvt(event);"
editable="false"/>
</mx:VBox>
</mx:Application>
In this example, the selectedItem property contains a reference to the object defining the selected item. The
example uses selectedItem.label to access the object’s label property (the color name), and
selectedItem.descript to access the object’s descript property (the color description). Every change event
updates the TextArea control with the label property of the selected item and the item’s description. The open
event clears the current text in the TextArea control each time the user opens up the ColorPicker to display the
swatch panel.
This example also uses several of the ColorPicker properties and styles to specify the control’s behavior and
appearance. The editable property prevents users from entering a value in the color label box (so they can only
select the colors from the dataProvider). The swatchWidth and swatchHeight styles control the size of the color
samples in the swatch panel, and the textFieldWidth style ensures that the text field is long enough to accom-
modate the longest color name.
<mx:Script>
ADOBE FLEX 3 299
Adobe Flex 3 Developer Guide
<![CDATA[
import mx.events.ColorPickerEvent;
import mx.events.DropdownEvent;
<mx:Style>
.myStyle {
swatchWidth:25;
swatchHeight:25;
textFieldWidth:95;
}
</mx:Style>
<mx:VBox>
<mx:TextArea id="descriptBox"
width="150" height="50"/>
<mx:ColorPicker id="cp"
height="50" width="150"
labelField="cName"
colorField="cVal"
change="changeEvt(event)"
open="openEvt(event)"
swatchPanelStyleName="myStyle"
editable="false">
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<mx:Object cName="Yellow" cVal="0xFFFF00"
cDescript="A bright, light color."/>
<mx:Object cName="Hot Pink" cVal="0xFF66CC"
cDescript="It's HOT!"/>
<mx:Object cName="Brick Red" cVal="0x990000"
cDescript="Goes well with warm colors."/>
<mx:Object cName="Navy Blue" cVal="0x000066"
cDescript="The conservative favorite."/>
<mx:Object cName="Forest Green" cVal="0x006600"
cDescript="Great outdoorsy look."/>
<mx:Object cName="Grey" cVal="0x666666"
cDescript="An old reliable."/>
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:ColorPicker>
</mx:VBox>
</mx:Application>
300 CHAPTER 9
User interaction
A ColorPicker control can be editable or noneditable. In a noneditable ColorPicker control, the user must select
a color from among the swatch panel options. In an editable ColorPicker control, a user can select swatch panel
items or enter a hexadecimal color value directly into the label text field at the top of the swatch panel. Users can
type numbers and uppercase or lowercase letters in the ranges a-f and A-F in the text box; it ignores all other non-
numeric characters.
Mouse interaction
You can use the mouse to navigate and select from the control:
• Click the collapsed control to display or hide the swatch panel.
• Click any swatch in the swatch panel to select it and close the panel.
• Click outside the panel area to close the panel without making a selection.
• Click in the text field to move the text entry cursor.
Keyboard interaction
If the ColorPicker is editable, and the swatch panel has the focus, alphabetic keys in the range A-F and a-f, numeric
keys, and the Backspace and Delete keys enter and remove text in the color text box. You can also use the following
keystrokes to control the ColorPicker:
Key Description
Control+Down Arrow Opens the swatch panel and puts the focus on the selected swatch.
Home Moves the selection to the first color in a row of the swatch panel. Has no effect if there is a single column.
End Moves the selection to the last color in a row of the swatch panel. Has no effect if there is a single column.
Page Up Moves the selection to the top color in a column of the swatch panel. Has no effect if there is a single row.
Page Down Moves the selection to the bottom color in a column of the swatch panel. Has no effect if there is a single
row.
ADOBE FLEX 3 301
Adobe Flex 3 Developer Guide
Key Description
Escape Closes the swatch panel without changing the color in the color picker.
Enter Selects the current color from the swatch panel and closes the swatch panel; equivalent to clicking a color
swatch. If the focus is on the text field of an editable ColorPicker, selects the color specified by the field text.
Arrows When the swatch panel is open, moves the focus to the next color left, right, up, and down in the swatch
grid. On a single-row swatch panel, Up and Right Arrow keys are equivalent, and Down and Left Arrow keys
are equivalent.
On a multirow swatch panel, the selection wraps to the beginning or end of the next or previous line. On a
single-row swatch panel, pressing the key past the beginning or end of the row loops around on the row.
When the swatch panel is closed, but has the focus, the Up and Down Arrow keys have no effect. The Left
and Right Arrow keys change the color picker selection, moving through the colors as if the panel were
open.
Note: When the swatch panel is open, you cannot use the Tab and Shift+Tab keys to move the focus to another object.
Alert control
All Flex components can call the static show() method of the Alert class to open a pop-up modal dialog box with
a message and an optional title, buttons, and icons. The following example shows an Alert control pop-up dialog
box:
The Alert control closes when you select a button in the control, or press the Escape key.
The Alert.show() method has the following syntax:
public static show(
text:String,
title:String=null,
flags:uint=mx.controls.Alert.OK,
parent:Sprite=null,
clickListener:Function=null,
iconClass:Class=null,
302 CHAPTER 9
defaultButton:uint=mx.controls.Alert.OK
):Alert
This method returns an Alert control object.
The following table describes the arguments of the show() method:
Argument Description
text (Required) Specifies the text message displayed in the dialog box.
title Specifies the dialog box title. If omitted, displays a blank title bar.
flags Specifies the button(s) to display in the dialog box. The options are as follows:
mx.controls.Alert.OK OK button
mx.controls.Alert.NO No button
Each option is a bit value and can be combined with other options by using the pipe '|' operator. The buttons
appear in the order listed here regardless of the order specified in your code. The default value is
mx.controls.Alert.OK.
clickListener Specifies the listener for click events from the buttons.
The event object passed to this handler is an instance of the CloseEvent class. The event object contains the
detail field, which is set to the button flag that was clicked (mx.controls.Alert.OK,
mx.controls.Alert.CANCEL, mx.controls.Alert.YES, or mx.controls.Alert.NO).
iconClass Specifies an icon to display to the left of the message text in the dialog box.
defaultButton Specifies the default button by using one of the valid values for the flags argument. This is the button that is
selected when the user presses the Enter key. The default value is Alert.OK.
Pressing the Escape key triggers the Cancel or No button just as if you clicked it.
To use the Alert control, you first import the Alert class into your application, then call the show() method, as the
following example shows:
<?xml version="1.0"?>
<!-- controls\alert\AlertSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
]]>
</mx:Script>
ADOBE FLEX 3 303
Adobe Flex 3 Developer Guide
<mx:TextInput id="myInput"
width="150"
text=""/>
<mx:Button id="myButton"
label="Copy Text"
click="myText.text = myInput.text;
Alert.show('Text Copied!', 'Alert Box', mx.controls.Alert.OK);"/>
<mx:TextInput id="myText"/>
</mx:Application>
In this example, selecting the Button control copies text from the TextInput control to the TextArea control, and
displays the Alert control.
You can also define an event listener for the Button control, as the following example shows:
<?xml version="1.0"?>
<!-- controls\alert\AlertSimpleEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
<mx:TextInput id="myInput"
width="150"
text=""/>
<mx:Button id="myButton"
label="Copy Text"
click="alertListener();"/>
<mx:TextInput id="myText"/>
</mx:Application>
Note: After the show() method creates the dialog box, Flex continues processing of your application; it does not wait
for the user to close the dialog box.
<mx:TextInput id="myInput"
width="150"
text=""/>
<mx:Button id="myButton"
label="Copy Text"
click="openAlert();"/>
<mx:TextInput id="myText"/>
</mx:Application>
In this example, you set the height and width properties of the Alert object to explicitly size the control.
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
<mx:TextInput id="myInput"
width="150"
text="" />
<mx:Button id="myButton"
ADOBE FLEX 3 305
Adobe Flex 3 Developer Guide
label="Copy Text"
click='Alert.show("Copy Text?", "Alert",
Alert.OK | Alert.CANCEL, this,
alertListener, null, Alert.OK);'/>
<mx:TextInput id="myText"/>
</mx:Application>
In this example, you define an event listener for the Alert control. Within the body of the event listener, you
determine which button was pressed by examining the detail property of the event object. The event object is
an instance of the CloseEvent class. If the user pressed the OK button, copy the text. If the user pressed any other
button, or pressed the Escape key, do not copy the text.
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
[Embed(source="assets/alertIcon.jpg")]
[Bindable]
public var iconSymbol:Class;
<mx:TextInput id="myInput"
width="150"
text=""/>
<mx:Button id="myButton"
label="Copy Text"
click='Alert.show("Copy Text?", "Alert",
Alert.OK | Alert.CANCEL, this,
alertListener, iconSymbol, Alert.OK );'/>
<mx:TextInput id="myText"/>
</mx:Application>
306 CHAPTER 9
ProgressBar control
The ProgressBar control provides a visual representation of the progress of a task over time. There are two types
of ProgressBar controls: determinate and indeterminate. A determinate ProgressBar control is a linear represen-
tation of the progress of a task over time. You can use this when the user is required to wait for an extended period
of time, and the scope of the task is known.
An indeterminate ProgressBar control represents time-based processes for which the scope is not yet known. As
soon as you can determine the scope, you should use a determinate ProgressBar control.
The following example shows both types of ProgressBar controls:
Use the ProgressBar control when the user is required to wait for completion of a process over an extended period
of time. You can attach the ProgressBar control to any kind of loading content. A label can display the extent of
loaded contents when enabled.
<mx:Script>
<![CDATA[
public function initImage():void {
image1.load('../assets/DSC00034.JPG');
}
]]>
</mx:Script>
<mx:VBox id="vbox0"
width="600" height="600">
<mx:Canvas>
<mx:ProgressBar width="200" source="image1"/>
</mx:Canvas>
<mx:Button id="myButton"
label="Show"
click="initImage();"
/>
<mx:Image id="image1"
height="500" width="600"
autoLoad="false"
visible="true"
/>
</mx:VBox>
</mx:Application>
After you run this example the first time, the large image will typically be stored in your browser’s cache. Before
running this example a second time, clear your browser’s cache so that you can see the ProgressBar control
complete. If you do not clear your browser’s cache, Flash Player loads the image from the cache and the
ProgressBar control might go from 0% to 100% too quickly to see it tracking any progress in between.
In this mode, the Image control issues progress events during the load, and a complete event when the load
completes.
The <mx:Image> tag exposes the bytesLoaded and bytesTotal properties, so you could also use polled mode,
as the following example shows:
<mx:ProgressBar width="200" source="image1" mode="polled"/>
308 CHAPTER 9
In manual mode, mode="manual", you use an indeterminate ProgressBar control with the maximum and minimum
properties and the setProgress() method. The setProgress() method has the following method signature:
setProgress(Number completed, Number total)
completed Specifies the progress made in the task, and must be between the maximum and minimum values. For
example, if you were tracking the number of bytes to load, this would be the number of bytes already loaded.
total Specifies the total task. For example, if you were tracking bytes loaded, this would be the total number of
bytes to load. Typically, this is the same value as maximum.
To measure progress, you make explicit calls to the setProgress() method to update the ProgressBar control.
<mx:Script>
<![CDATA[
public function initImage():void {
image1.load('../assets/DSC00034.JPG');
}
]]>
</mx:Script>
<mx:VBox id="vbox0"
width="600" height="600">
<mx:Canvas>
<mx:ProgressBar
width="300"
source="image1"
mode="polled"
label="Loading Image %1 out of %2 bytes, %3%%"
labelWidth="400"
ADOBE FLEX 3 309
Adobe Flex 3 Developer Guide
/>
</mx:Canvas>
<mx:Button id="myButton"
label="Show"
click="initImage();"
/>
<mx:Image id="image1"
height="500" width="600"
autoLoad="false"
visible="true"
/>
</mx:VBox>
</mx:Application>
As with the previous example, be sure to clear your browser’s cache before running this example a second time.
<mx:VBox>
<mx:Label text="Above"/>
<mx:HRule/>
<mx:Label text="Below"/>
</mx:VBox>
<mx:HBox>
<mx:Label text="Left"/>
<mx:VRule/>
<mx:Label text="Right"/>
</mx:HBox>
</mx:Application>
This example creates the output shown in the preceding image.
You can also use properties of the HRule and VRule controls to specify line width, stroke color, and shadow color,
as the following example shows:
<?xml version="1.0"?>
<!-- controls\rule\RuleProps.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox>
<mx:Label text="Above"/>
<mx:HRule shadowColor="0xEEEEEE"/>
<mx:Label text="Below"/>
</mx:VBox>
<mx:HBox>
<mx:Label text="Left"/>
<mx:VRule strokeWidth="10" strokeColor="0xC4CCCC"/>
<mx:Label text="Right"/>
</mx:HBox>
</mx:Application>
This code produces the following image:
• If you set the strokeWidth property to 2, Flex draws the rule as two adjacent 1-pixel-wide lines, horizontal
for an HRule control or vertical for a VRule control. This is the default value.
• If you set the strokeWidth property to a value greater than 2, Flex draws the rule as a hollow rectangle with
1-pixel-wide edges.
The following example shows all three options:
If you set the height property of an HRule control to a value greater than the strokeWidth property, Flex draws
the rule within a rectangle of the specified height, and centers the rule vertically within the rectangle. The height
of the rule is the height specified by the strokeWidth property.
If you set the width property of a VRule control to a value greater than the strokeWidth property, Flex draws the
rule within a rectangle of the specified width, and centers the rule horizontally within the rectangle. The width of
the rule is the width specified by the strokeWidth property.
If you set the height property of an HRule control or the width property of a VRule control to a value smaller
than the strokeWidth property, the rule is drawn as if it had a strokeWidth property equal to the height or
width property.
Note: If the height and width properties are specified as percentage values, the actual pixel values are calculated
before the height and width properties are compared to the strokeWidth property.
The strokeColor and shadowColor properties determine the colors of the HRule and VRule controls. The
strokeColor property specifies the color of the line as follows:
• If you set the strokeWidth property to 1, specifies the color of the entire line.
• If you set the strokeWidth property to 2, specifies the color of the top line for an HRule control, or the left
line for a VRule control.
• If you set the strokeWidth property to a value greater than 2, specifies the color of the top and left edges of
the rectangle.
312 CHAPTER 9
The shadowColor property specifies the shadow color of the line as follows:
• If you set the strokeWidth property to 1, does nothing.
• If you set the strokeWidth property to 2, specifies the color of the bottom line for an HRule control, or the
right line for a VRule control.
• If you set the strokeWidth property to a value greater than 2, specifies the color of the bottom and right edges
of the rectangle.
<mx:Style>
.thickRule {strokeWidth:5}
HRule {strokeColor:#00FF00; shadowColor:#0000FF}
</mx:Style>
<mx:HRule styleName="thickRule"/>
</mx:Application>
This example produces the following image:
ScrollBar control
The VScrollBar (vertical ScrollBar) control and HScrollBar (horizontal ScrollBar) controls let the user control the
portion of data that is displayed when there is too much data to fit in the display area.
Although you can use the VScrollBar control and HScrollBar control as stand-alone controls, they are usually
combined with other components as part of a custom component to provide scrolling functionality. For more
information, see Creating and Extending Adobe Flex 3 Components.
ADOBE FLEX 3 313
Adobe Flex 3 Developer Guide
ScrollBar controls consists of four parts: two arrow buttons, a track, and a thumb. The position of the thumb and
display of the buttons depends on the current state of the ScrollBar control. The width of the control is equal to
the largest width of its subcomponents (arrow buttons, track, and thumb). Every subcomponent is centered in the
scroll bar.
The ScrollBar control uses four parameters to calculate its display state:
• Minimum range value
• Maximum range value
• Current position; must be within the minimum and maximum range values
• Viewport size; represents the number of items in the range that can be displayed at once and must be equal to
or less than the range
<mx:Script>
<![CDATA[
import mx.events.ScrollEvent;
<mx:Label
width="100%"
color="blue"
text="Click on the ScrollBar control to view its properties."/>
<mx:VScrollBar id="bar"
height="100%"
minScrollPosition="0"
314 CHAPTER 9
maxScrollPosition="{this.width - 20}"
lineScrollSize="50"
pageScrollSize="100"
repeatDelay="1000"
repeatInterval="500"
scroll="myScroll(event);"/>
<mx:TextArea id="showPosition"
height="100%" width="100%"
color="blue"/>
</mx:Application>
User interaction
Use the mouse to click the various portions of the ScrollBar control, which dispatches events to listeners. The
object listening to the ScrollBar control is responsible for updating the portion of data displayed. The ScrollBar
control updates itself to represent the new state after the action has taken place.
315
Topics
About text controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
Using the text property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
Using the htmlText property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
Selecting and modifying text. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330
Label control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
TextInput control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
Text control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
TextArea control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
RichTextEditor control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
Label No No
TextInput No Yes
Text Yes No
All controls except the RichTextEditor control are single components with a simple text region; for example, the
following image shows a TextInput control in a simple form:
Note: If you specify the value of the text property by using a string directly in MXML, Flex collapses white space
characters. If you specify the value of the text property in ActionScript, Flex does not collapse white space characters.
<mx:Text width="400">
<mx:text>
This string contains a less than, <, greater than,
>, ampersand, &, apostrophe, ', and quotation mark, ".
</mx:text>
</mx:Text>
ADOBE FLEX 3 319
Adobe Flex 3 Developer Guide
</mx:Application>
The resulting application contains three almost identical text controls, each with the following text. The first two
controls, however, convert any tabs in the text to spaces.
This string contains a less than, <, greater than, >, ampersand, &,apostrophe, ',
and quotation mark, ".
In a CDATA section If you wrap the text string in the CDATA tag, the following rules apply:
• You cannot use a CDATA section in a property assignment statement in the text control opening tag; you must
define the property in an <mx:text> child tag.
• Text inside the CDATA section appears as it is entered, including white space characters. Use literal characters,
such as " or < for special characters, and use standard return and tab characters. Character entities, such as >,
and backslash-style escape characters, such as \n, appear as literal text.
The following code example follows these CDATA section rules. The second and third lines of text in the
<mx:text> tag are not indented because any leading tab or space characters would appear in the displayed text.
<?xml version="1.0"?>
<!-- textcontrols/TextCDATA.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="500">
<mx:Text width="100%">
<mx:text>
<![CDATA[This string contains a less than, <, greater than, >,
ampersand, &, apostrophe, ', return,
tab. and quotation mark, ".]]>
</mx:text>
</mx:Text>
</mx:Application>
The displayed text appears on three lines, as follows:
This string contains a less than, <, greater than, >,
ampersand, &, apostrophe, ', return,
tab. and quotation mark, ".
• Use backslash escape characters for special characters, including \t for the tab character, and \n or \r for a
return/line feed character combination. You can use the escape character \" for the double-quotation mark and \'
for the single-quotation mark.
• In standard text, but not in CDATA sections, you can use the special characters left angle bracket (<), right
angle bracket (>), and ampersand (&), by inserting the XML character entity equivalents of <, >, and
&, respectively. You can also use " and ' for double-quotation marks ("), and single-quotation
marks ('), and you can use numeric character references, such as ¥ for the Yen mark (¥). Do not use any
other named character entities; Flex treats them as literal text.
• In CDATA sections only, do not use character entities or references, such as < or ¥ because Flex
treats them as literal text. Instead, use the actual character, such as <.
The following example uses an initialization function to set the text property to a string that contains these
characters:
<?xml version="1.0"?>
<!-- textcontrols/InitText.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="initText()">
<mx:Script>
public function initText():void {
//The following is on one line.
myText.text="This string contains a return, \n, tab, \t, and quotation mark, \". " +
"This string also contains less than, <, greater than, >, " +
"ampersand, &, and apostrophe, ', characters.";
}
</mx:Script>
<mx:Text width="450" id="myText" initialize="initText();"/>
</mx:Application>
The following example uses an <mx:Script> tag with a variable in a CDATA section to set the text property:
<?xml version="1.0"?>
<!-- textcontrols/VarText.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
//The following is on one line.
public var myText:String ="This string contains a return, \n, tab, \t, and
quotation mark, \". This string also contains less than, <, greater than, <, ampersand,
<;, and apostrophe, ', characters.";
]]>
</mx:Script>
<mx:Text width="450" text="{myText}"/>
</mx:Application>
The displayed text for each example appears on three lines. The first line ends at the return specified by the \n
character. The remaining text wraps onto a third line because it is too long to fit on a single line. (Note: Although
the tab character may be noticeable in the following output, it is included in the right location.)
This string contains a return,
, tab, , and quotation mark, ". This string also contains less than, <,
greater than, >, ampersand, &, and apostrophe, ', characters.
ADOBE FLEX 3 321
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import flash.events.TextEvent;
<mx:TextArea id="myTA"/>
</mx:Application>
The Label control must have the selectable property set to true to generate the link event.
326 CHAPTER 10
When you use the link event, the event is generated and the text following event: in the hyperlink destination
is included in the text property of the event object. However, the hyperlink is not automatically executed; you
must execute the hyperlink from within your event handler. This allows you to modify the hyperlink, or even
prohibit it from occurring, in your application.
<![CDATA[
You can vary the <font size='20'>font size</font>,<br><font
color="#0000FF">color</font>,<br><font face="CourierNew, Courier,
Typewriter">face</font>, or<br><font size="18" color="#FF00FF"face="Times, Times New
Roman, _serif">any combination of the three.</font>
]]>
</mx:htmlText>
</mx:TextArea>
</mx:Application>
This code results in the following output:
id Specifies the identifier for the imported image. This is useful if you want to control the embedded content
with ActionScript.
vspace Specifies the amount of vertical space that surrounds the image where no text.
width Specifies the width of the image, in pixels. The default value is 8.
The following example shows the use of the <img> tag and how text can flow around the image:
<?xml version="1.0"?>
<!-- textcontrols/ImgTag.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundGradientColors="[#FFFFFF, #FFFFFF]" width="300" height="300">
<mx:Text height="100%" width="100%">
<mx:htmlText>
<![CDATA[
<p>You can include an image in your HTML text with the <img> tag.</p>
<p><img src='assets/butterfly.gif' width='30' height='30' align='left'
hspace='10' vspace='10'>
Here is text that follows the image. I'm extending the text by lengthening this
sentence until it's long enough to show wrapping around the bottom of the image.</p>
]]>
</mx:htmlText>
</mx:Text>
</mx:Application>
Selecting text
The Flex editable controls provide properties and methods to select text regions and get selections. You can
modify the contents of the selection as described in “Modifying text” on page 332.
ADOBE FLEX 3 331
Adobe Flex 3 Developer Guide
Creating a selection
The TextInput and TextArea controls, including the RichTextEditor control’s TextArea subcontrol, provide the
following text selection properties and method:
• setSelection() method selects a range of text. You specify the zero-based indexes of the start character and
the position immediately after the last character in the text.
• selectionBeginIndex and selectionEndIndex set or return the zero-based location in the text of the start
and position immediately after the end of a selection.
To select the first 10 characters of the myTextArea TextArea control, for example, use the following method:
myTextArea.setSelection(0, 10);
To change the last character of this selection to be the twenty-fifth character in the TextArea control, use the
following statement:
myTextArea.endIndex=25;
To select text in a RichTextEditor control, use the control’s TextArea subcontrol, which you access by using the
textArea id. To select the first 10 characters in the myRTE RichTextEditor control, for example, use the following
code:
myRTE.textArea.setSelection(0, 10);
Getting a selection
You get a text control’s selection by getting a TextRange object with the selected text. You can then use the
TextRange object to modify the selected text, as described in “Modifying text” on page 332. The technique you
use to get the selection depends on the control type.
Modifying text
You use the TextRange class to modify the text in a TextArea, TextInput, or RichTextEditor control. This class lets
you affect the following text characteristics:
• text or htmltext property contents
• text color, decoration (underlining), and alignment
• font family, size, style (italics), and weight (bold)
• URL of an HTML <a> link
Changing text
After you get a TextRange object, use its properties to modify the text in the range. The changes you make to the
TextRange appear in the text control.
You can get or set the text in a TextRange object as HTML text or as a plain text, independent of any property that
you might have used to initially set the text. If you created a TextArea control, for example, and set its text
property, you can use the TextRange htmlText property to get and change the text. The following example shows
this usage, and shows using the TextRange class to access a range of text and change its properties. It also shows
using String properties and methods to get text indexes.
<?xml version="1.0"?>
<!-- textcontrols/TextRangeExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
ADOBE FLEX 3 333
Adobe Flex 3 Developer Guide
<mx:Script><![CDATA[
import mx.controls.textClasses.TextRange
[Bindable]
public var htmlData:String="<textformat leading='2'><p align='center'><b><font
size='20'>HTML Formatted Text</font></b></p></textformat><br><textformat leading='2'><p
align='left'><font face='_sans' size='12' color='#000000'>This paragraph contains
<b>bold</b>, <i>italic</i>, <u>underlined</u>, and <b><i><u>bold italic underlined
</u></i></b>text. </font></p></textformat><br><p><u><font face='arial' size='14'
color='#ff0000'>This a red underlined 14-point arial font with no alignment
set.</font></u></p><p align='right'><font face='verdana' size='12'
color='#006666'><b>This a teal bold 12-pt. Verdana font with alignment set to
right.</b></font></p>";
<!-- The text area. When you release the mouse after selecting text,
it calls the func1 function. -->
<mx:RichTextEditor id="rte1" htmlText="{htmlData}" width="100%" height="100%"
mouseUp="changeSelectionText()"/>
<mx:TextArea editable="false" id="t1" fontSize="12" fontWeight="bold" width="300"
height="180"/>
</mx:Application>
Label control
The Label control is a noneditable single-line text label. It has the following characteristics:
• The user cannot change the text, but the application can modify it.
• You can specify text formatting by using styles or HTML text.
ADOBE FLEX 3 335
Adobe Flex 3 Developer Guide
For the code used to create this sample, see Creating a Label control.
<mx:Label text="Label1"/>
</mx:Application>
You use the text property to specify a string of raw text, and the htmlText property to specify an
HTML-formatted string. For more information on using these properties, see “Using the text property” on
page 317 and “Using the htmlText property” on page 321.
336 CHAPTER 10
TextInput control
The TextInput control is a single-line text field that is optionally editable. The TextInput control supports the
HTML rendering capabilities of Adobe Flash Player.
For complete reference information, see the Adobe Flex Language Reference.
The following image shows a TextInput control:
To create a multiline, editable text field, use a TextArea control. For more information, see “TextArea control” on
page 339. To create noneditable text fields, use Label and Text controls. For more information, see “Label control”
on page 334 and “Text control” on page 337.
The TextInput control does not include a label, but you can add one by using a Label control or by nesting the
TextInput control in a FormItem container in a Form layout container, as shown in the example in “About text
controls” on page 315. TextInput controls dispatch change, textInput, and enter events.
If you disable a TextInput control, it displays its contents in a different color, represented by the disabledColor
style. You can set a TextInput control’s editable property to false to prevent editing of the text. You can set a
TextInput control’s displayAsPassword property to conceal the input text by displaying characters as asterisks.
Text control
The Text control displays multiline, noneditable text. The control has the following characteristics:
• The user cannot change the text, but the application can modify it.
• The control does not support scroll bars. If the text exceeds the control size, users can use keys to scroll the
text.
• The control is transparent so that the background of the component’s container shows through.
• The control has no borders, so the label appears as text written directly on its background.
• The control supports HTML text and a variety of text and font styles.
• The text always word-wraps at the control boundaries, and is always aligned to the top of the control.
338 CHAPTER 10
For complete reference information, see the Adobe Flex Language Reference.
To create a single-line, noneditable text field, use the Label control. For more information, see “Label control” on
page 334. To create user-editable text fields, use the TextInput or TextArea controls. For more information, see
“TextInput control” on page 336 and “TextArea control” on page 339.
The following image shows an example of a Text control with a width of 175 pixels:
As a general rule, if you have long text, you should specify a pixel-based width property. If the text might change
and you want to ensure that the Text control always takes up the same space in your application, set explicit
height and width properties that fit the largest expected text.
TextArea control
The TextArea control is a multiline, editable text field with a border and optional scroll bars. The TextArea control
supports the HTML and rich text rendering capabilities of Flash Player and AIR. The TextArea control dispatches
change and textInput events.
For complete reference information, see the Adobe Flex Language Reference.
The following image shows a TextArea control:
To create a single-line, editable text field, use the TextInput control. For more information, see “TextInput control”
on page 336. To create noneditable text fields, use the Label and Text controls. For more information, see “Label
control” on page 334 and “Text control” on page 337.
If you disable a TextArea control, it displays its contents in a different color, represented by the disabledColor
style. You can set a TextArea control’s editable property to false to prevent editing of the text. You can set a
TextArea control’s displayAsPassword property to conceal input text by displaying characters as asterisks.
RichTextEditor control
The RichTextEditor control lets users enter, edit, and format text. Users apply text formatting and URL links by
using subcontrols that are located at the bottom of the RichTextEditor control.
For complete reference information, see the Adobe Flex Language Reference.
The following image shows a RichTextEditor control with some formatted text:
For the source for this example, see “Creating a RichTextEditor control” on page 341.
You use the RichTextEditor interactively as follows:
• Text that you type is formatted as specified by the control settings.
• To apply new formatting to existing text, select the text and set the controls to the required format.
• To create a link, select a range of text, enter the link target in the text box on the right, and press Enter. You
can only specify the URL; the link always opens in a _blank target. Also, creating the link does not change the
appearance of the link text; you must separately apply any color and underlining.
• You can cut, copy, and paste rich text within and between Flash HTML text fields, including the RichTextE-
ditor control’s TextArea subcontrol, by using the normal keyboard commands. You can copy and paste plain text
between the TextArea and any other text application, such as your browser or a text editor.
You can use the text property to specify an unformatted text string, or the htmlText property to specify an
HTML-formatted string. For more information on using these properties, see “Using the text property” on
page 317, and “Using the htmlText property” on page 321. For information on selecting, replacing, and formatting
text that is in the control, see “Selecting and modifying text” on page 330.
The following example shows the code used to create the image in “About the RichTextEditor control” on
page 340:
<?xml version="1.0"?>
<!-- textcontrols/RichTextEditorControlWithFormattedText.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- The HTML text string used to populate the RichTextEditor control's
TextArea subcontrol. The text is on a single line. -->
<mx:Script><![CDATA[
[Bindable]
public var htmlData:String="<textformat leading='2'><p align='center'><b><font
size='20'>HTML Formatted Text</font></b></p></textformat><br><textformat leading='2'><p
align='left'><font face='_sans' size='12' color='#000000'>This paragraph
contains<b>bold</b>, <i>italic</i>, <u>underlined</u>, and <b><i><u>bold italic
underlined </u></i></b>text.</font></p></textformat><br><p><u><font face='arial'
size='14' color='#ff0000'>This a red underlined 14-point arial font with no alignment
set.</font></u></p><p align='right'><font face='verdana' size='12'
color='#006666'><b>This a teal bold 12-pt.' Verdana font with alignment set to
right.</b></font></p><br><li>This is bulleted text.</li><li><font face='arial' size='12'
color='#0000ff'><u> <a href='http://www.adobe.com'>This is a bulleted link with underline
and blue color set.</a></u></font></li>";
]]></mx:Script>
<!-- The RichTextEditor control. To reference a subcontrol prefix its ID with the
RichTextEditor control ID. -->
<mx:RichTextEditor id="rte1"
backgroundColor="#ccffcc"
width="500"
headerColors="[#88bb88, #bbeebb]"
footerColors="[#bbeebb, #88bb88]"
title="Rich Text Editor"
htmlText="{htmlData}"
initialize="rte1.textArea.setStyle('backgroundColor', '0xeeffee')"
/>
</mx:Application>
<mx:HBox>
<mx:RichTextEditor id="rt1"
title="RichTextEditor With No Align Buttons"
creationComplete="removeAlignButtons()"
/>
<mx:RichTextEditor id="rt2"
title="Default RichTextEditor"
/>
</mx:HBox>
</mx:Application>
<mx:Script>
<![CDATA[
import mx.controls.*;
import mx.containers.*;
import flash.events.*;
import mx.managers.PopUpManager;
import mx.core.IFlexDisplayObject;
</mx:Application>
The following MyTitleWindow.mxml file defines the custom myTitleWindow control that contains the find-and-
replace interface and logic:
<?xml version="1.0"?>
<!-- A TitleWindow that displays the X close button. Clicking the close button
only generates a CloseEvent event, so it must handle the event to close the control. -->
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
title="Find/Replace"
showCloseButton="true"
close="closeDialog();"
>
<mx:Script>
<![CDATA[
346 CHAPTER 10
import mx.controls.TextArea;
import mx.managers.PopUpManager;
]]>
</mx:Script>
Topics
About menu-based controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Defining menu structure and data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
Menu-based control events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
Menu control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
MenuBar control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
PopUpMenuButton control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
As with all data-driven controls, if the data provider contents can change dynamically, and you want the Menu to
update with the changes, ensure that the data source is a collection, such as an ArrayCollection or XMLListCol-
lection object. To modify the menu, change the underlying collection, and the menu will update its appearance
accordingly.
Node (menu item) tags in the XML data can have any name. Many examples in this topic use tags such as <node>
for all menu items, or <menuItem> for top-level items and <subMenuItem> for submenu items, but it might be
more realistic to use tag names that identify the data, such as <person>, <address>, and so on. The menu-
handling code reads through the XML and builds the display hierarchy based on the nested relationship of the
nodes. For more information, see “Specifying and using menu entry information” on page 349.
Most menus have multiple items at the top level, not a single root item. XML objects, such as the XML object
created by the <mx:XML> tag, must have a single root node. To display a menu that uses a data provider that has a
root that you do not want to display, set the Menu, PopUpMenuButton, or MenuBar showRoot property to false.
separator Items with the separator type provide a simple horizontal line that divides the items in a menu into
different visual groups.
Menu attributes
Menu items can specify several attributes that determine how the item is displayed and behaves. The following
table lists the attributes you can specify, their data types, their purposes, and how the data provider must represent
them if the menu uses the DefaultDataDescriptor class to parse the data provider:
enabled Boolean Specifies whether the user can select the menu item (true), or not ( false). If not specified, Flex treats the
item as if the value were true.
If you use the default data descriptor, data providers must use an enabled XML attribute or object field to
specify this characteristic.
groupName String (Required, and meaningful, for radio type only) The identifier that associates radio button items in a radio
group. If you use the default data descriptor, data providers must use a groupName XML attribute or object
field to specify this characteristic.
icon Class Specifies the class identifier of an image asset. This item is not used for the check, radio, or separator
types. You can use the checkIcon and radioIcon styles to specify the icons used for radio and check box
items that are selected.
The menu’s iconField or iconFunction property determines the name of the field in the data that
specifies the icon, or a function for determining the icons.
label String Specifies the text that appears in the control. This item is used for all menu item types except separator.
The menu’s labelField or labelFunction property determines the name of the field in the data that
specifies the label, or a function for determining the labels. (If the data provider is in E4X XML format, you
must specify one of these properties to display a label.) If the data provider is an array of strings, Flex uses
the string value as the label.
toggled Boolean Specifies whether a check or radio item is selected. If not specified, Flex treats the item as if the value
were false and the item is not selected.
If you use the default data descriptor, data providers must use a toggled XML attribute or object field to
specify this characteristic.
type String Specifies the type of menu item. Meaningful values are separator, check, or radio. Flex treats all other
values, or nodes with no type entry, as normal menu entries.
If you use the default data descriptor, data providers must use a type XML attribute or object field to
specify this characteristic.
Menu-based controls ignore all other object fields or XML attributes, so you can use them for application-specific
data.
ADOBE FLEX 3 351
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.controls.Menu;
The following image shows the resulting control, with MenuItem D open; notice that check item B and radio item
D-2 are selected:
<mx:Script>
<![CDATA[
// Import the Menu control.
import mx.controls.Menu;
[Bindable]
[Embed(source="assets/topIcon.jpg")]
public var myTopIcon:Class;
[Bindable]
[Embed(source="assets/radioIcon.jpg")]
public var myRadioIcon:Class;
[Bindable]
[Embed(source="assets/checkIcon.gif")]
public var myCheckIcon:Class;
]]>
</mx:Script>
Property Description
item The item in the data provider for the menu item associated with the event.
index The index of the item in the menu or submenu that contains it.
menuBar The MenuBar control instance that is the parent of the menu, or undefined when the menu does not belong
to a MenuBar. For more information, see “MenuBar control” on page 365.
To access properties and fields of an object-based menu item, you specify the menu item field name, as follows:
ta1.text = event.item.label
To access attributes of an E4X XML-based menu item, you specify the menu item attribute name in E4X syntax,
as follows:
ta1.text = event.item.@label
Note: If you set an event listener on a submenu of a menu-based control, and the menu data provider’s structure
changes (for example, an element is removed), the event listener might no longer exist. To ensure that the event listener
is available when the data provider structure changes, either listen on events of the menu-based control, not a
submenu, or add the event listener each time an event occurs that changes the data provider’s structure.
The following example shows a menu with a simple event listener. For a more complex example, see “Example:
Using Menu control events” on page 358.
ADOBE FLEX 3 355
Adobe Flex 3 Developer Guide
<?xml version="1.0"?>
<!-- menus/EventListener.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute">
<mx:Script>
<![CDATA[
import mx.controls.Menu;
import mx.events.MenuEvent;
MenuBar events
The following figure shows a MenuBar control:
<mx:Script>
ADOBE FLEX 3 357
Adobe Flex 3 Developer Guide
<![CDATA[
import mx.events.MenuEvent;
import mx.controls.Alert;
import mx.collections.*;
[Bindable]
public var menuBarCollection:XMLListCollection;
<mx:Label
width="100%"
358 CHAPTER 11
color="blue"
text="Select a menu item."/>
<mx:MenuBar labelField="@label"
dataProvider="{menuBarCollection}"
change="changeHandler(event);"
itemClick="itemClickHandler(event);"
itemRollOver="rollOverHandler(event);"/>
<mx:TextArea id="rollOverTextArea"
width="200" height="100"/>
<mx:TextArea id="itemClickTextArea"
width="200" height="100"/>
</mx:Panel>
</mx:Application>
];
]]>
</mx:Script>
<!-- The XML-based menu data provider. The XML tag requires a single root. -->
<mx:XML id="myMenuData">
<xmlRoot>
<menuitem label="MenuItem A" >
<menuitem label="SubMenuItem A-1" enabled="false"/>
<menuitem label="SubMenuItem A-2"/>
</menuitem>
<menuitem label="MenuItem B" type="check" toggled="true"/>
<menuitem label="MenuItem C" type="check" toggled="false"/>
<menuitem type="separator"/>
<menuitem label="MenuItem D" >
<menuitem label="SubMenuItem D-1" type="radio" groupName="one"/>
<menuitem label="SubMenuItem D-2" type="radio" groupName="one"
toggled="true"/>
<menuitem label="SubMenuItem D-3" type="radio" groupName="one"/>
</menuitem>
</xmlRoot>
</mx:XML>
<!-- Text area to display the event information. -->
<mx:TextArea id="ta1" width="264" height="168" x="11" y="38"/>
<!-- Button controls to open the menus. -->
<mx:Button id="b1"
label="Open XML Popup"
click="createAndShow();" x="10" y="10"
/>
<mx:Button id="b2"
label="Open Object Popup"
click="createAndShow2();" x="139" y="10"
/>
</mx:Application>
When the user selects an item from the pop-up menu, the following things occur:
• The PopUpMenuButton dispatches an itemClick event.
• The application’s itemClickHandler() event listener function handles the itemClick event and displays the
information about the event in an Alert control.
When the user clicks the main button, the following things occur:
• The PopUpMenuButton control dispatches a click event.
• The PopUpMenuButton control dispatches an itemClick event.
• The application’s itemClickHandler() event listener function handles the itemClick event and displays
information about the selected Menu item in an Alert control.
• The application’s clickHandler() event listener function also handles the MouseEvent.CLICK event, and
displays the Button label in an Alert control.
<?xml version="1.0"?>
<!-- menus/PopUpMenuButtonEvents.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
height="600" width="600"
creationComplete="initData();">
<mx:Script>
<![CDATA[
import mx.events.*;
import mx.controls.*;
// Set the Inbox (fourth) item in the menu as the button item.
private function initData():void {
Menu(p1.popUp).selectedIndex=3;
}
// itemClick event handler, invoked when you select from the menu.
// Shows the event's label, index properties, and the values of the
// label and data fields of the data provider entry specified by
// the event's item property.
public function itemClickHandler(event:MenuEvent):void {
Alert.show("itemClick event label: " + event.label
+ " \nindex: " + event.index
+ " \nitem.label: " + event.item.label
+ " \nitem.data: " + event.item.data);
}
<mx:PopUpMenuButton id="p1"
showRoot="true"
dataProvider="{menuDP}"
click="clickHandler(event)"
itemClick="itemClickHandler(event);"
/>
</mx:Application>
Menu control
The Menu control is a pop-up control that contains a menu of individually selectable choices. You use Action-
Script to create a Menu control that pops up in response to a user action, typically as part of an event listener.
Because you create a Menu control in response to an event, it does not have an MXML tag; you can create Menu
controls in ActionScript only.
For complete reference information, see the Adobe Flex Language Reference.
In this example, the MenuItem A and MenuItem D items open submenus. Submenus open when the user moves
the mouse pointer over the parent item or accesses the parent item by using keyboard keys.
The default location of the Menu control is the upper-left corner of your application, at x, y coordinates 0,0. You
can pass x and y arguments to the show() method to control the position relative to the application.
After a Menu opens, it remains visible until the user selects an enabled menu item, the user selects another
component in the application, or a script closes the menu.
ADOBE FLEX 3 363
Adobe Flex 3 Developer Guide
To create a static menu that stays visible all the time, use the MenuBar control or PopUpMenuButton control. For
more information on the MenuBar control, see “MenuBar control” on page 365. For more information on the
PopUpMenuButton control, see “PopUpMenuButton control” on page 367.
<mx:Script>
<![CDATA[
// Import the Menu control.
import mx.controls.Menu;
myMenu.labelField="@label";
myMenu.show(10, 10);
}
]]>
</mx:Script>
<mx:VBox>
<!-- Define a Button control to open the menu -->
<mx:Button id="myButton"
label="Open Menu"
click="createAndShow();"/>
</mx:VBox>
</mx:Application>
You can assign any name to node tags in the XML data. In the previous sample, each node is named with the
generic <menuitem> tag, but you can have used <node>, <subNode>, <person>, <address> and so on.
Because this example uses an E4X XML data source, you must specify the label field by using the E4X @ attribute
specifier syntax, and you tell the control not to show the data provider root node.
Several attributes or fields, such as the type attribute, have meaning to the Menu control. For information on how
Flex interprets and uses the data provider data, see “Specifying and using menu entry information” on page 349.
When a Menu control has focus, you can use the following keys to control it:
Key Description
Down Arrow Moves the selection down and up the rows of the menu. The selection loops at the top or bottom row.
Up Arrow
Right Arrow Opens a submenu, or moves the selection to the next menu in a menu bar.
Left Arrow Closes a submenu and returns focus to the parent menu (if a parent menu exists), or moves the selection to the
previous menu in a menu bar (if the menu bar exists).
Enter Opens a submenu, has the effect of clicking and releasing the mouse on a row if a submenu does not exist.
MenuBar control
A MenuBar control displays the top level of a menu as a horizontal bar of menu items, where each item on the bar
can pop up a submenu. The MenuBar control interprets the data provider in the same way as the Menu control,
and supports the same events as the Menu control. Unlike the Menu control, a MenuBar control is static; that is,
it does not function as a pop-up menu, but is always visible in your application. Because the MenuBar is static,
you can define it directly in MXML.
For complete reference information, see the Adobe Flex Language Reference. For more information on the Menu
control, see “Menu control events” on page 354.
The control shows the labels of the top level of the data provider menu. When a user selects a top-level menu item,
the MenuBar control opens a submenu. The submenu stays open until the user selects another top-level menu
item, selects a submenu item, or clicks outside the MenuBar area.
366 CHAPTER 11
The top-level nodes in the MenuBar control correspond to the buttons on the bar. Therefore, in this example, the
MenuBar control displays the four labels shown in the preceding image.
You can assign any name to node tags in the XML data. In the previous example, each node is named with the
generic <menuitem> tag, but you can use <node>, <subNode>, <person>, <address>, and so on. Several
attributes or fields, such as the type attribute, have meaning to the MenuBar control. For information on how Flex
interprets and uses the data provider data, see “Specifying and using menu entry information” on page 349.
PopUpMenuButton control
The PopUpMenuButton is a PopUpButton control whose secondary button pops up a Menu control. When the
user selects an item from the pop-up menu, the main button of the PopUpButton changes to show the icon and
label of the selected menu item. Unlike the Menu and MenuBar controls, the PopUpMenuButton supports only a
single-level menu.
For complete reference information, see the Adobe Flex Language Reference. For more information on the Menu
control, see “Menu control events” on page 354. For more information on PopUpButton controls, see “PopUp-
Button control” on page 237.
368 CHAPTER 11
<mx:Script>
<![CDATA[
import mx.controls.Menu
<editItem label="Paste"/>
<separator type="separator"/>
<editItem label="Delete"/>
</root>
</mx:XML>
<mx:PopUpMenuButton id="pb2"
dataProvider="{dp2}"
labelField="@label"
showRoot="false"
creationComplete="initData();"/>
</mx:Application>
Because this example uses an E4X XML data source, you must specify the label field by using the E4X @ attribute
specifier syntax, and you must tell the control not to show the data provider root node.
[Bindable]
public var menuData:Array = [
{label: "Inbox", data: "inbox"},
{label: "Calendar", data: "calendar"},
{label: "Sent", data: "sent"},
{label: "Deleted Items", data: "deleted"},
{label: "Spam", data: "spam"}
];
]]>
</mx:Script>
<mx:PopUpMenuButton id="p1"
showRoot="true"
dataProvider="{menuData}"
ADOBE FLEX 3 371
Adobe Flex 3 Developer Guide
Topics
List control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
HorizontalList control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
TileList control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
ComboBox control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
DataGrid control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Tree control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
List control
The List control displays a vertical list of items. Its functionality is very similar to that of the SELECT form element
in HTML. It often contains a vertical scroll bar that lets users access the items in the list. An optional horizontal
scroll bar lets users view items when the full width of the list items is unlikely to fit. The user can select one or
more items from the list.
374 CHAPTER 12
Note: The HorizontalList, TileList, DataGrid, Menu, and Tree controls are derived from the List control or its
immediate parent, the ListBase class. As a result, much of the information for the List control applies to these controls.
For complete reference information, see the Adobe Flex Language Reference.
The following image shows a List control:
You specify the data for the List control by using the dataProvider property of the control. However, because
dataProvider is the List control’s default property, you do not have to specify a <mx:dataProvider> child tag
of the <mx:List> tag. In the simplest case for creating a static List control, you need only put <mx:String> tags
in the control body, because Flex also automatically interprets the multiple tags as an Array of Strings, as the
following example shows:
<?xml version="1.0"?>
<!-- dpcontrols/ListDataProvider.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:List>
<mx:dataProvider>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
<mx:String>AR</mx:String>
</mx:dataProvider>
</mx:List>
</mx:Application>
Because the data in this example is inline static data, it is not necessary to explicitly wrap it in an ArrayCollection
object. However, when working with data that could change, it is always best to specify a collection explicitly; for
more information, see “Using Data Providers and Collections” on page 137.
The index of items in the List control is zero-based, which means that values are 0, 1, 2, ... , n - 1, where n is the
total number of items. The value of the item is its label text.
You typically use events to handle user interaction with a List control. The following example code adds a handler
for a change event to the List control. Flex broadcasts a mx.ListEvent.CHANGE event when the value of the
control changes due to user interaction.
<?xml version="1.0"?>
<!-- dpcontrols/ListChangeEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import flash.events.Event;
In this example, you use two properties of the List control, selectedItem and selectedIndex, in the event
handler. Every change event updates the TextArea control with the label of the selected item and the item’s index
in the control.
The target property of the object passed to the event handler contains a reference to the List control. You can
reference any control property by using the event’s currentTarget property. The
currentTarget.selectedItem field contains a copy of the selected item. If you populate the List control with
an Array of Strings, the currentTarget.selectedItem field contains a String. If you populate it with an Array
of Objects, the currentTarget.selectedItem field contains the Object that corresponds to the selected item,
so, in this case, currentTarget.selectedItem.label refers to the selected item’s label field.
<mx:ArrayCollection id="myDP">
<mx:source>
<mx:Object label="AL" data="Montgomery"/>
<mx:Object label="AK" data="Juneau"/>
<mx:Object label="AR" data="Little Rock"/>
</mx:source>
</mx:ArrayCollection>
Note: This example uses an ArrayCollection object as the data provider. You should always use a collection as the
data provider when the data can change at run time. For more information, see “Using Data Providers and Collec-
tions” on page 137.
Displaying DataTips
DataTips are similar to ToolTips, but display text when the mouse pointer hovers over a row in a List control. Text
in a List control that is longer than the control width is clipped on the right side (or requires scrolling, if the control
has scroll bars). DataTips can solve that problem by displaying all of the text, including the clipped text, when the
mouse pointer hovers over a cell. If you enable data tips, they only appear for fields where the data is clipped. To
display DataTips, set the showDataTips property of a List control to true.
Note: To use DataTips with a DataGrid control, you must set the showDataTips property on the individual
DataGridColumns of the DataGrid.
The default behavior of the showDataTips property is to display the label text. However, you can use the
dataTipField and dataTipFunction properties to determine what is displayed in the DataTip. The
dataTipField property behaves like the labelField property; it specifies the name of the field in the data
provider to use as the DataTip for cells in the column. The dataTipFunction property behaves like the
labelFunction property; it specifies the DataTip string to display for list items.
The following example sets the showDataTips property for a List control:
<mx:List id="myList" dataProvider="{myDP}" width="220" height="200" showDataTips="true"/>
This example creates the following List control:
378 CHAPTER 12
Displaying ScrollTips
You use ScrollTips to give users context about where they are in a list as they scroll through the list. The tips appear
only when you scroll; they don’t appear if you only hover the mouse over the scroll bar. ScrollTips are useful when
live scrolling is disabled (the liveScrolling property is false) so scrolling does not occur until you release the
scroll thumb. The default value of the showScrollTips property is false.
The default behavior of the showScrollTips property is to display the index number of the top visible item. You
can use the scrollTipFunction property to determine what is displayed in the ScrollTip. The
scrollTipFunction property behaves like the labelFunction property; it specifies the ScrollTip string to
display for list items. You should avoid going to the server to fill in a ScrollTip.
The following example sets the showScrollTips and scrollTipFunction properties of a HorizontalList
control, which shares many of the same properties and methods as the standard List control; for more information
about the HorizontalList control, see “HorizontalList control” on page 382. The scrollTipFunction property
specifies a function that gets the value of the description property of the current list item.
<mx:HorizontalList id="list" dataProvider="{album.photo}" width="100%"
itemRenderer="Thumbnail" columnWidth="108" height="100"
selectionColor="#FFCC00" liveScrolling="false" showScrollTips="true"
scrollTipFunction="scrollTipFunc"
change="currentPhoto=album.photo[list.selectedIndex]"/>
This code produces the following HorizontalList control:
The following example sets the variableRowHeight property for a List control to true:
<mx:List id="myList" dataProvider="{myDP}" width="220" height="200"
variableRowHeight="true"/>
You can use the wordWrap property in combination with the variableRowHeight property to wrap text to
multiple lines when it exceeds the width of a List row.
The following example sets the wordWrap and variableRowHeight properties to true:
<mx:List id="myList" dataProvider="{myDP}" width="220" height="200"
variableRowHeight="true" wordWrap="true"/>
This code produces the following List control:
<mx:List iconField="myIcon">
<mx:dataProvider>
<mx:Array>
<mx:Object label="AL" data="Montgomery" myIcon="iconSymbol1"/>
<mx:Object label="AK" data="Juneau" myIcon="iconSymbol2"/>
<mx:Object label="AR" data="Little Rock" myIcon="iconSymbol1"/>
</mx:Array>
</mx:dataProvider>
</mx:List>
</mx:Application>
In this example, you use the iconField property to specify the field of each item containing the icon. You use the
Embed metadata to import the icons, and then reference them in the List control definition.
You can also use the iconFunction property to specify a function that determines the icon, similar to the way
that you can use the labelFunction property to specify a function that determines the label text. The icon
function must have the following signature:
iconFunction(item:Object):Class
The item parameter passed in by the Label control contains the list item object. The function must return the icon
class to display in the List control.
The following example shows a List control that uses the iconFunction property to determine the icon to display
for each item in the list:
<?xml version="1.0"?>
<!-- dpcontrols/ListIconFunction.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
// Embed icons.
[Embed(source="assets/radioIcon.jpg")]
public var pavementSymbol:Class;
[Embed(source="assets/topIcon.jpg")]
public var normalSymbol:Class;
ADOBE FLEX 3 381
Adobe Flex 3 Developer Guide
list1.dataProvider = myDP;
}
<mx:VBox >
<mx:List id="list1" initialize="initList()" labelField="Artist"
iconFunction="myiconfunction" />
</mx:VBox>
</mx:Application>
Key Action
Alphanumeric keys Jumps to the next item with a label that begins with the character typed.
Control Toggle key. Allows for multiple (noncontiguous) selection and deselection. Works with key presses, click selec-
tion, and drag selection.
Shift Contiguous selection key. Allows for contiguous selections. Works with key presses, click selection, and drag
selection.
HorizontalList control
The HorizontalList control displays a horizontal list of items. The HorizontalList control is particularly useful in
combination with a custom item renderer for displaying a list of images and other data. For more information
about custom item renderers, see “Using Item Renderers and Item Editors” on page 779.
For complete reference information, see HorizontalList in the Adobe Flex Language Reference.
The HorizontalList control always displays items from left to right. The control usually contains a horizontal scroll
bar, which lets users access all items in the list. An optional vertical scroll bar lets users view items when the full
height of the list items is unlikely to fit. The user can select one or more items from the list, depending on the value
of the allowMultipleSelection property.
The following image shows a HorizontalList control:
For complete reference information, see HorizontalList in the Adobe Flex Language Reference.
}
]]>
</mx:Script>
Keyboard navigation
The HorizontalList control has the following keyboard navigation features:
Key Action
Key Action
Control Toggle key. Allows for multiple (noncontiguous) selection and deselection when the
allowMultipleSelection property is set to true. Works with key presses, click selection, and drag selection.
Shift Contiguous selection key. Allows for contiguous selections when allowMultipleSelection is set to true.
Works with key presses, click selection, and drag selection.
TileList control
The TileList control displays a tiled list of items. The items are tiled in vertical columns or horizontal rows. The
TileList control is particularly useful in combination with a custom item renderer for displaying a list of images
and other data. The default item renderer for the TileList control is TileListItemRenderer, which, by default,
displays text of the data provider’s label field and any icon. For more information about custom item renderers,
see “Using Item Renderers and Item Editors” on page 779.
For complete reference information, see the Adobe Flex Language Reference.
<mx:TileList dataProvider="{TileListdp}"
itemRenderer="mx.controls.Button"/>
</mx:Application>
In this example, you populate the data provider with an ArrayCollection that contains an Array of strings defining
labels and data values. You then use the itemRenderer property to specify a Button control as the item renderer.
The Button controls display the data provider label values. The TileList control displays nine Button controls with
the specified labels.
Keyboard navigation
The TileList control has the following keyboard navigation features:
Key Action
Up Arrow Moves selection up one item. If the control direction is vertical, and the current item is at the top of a column,
moves to the last item in the previous column; motion stops at the first item in the first column.
Down Arrow Moves selection down one item. If the control direction is vertical, and the current item is at the bottom of a
column, moves to the first item in the next column; motion stops at the last item in the last column.
Right Arrow Moves selection to the right one item. If the control direction is horizontal, and the current item is at the end of
a row, moves to the first item in the next row; motion stops at the last item in the last column.
Left Arrow Moves selection to the left one item. If the control direction is horizontal, and the current item is at the begin-
ning of a row, moves to the last item in the previous row; motion stops at the first item in the first row.
Page Up Moves selection up one page. For a single-page control, moves the selection to the beginning of the list.
Page Down Moves selection down one page. For a single-page control, moves the selection to the end of the list.
Key Action
Control Toggle key. Allows for multiple (noncontiguous) selection and deselection when allowMultipleSelection is
set to true. Works with key presses, click selection, and drag selection.
Shift Contiguous selection key. Allows for contiguous selections when allowMultipleSelection is set to true.
Works with key presses, click selection, and drag selection.
ComboBox control
The ComboBox control is a drop-down list from which the user can select a single value. Its functionality is very
similar to that of the SELECT form element in HTML.
For complete reference information, see the Adobe Flex Language Reference.
In its editable state, the user can type text directly into the top of the list, or select one of the preset values from
the list. In its noneditable state, as the user types a letter, the drop-down list opens and scrolls to the value that
most closely matches the one being entered; matching is only performed on the first letter that the user types.
If the drop-down list hits the lower boundary of the application, it opens upward. If a list item is too long to fit in
the horizontal display area, it is truncated to fit. If there are too many items to display in the drop-down list, a
vertical scroll bar appears.
The ComboBox control uses a list-based data provider. For more information, see “Using Data Providers and
Collections” on page 137.
You specify the data for the ComboBox control by using the dataProvider property of the <mx:ComboBox> tag.
The data provider should be a collection; the standard collection implementations are the ArrayCollection and
XMLListCollection classes, for working with Array-based and XML-based data, respectively. You can also use a
raw data object, such as Array or XMLList object, as a data provider; however, it is always better to specify a
collection explicitly for data that could change. For more information on data providers and collections see “Using
Data Providers and Collections” on page 137.
In a simple case for creating a ComboBox control, you specify the property by using an <mx:dataProvider>
child tag, and use an <mx:ArrayCollection> tag to define the entries as an ArrayCollection whose source is an
Array of Strings, as the following example shows:
<?xml version="1.0"?>
<!-- dpcontrols/ComboBoxSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:ComboBox>
<mx:ArrayCollection>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
<mx:String>AR</mx:String>
</mx:ArrayCollection>
</mx:ComboBox>
</mx:Application>
This example shows how you can take advantages of MXML defaults. You do not have to use an
<mx:dataProvider> tag, because dataProvider is the default property of the ComboBox control. Similarly, you
do not have to use an <mx:source> tag inside the <mx:ArrayCollection> tag because source is the default
property of the ArrayCollection class. Finally, you do not have to specify an <mx:Array> tag for the source array.
The data provider can also contain objects with multiple fields, as in the following example:
<?xml version="1.0"?>
<!-- dpcontrols/ComboBoxMultiple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:ComboBox>
<mx:ArrayCollection>
<mx:Object label="AL" data="Montgomery"/>
<mx:Object label="AK" data="Juneau"/>
<mx:Object label="AR" data="Little Rock"/>
</mx:ArrayCollection>
</mx:ComboBox>
</mx:Application>
If the data source is an array of strings, as in the first example, the ComboBox displays strings as the items in the
drop-down list. If the data source consists of objects, the ComboBox, by default, uses the contents of the label field.
You can, however, override this behavior, as described in “Specifying ComboBox labels” on page 391.
The index of items in the ComboBox control is zero-based, which means that values are 0, 1, 2, ... , n - 1, where n
is the total number of items. The value of the item is its label text.
390 CHAPTER 12
// Display a selected item's label field and index for change events.
private function changeEvt(event:Event):void {
forChange.text+=event.currentTarget.selectedItem.label + " " +
event.currentTarget.selectedIndex + "\n";
}
]]>
</mx:Script>
If you populate the ComboBox control with an Array of Strings, the currentTarget.selectedItem field
contains a String. If you populate it with an Array of Objects, the currentTarget.selectedItem field contains
the Object that corresponds to the selected item, so, in this case, currentTarget.selectedItem.label refers
to the selected item object’s label field.
In this example, you use two properties of the ComboBox control, selectedItem and selectedIndex, in the
event handlers. Every change event updates the TextArea control with the label of the selected item and the item’s
index in the control, and every open or close event appends the event type.
<mx:Script>
<![CDATA[
import mx.collections.*
private var COLOR_ARRAY:Array=
[{label:"Red", data:"#FF0000"},
{label:"Green", data:"#00FF00"},
{label:"Blue", data:"#0000FF"}];
// Declare an ArrayCollection variable for the colors.
// Make it Bindable so it can be used in bind
// expressions ({colorAC}).
[Bindable]
public var colorAC:ArrayCollection;
<mx:ComboBox dataProvider="{colorAC}"/>
<mx:ComboBox dataProvider="{stateAC}"/>
</mx:Application>
ADOBE FLEX 3 393
Adobe Flex 3 Developer Guide
This example uses a simple model. However, you can populate the model from an external data source or define
a custom data model class in ActionScript. For more information on using data models, see “Storing Data” on
page 1257.
You can use remote data providers to supply data to your ComboBox control. For example, when a web service
operation returns an Array of strings, you can use the following format to display each string as a row of a
ComboBox control:
<mx:ArrayCollection id=”resultAC”
source=”mx.utils.ArrayUtil.toArray(service.operation.lastResult);”
<mx:ComboBox dataProvider="{resultAC}" />
For more information on using remote data providers, see “Remote data in data provider components” on
page 180.
Key Description
Key Description
Page Down Displays the item that would be at the end bottom of the drop-down list. If the current selection is a multiple
of the rowCount value, displays the item that rowCount -1 down the list, or the last item. If the current selec-
tion is the last item in the data provider, does nothing.
Page Up Displays the item that would be at the top of the drop-down. If the current selection is a multiple of the
rowCount value, displays the item that rowCount -1 up the list, or the first item. If the current selection is the
first item in the data provider, does nothing.
When the drop-down list of a noneditable ComboBox control has focus, alphanumeric keystrokes move the
selection up and down the drop-down list to the next item with the same first character. You can also use the
following keys to control a drop-down list when it is open:
Key Description
Control+Up Closes the drop-down list and returns focus to the ComboBox control.
Enter Closes the drop-down list and returns focus to the ComboBox control.
Escape Closes the drop-down list and returns focus to the ComboBox control.
Page Down Moves to the bottom of the visible list. If the current selection is at the bottom of the list, moves the current selec-
tion to the top of the displayed list and displays the next rowCount-1 items, if any. If there current selection is the
last item in the data provider, does nothing.
Page Up Moves to the top of the visible list. If the current selection is at the top of the list, moves the current selection to
the bottom of the displayed list and displays the previous rowCount-1 items, if any. If the current selection is the
first item in the data provider, does nothing.
Shift+Tab Closes the drop-down list and moves the focus to the previous object in the DisplayList.
Tab Closes the drop-down list and moves the focus to the next object in the DisplayList.
DataGrid control
The DataGrid control is a list that can display more than one column of data. It is a formatted table of data that
lets you set editable table cells, and is the foundation of many data-driven applications.
For information on the following topics, which are often important for creating advanced data grid controls, see:
• How to format the information in each DataGrid cell and control how users enter data in the cells; see “Using
Item Renderers and Item Editors” on page 779.
• How to drag objects to and from the data grid; see “Using Drag and Drop” on page 741.
For complete reference information, see the Adobe Flex Language Reference.
Rows are responsible for rendering items. Each row is laid out vertically below the previous one. Columns are
responsible for maintaining the state of each visual column; columns control width, color, and size.
396 CHAPTER 12
The column names displayed in the DataGrid control are the property names of the Array Objects. By default, the
columns are in alphabetical order by the property names. Different Objects can define their properties in differing
orders. If an Array Object omits a property, the DataGrid control displays an empty cell in that row.
Specifying columns
Each column in a DataGrid control is represented by a DataGridColumn object. You use the columns property
of the DataGrid control and the <mx:DataGridColumn> tag to select the DataGrid columns, specify the order in
which to display them, and set additional properties. You can also use the DataGridColumn class visible
property to hide and redisplay columns, as described in “Hiding and displaying columns” on page 398.
For complete reference information for the <mx:DataGridColumn> tag, see DataGridColumn in the Adobe Flex
Language Reference.
You specify an Array element to the <mx:columns> child tag of the <mx:DataGrid> tag, as the following example
shows:
<?xml version="1.0"?>
<!-- dpcontrols/DataGridSpecifyColumns.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:DataGrid>
<mx:ArrayCollection>
<mx:Object Artist="Pavement" Price="11.99"
Album="Slanted and Enchanted" />
<mx:Object Artist="Pavement"
Album="Brighten the Corners" Price="11.99" />
</mx:ArrayCollection>
<mx:columns>
<mx:DataGridColumn dataField="Album" />
<mx:DataGridColumn dataField="Price" />
</mx:columns>
</mx:DataGrid>
</mx:Application>
In this example, you only display the Album and Price columns in the DataGrid control. You can reorder the
columns as well, as the following example shows:
<mx:columns>
<mx:DataGridColumn dataField="Price" />
<mx:DataGridColumn dataField="Album" />
</mx:columns>
In this example, you specify that the Price column is the first column in the DataGrid control, and that the Album
column is the second.
You can also use the <mx:DataGridColumn> tag to set other options. The following example uses the headerText
property to set the name of the column to a value different than the default name of Album, and uses the width
property to set the album name column wide enough to display the full album names:
<mx:columns>
<mx:DataGridColumn dataField="Album" width="200" />
398 CHAPTER 12
[Bindable]
public var initDG:ArrayCollection;
//Initialize initDG ArrayCollection variable from the Array.
//You can use this technique to convert an HTTPService,
ADOBE FLEX 3 399
Adobe Flex 3 Developer Guide
<mx:Form>
<mx:FormItem label="Column Index:">
<mx:Label id="clickColumn"/>
</mx:FormItem>
400 CHAPTER 12
For an example that sets an initial, multicolumn sort on a DataGrid, see “Example: Sorting a DataGrid on multiple
columns” on page 402.
<mx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.collections.*;
Keyboard navigation
The DataGrid control has the following keyboard navigation features:
Key Action
Enter When a cell is in editing state, commits change, and moves editing to the cell on the same column, next row down or
up, depending on whether Shift is pressed.
Return
Shift+Enter
Tab Moves focus to the next editable cell, traversing the cells in row order. If at the end of the last row, advances to the
next element in the parent container that can receive focus.
Shift+Tab Moves focus to the previous editable cell. If at the beginning of a row, advances to the end of the previous row. If at
the beginning of the first row, advances to the previous element in the parent container that can receive focus.
ADOBE FLEX 3 405
Adobe Flex 3 Developer Guide
Key Action
Up Arrow Home If editing a cell, shifts the cursor to the beginning of the cell’s text. If the cell is not editable, moves selection up one
item.
Page Up
Down Arrow If editing a cell, shifts the cursor to the end of the cell’s text. If the cell is not editable, moves selection down one item.
End
Page Down
Control Toggle key. If you set the DataGrid control allowMultipleSelection property to true, allows for multiple
(noncontiguous) selection and deselection. Works with key presses, click selection, and drag selection.
Shift Contiguous select key. If you set the DataGrid control allowMultipleSelection property to true, allows for
contiguous selections. Works with key presses, click selection, and drag selection.
Tree control
The Tree control lets a user view hierarchical data arranged as an expandable tree.
For complete reference information, see the Adobe Flex Language Reference. For information on hierarchical data
providers, see “Hierarchical data objects” on page 167.
For information on the following topics, which are often important for using advanced Tree controls, see:
• How to format the information in each Tree node and control how users enter data in the nodes; see “Using
Item Renderers and Item Editors” on page 779.
• How to drag objects to and from the Tree control; see “Using Drag and Drop” on page 741.
The following code contains a single Tree control that defines the tree shown in the image in “Tree control” on
page 405. This uses an XMLListCollection wrapper around an <mx:XMLList> tag. By using an XMLListCol-
lection, you can modify the underlying XML data provider by changing the contents of the MailBox XMLListC-
ollection, and the Tree control will represent the changes to the data. This example also does not use the
<mx:dataProvider> tag because dataProvider is the default property of the Tree control.
<?xml version="1.0"?>
<!-- dpcontrols/TreeSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Tree id="tree1" labelField="@label" showRoot="true" width="160">
<mx:XMLListCollection id="MailBox">
<mx:XMLList>
<folder label="Mail">
<folder label="INBOX"/>
<folder label="Personal Folder">
<Pfolder label="Business" />
<Pfolder label="Demo" />
<Pfolder label="Personal" isBranch="true" />
<Pfolder label="Saved Mail" />
</folder>
<folder label="Sent" />
<folder label="Trash" />
</folder>
</mx:XMLList>
</mx:XMLListCollection>
</mx:Tree>
</mx:Application>
The tags that represent tree nodes in the XML data can have any name. The Tree control reads the XML and builds
the display hierarchy based on the nested relationship of the nodes. For information on valid XML structure, see
“Hierarchical data objects” on page 167.
Some data providers have a single top level node, called a root node. Other data providers are lists of nodes and
do not have a root node. In some cases, you might not want to display the root node as the Tree root. To prevent
the tree from displaying the root node, specify the showRoot property to false; doing this does not affect the
data provider contents, only the Tree display. You can only specify a false showRoot property for data providers
that have roots, that is, XML and Object-based data providers.
A branch node can contain multiple child nodes, and, by default, appears as a folder icon with a disclosure triangle
that lets users open and close the folder. Leaf nodes appear by default as file icons and cannot contain child nodes.
When a Tree control displays a node of a non-XML data provider, by default, it displays the value of the label
property of the node as the text label. When you use an E4X XML-based data provider, however, you must specify
the label field, even if the label is identified by an attribute named “label”. To specify the label field, use the
labelField property; for example, if the label field is the label attribute, specify labelField="@label".
408 CHAPTER 12
<mx:Form>
<mx:FormItem label="Change Event:">
<mx:Label id="forChange" width="150"/>
</mx:FormItem>
<mx:FormItem label="Open Event:">
<mx:Label id="forOpen" width="150"/>
ADOBE FLEX 3 409
Adobe Flex 3 Developer Guide
</mx:FormItem>
</mx:Form>
</mx:Application>
In this example, you define event listeners for the change and itemOpen events. The Tree control broadcasts the
change event when the user selects a tree item, and broadcasts the itemOpen event when a user opens a branch
node. For each event, the event handler displays the label and the data property, if any, in a TextArea control.
You can programmatically walk down a Tree control’s nodes and open a node without knowing what depth you
are at in the Tree’s data provider. One way to do this is by using the children() method of a node’s XML object
to test whether the node has any children; you can use the expandItem() method to open the node.
The following example opens nodes in the Tree control based on the values of query string parameters. For
example, if you pass app_url?0=1&1=2&2=0 to the application, then Flex opens the second item at the top level
of the tree, the third item at the next level, and the first item at the third level of the tree (nodes are zero-based).
<?xml version="1.0"?>
<!-- dpcontrols/DrillIntoTree.mxml -->
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="initApp();">
<mx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
[Bindable]
private var treeData:XML =
<root>
<node label="Monkeys">
<node label="South America">
<node label="Coastal"/>
<node label="Inland"/>
</node>
<node label="Africa" isBranch="true"/>
<node label="Asia" isBranch="true"/>
</node>
<node label="Sharks">
<node label="South America" isBranch="true"/>
<node label="Africa" isBranch="true"/>
<node label="Asia" >
<node label="Coastal"/>
<node label="Inland"/>
</node>
</node>
</root>;
<mx:Tree id="myTree"
y="50"
width="221"
height="257"
horizontalCenter="0"
dataProvider="{treeData.node}"
labelField="@label"/>
</mx:Application>
<mx:Tree
folderOpenIcon="@Embed(source='open.jpg')"folderClosedIcon="@Embed(source='closed.jpg')"
defaultLeafIcon="@Embed(source='def.jpg')">
<mx:Script>
<![CDATA[
[Bindable]
[Embed(source="assets/radioIcon.jpg")]
public var iconSymbol1:Class;
[Bindable]
[Embed(source="assets/topIcon.jpg")]
public var iconSymbol2:Class;
]]>
</mx:Script>
<mx:Script>
<![CDATA[
[Bindable]
[Embed(source="assets/radioIcon.jpg")]
public var iconSymbol1:Class;
[Bindable]
[Embed(source="assets/topIcon.jpg")]
public var iconSymbol2:Class;
XMLTree1.expandItem(MailBox.getItemAt(0), true);
414 CHAPTER 12
XMLTree1.selectedIndex = 2;
}
]]>
</mx:Script>
<mx:XMLListCollection id="MailBox">
<mx:XMLList>
<node label="Mail" data="100">
<mx:Script>
<![CDATA[
ADOBE FLEX 3 415
Adobe Flex 3 Developer Guide
import mx.collections.XMLListCollection;
[Bindable]
private var company:XML =
<list>
<department title="Finance" code="200">
<employee name="John H"/>
<employee name="Sam K"/>
</department>
<department title="Operations" code="400">
<employee name="Bill C"/>
<employee name="Jill W"/>
</department>
<department title="Engineering" code="300">
<employee name="Erin M"/>
<employee name="Ann B"/>
</department>
</list>;
[Bindable]
private var companyData:XMLListCollection =
new XMLListCollection(company.department);
<mx:Tree id="tree"
top="72" left="50"
416 CHAPTER 12
dataProvider="{companyData}"
labelFunction="treeLabel"
height="225" width="300"
/>
<mx:VBox>
<mx:HBox>
<mx:Button label="Add Operations Employee" click="addEmployee();"/>
<mx:TextInput id="empName"/>
</mx:HBox>
<mx:Button label="Remove Selected Employee" click="removeEmployee();"/>
</mx:VBox>
</mx:Application>
Event Description
itemEditBegin Dispatched when the editedItemPosition property has been set and the cell can be edited.
itemEditEnd Dispatched when cell editing session ends for any reason.
itemFocusIn Dispatched when tree node gets the focus: when a user selects the label or tabs to it.
These events are commonly used in custom item editors. For more information see “Using Item Renderers and
Item Editors” on page 779.
ADOBE FLEX 3 417
Adobe Flex 3 Developer Guide
Key Description
Page Down
End
Page Up
Home
Enter Ends editing and moves selection to the next visible node, which can then be edited. At the last node, selects the
label.
Shift Enter Ends editing and moves selection to the previous visible node, which can then be edited. At the first node, selects
the label.
Escape Cancels the edit, restores the text, and changes the row state from editing to selected.
TAB When in editing mode, accepts the current changes, selects the row below, and goes into editing mode with the
label text selected. If at the last element in the tree or not in editing mode, sends focus to the next control.
Shift-TAB When in editing mode, accepts the current changes, selects the row above, and goes into editing mode. If at the
first element in the tree or not in editing mode, sends focus to the previous control.
Key Description
Down Arrow Moves the selection down one. When the Tree control gets focus, use the Down arrow to move focus to the
first node.
Right Arrow Opens a selected branch node. If a branch is already open, moves to the first child node.
Left Arrow Closes a selected branch node. If a leaf node or a closed branch node is currently selected, selects the parent
node.
418 CHAPTER 12
Key Description
Spacebar or * (Asterisk on Opens or closes a selected branch node (toggles the state).
numeric keypad)
Control + Arrow keys Moves the focus, but does not select a node. Use the Spacebar to select a node.
Topics
About containers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Using containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Using scroll bars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
Using Flex coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
Creating and managing component instances at run time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
About containers
A container defines a rectangular region of the drawing surface of Adobe® Flash® Player. Within a container, you
define the components, both controls and containers, that you want to appear within the container. Components
defined within a container are called children of the container. Adobe® Flex® provides a wide variety of containers,
ranging from simple boxes through panels and forms, to elements such as accordions or tabbed navigators that
provide built-in navigation among child containers.
At the root of a Flex application is a single container, called the Application container, that represents the entire
Flash Player drawing surface. This Application container holds all other containers and components.
A container has predefined rules to control the layout of its children, including sizing and positioning. Flex defines
layout rules to simplify the design and implementation of rich Internet applications, while also providing enough
flexibility to let you create a diverse set of applications.
Predefined layout rules also offer the advantage that your users soon grow accustomed to them. That is, by
standardizing the rules of user interaction, your users do not have to think about how to navigate the application,
but can instead concentrate on the content that the application offers.
Different containers support different layout rules:
• All containers, except the Canvas container, support automatic layout. With this type of layout you do not
specify the position of the children of the container. Instead, you control the positions by selecting the container
type; by setting the order of the container’s children; and by specifying properties, such as gaps, and controls, such
as Spacers. For example, to lay out children horizontally in a box, you use the HBox container.
• The Canvas container, and optionally the Application and Panel containers, use absolute layout, where you
explicitly specify the children’s x and y positions. Alternatively, you can use constraint-based layout to anchor the
sides, baseline, or center of the children relative to the parent.
Absolute layout provides a greater level of control over sizing and positioning than does automatic layout; for
example, you can use it to overlay one control on another. But absolute layout provides this control at the cost of
making you specify positions in detail.
For more information on layout, see “Sizing and Positioning Components” on page 185.
Using containers
The rectangular region of a container encloses its content area, the area that contains its child components. The
size of the region around the content area is defined by the container padding and the width of the container
border. A container has top, bottom, left, and right padding, each of which you can set to a pixel width. A container
also has properties that let you specify the type and pixel width of the border. The following image shows a
container and its content area, padding, and borders:
A B
A. Left padding B. Right padding C. Container D. Content area E. Top padding F. Bottom padding
Although you can create an entire Flex application by using a single container, typical applications use multiple
containers. For example, the following image shows an application that uses three layout containers:
A B
Components Components
B
In this example, the two VBox (vertical box) layout containers are nested within an HBox (horizontal box) layout
container and are referred to as children of the HBox container.
The HBox container arranges its children in a single horizontal row and oversees the sizing and positioning
characteristics of the VBox containers. For example, you can control the distance, or gap, between children in a
container by using the horizontalGap and verticalGap properties.
422 CHAPTER 13
A VBox container arranges its children in a single vertical stack, or column, and oversees the layout of its own
children. The following image shows the preceding example with the outermost container changed to a VBox
layout container:
Components
B
Components
B
In this example, the outer container is a VBox container, so it arranges its children in a vertical column.
The primary use of a layout container is to arrange its children, where the children are either controls or other
containers. The following image shows a simple VBox container that has three child components:
In this example, a user enters a ZIP code into the TextInput control, and then clicks the Button control to see the
current temperature for the specified ZIP code in the TextArea control.
ADOBE FLEX 3 423
Adobe Flex 3 Developer Guide
Flex supports form-based applications through its Form layout container. In a Form container, Flex can automat-
ically align labels, uniformly size TextInput controls, and display input error notifications. The following image
shows a Form container:
Form containers can take advantage of the Flex validation mechanism to detect input errors before the user
submits the form. By detecting the error, and letting the user correct it before submitting the form to a server, you
eliminate unnecessary server connections. The Flex validation mechanism does not preclude you from
performing additional validation on the server. For more information on Form containers, see “Form,
FormHeading, and FormItem layout containers” on page 484. For more information on validators, see “Validating
Data” on page 1267.
424 CHAPTER 13
Navigator containers, such as the TabNavigator and Accordion containers, have built-in navigation controls that
let you organize information from multiple child containers in a way that makes it easy for a user to move through
it. The following image shows an Accordion container:
A. Accordion buttons
You use the Accordion buttons to move among the different child containers. The Accordion container defines a
sequence of child panels, but displays only one panel at a time. To navigate a container, the user clicks on the
navigation button that corresponds to the child panel that they want to access.
Accordion containers support the creation of multistep procedures. The preceding image shows an Accordion
container that defines four panels of a complex form. To complete the form, the user enters data into all four
panels. Accordion containers let users enter information in the first panel, click the Accordion button to move to
the second panel, and then move back to the first if they want to edit the information. For more information, see
“Accordion navigator container” on page 538.
ADOBE FLEX 3 425
Adobe Flex 3 Developer Guide
Flex containers
The following table describes the Flex containers:
Accordion Navigator Organizes information in a series of child panels, “Accordion navigator container” on page 538
where one panel is active at any time.
Application Layout Holds components that provide global naviga- “ApplicationControlBar layout container” on
ControlBar tion and application commands. Can be docked page 479
at the top of an Application container.
Box (HBox and VBox) Layout Displays content in a uniformly spaced row or “Box, HBox, and VBox layout containers” on
column. An HBox container horizontally aligns page 476
its children; a VBox container vertically aligns its
children.
Canvas Layout Defines a container in which you must explicitly “Canvas layout container” on page 472
position its children.
ControlBar Layout Places controls at the lower edge of a Panel or “ControlBar layout container” on page 478
TitleWindow container.
DividedBox (HDivid- Layout Lays out its children horizontally or vertically, “DividedBox, HDividedBox, and VDividedBox
edBox and VDivid- much like a Box container, except that it inserts layout containers” on page 481
edBox) an adjustable divider between the children.
Form Layout Arranges its children in a standard form format. “Form, FormHeading, and FormItem layout
containers” on page 484
Grid Layout Arranges children as rows and columns of cells, “Grid layout container” on page 504
much like an HTML table.
Panel Layout Displays a title bar, a caption, a border, and its “Panel layout container” on page 509
children.
TabNavigator Navigator Displays a container with tabs to let users switch “TabNavigator container” on page 535
between different content areas.
Tile Layout Defines a layout that arranges its children in “Tile layout container” on page 513
multiple rows or columns.
TitleWindow Layout Displays a popup window that contains a title “TitleWindow layout container” on page 516
bar, a caption, border, a close button, and its
children. The user can move the container.
ViewStack Navigator Defines a stack of containers that displays a “ViewStack navigator container” on page 529
single container at a time.
426 CHAPTER 13
Sprite
UIComponent
Container
All Containers
All containers are derived from the ActionScript classes Sprite, UIComponent, and Container, and therefore
inherit the properties, methods, styles, effects, and events of their superclasses. Some containers are subclasses of
other containers; for example, the ApplicationControlBar is a subclass of the ControlBar container. For complete
reference information, see the Adobe Flex Language Reference.
Container example
The following image shows a Flex application that uses a Panel container with three child controls, where the
Panel container lays out its children vertically:
The only difference between these examples is the container type and the increased width of the Application
container caused by the horizontal layout, as the following code shows:
<?xml version="1.0"?>
<!-- containers\intro\Panel3ChildrenHoriz.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
Event overview
The following events are dispatched only by containers:
• childAdd Dispatched after a child is added to the container.
• childRemove Dispatched before a child is removed from the container.
• childIndexChange Dispatched after a child’s index in the container has changed.
• scroll Dispatched when the user manually scrolls the container.
428 CHAPTER 13
The first three events are dispatched for each of the container’s children, and the last is dispatched when the
container scrolls. For detailed information on these events, see Container in the Adobe Flex Language Reference.
The following events are dispatched only by Application containers:
• applicationComplete Dispatched after the application has been initialized, processed by the Layout-
Manager, and attached to the display list. This is the last event dispatched during an application’s startup sequence.
It is later than the application’s creationComplete event, which gets dispatched before the preloader has been
removed and the application has been attached to the display list.
• error Dispatched when an uncaught error occurs anywhere in the application.
The following events are dispatched by all components after they are added to or removed from a container:
• add Dispatched by a component after the component has been added to its container and the parent and the
child are in a consistent state. This event is dispatched after the container has dispatched the childAdd event and
all changes that need to be made as result of the addition have happened.
• remove Dispatched by a component after the component has been removed from its parent container. This
event is dispatched after the container has dispatched the childRemove event and all changes that need to be
made as result of the removal have happened.
Several events are dispatched for all components, but need special consideration for containers, particularly
navigator containers such as TabNavigator, where some children might not be created when the container is
created. These events include the following:
• preinitialize Dispatched when the component has been attached to its parent container, but before the
component has been initialized, or any of its children have been created. In most cases, this event is dispatched
too early for an application to use to configure a component.
• initialize Dispatched when a component has finished its construction and its initialization properties
have been set. At this point, all of the component’s immediate children have been created (they have at least
dispatched their preinitialize event), but they have not been laid out. Exactly when initialize events are
dispatched depends on the container’s creation policy.
• creationComplete Dispatched when the component, and all of its child components, and all of their
children, and so on have been created, laid out, and are visible.
For information on the initialize and creationComplete events, see “About the initialize and creationCom-
plete events” on page 429. For information on the remaining events, see Container in the Adobe Flex Language
Reference.
ADOBE FLEX 3 429
Adobe Flex 3 Developer Guide
OuterVBoxpreinitialize
InnerVBox1preinitialize
InnerVBox1Labelpreinitialize
InnerVBox1Labelinitialize
InnerVBox1initialize
InnerVBox2preinitialize
InnerVBox2Labelpreinitialize
InnerVBox2Labelinitialize
InnerVBox2initialize
OuterVBoxinitialize
InnerBox1LabelcreationComplete
InnerVBox2LabelcreationComplete
InnerVBox1creationComplete
InnerVBox2creationComplete
OuterVBoxcreationComplete
Notice that for the terminal controls, such as the Label controls, the controls are preinitialized and then immedi-
ately initialized. For containers, preinitialization starts with the outermost container and works inward on the first
branch, and then initialization works outward on the same branch. This process continues until all initialization
is completed. Then, the creationComplete event is dispatched first by the leaf components, and then by their
parents, and so on until the application dispatches the creationComplete event.
If you change the OuterVBox container to a ViewStack with a creationPolicy property set to auto, the events
would look as follows:
OuterViewStackpreinitialize
InnerVBox1preinitialize
InnerVBox2preinitialize
OuterViewStackinitialize
InnerBox1Labelpreinitialize
InnerBox1Labelinitialize
InnerVBox1initialize
InnerBox1LabelcreationComplete
InnerVBox1creationComplete
OuterViewStackcreationComplete
In this case, the second VBox is preinitialized only, because it does not have to be displayed. Notice that when a
navigator container dispatches the initialize event, its children exist and have dispatched the preinitialize
event, but its children have not dispatched the initialize event because they have not yet created their own
children. For more information on the creationPolicy property, see “Improving Startup Performance” on
page 91 in Building and Deploying Adobe Flex 3 Applications.
The initialize event is useful with a container that is an immediate child of a navigator container with an
ContainerCreationPolicy.AUTO creation policy. For example, by default, when a ViewStack is initialized, the
first visible child container dispatches an initialize event. Then, as the user moves to each additional child of
the container, the event gets dispatched for that child container.
The following example defines an event listener for the initialize event, which is dispatched when the user first
navigates to panel 2 of an Accordion container:
<?xml version="1.0"?>
ADOBE FLEX 3 431
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.controls.Alert;
public function pane2_initialize():void {
Alert.show("Pane 2 has been created.");
}
]]>
</mx:Script>
<mx:Accordion width="200" height="100">
<mx:VBox id="pane1" label="Pane 1">
<mx:Label text="This is pane 1."/>
</mx:VBox>
<mx:VBox id="pane2"
label="Pane 2"
initialize="pane2_initialize();">
<mx:Label text="This is pane 2."/>
</mx:VBox>
</mx:Accordion>
</mx:Application>
Disabling containers
All containers support the enabled property. By default, this property is set to true to enable user interaction
with the container and with the container’s children. If you set enabled to false, Flex dims the color of the
container and of all of its children, and blocks user input to the container and to all of its children.
The following image shows a Panel container with a Form container as its child:
For more information on the Panel container, see “Panel layout container” on page 509.
You can also define a ControlBar control as part of a Panel container. A ControlBar control defines an area at the
lower edge of the Panel container, below any children in the Panel container.
You can use the ControlBar container to hold components that might be shared by the other children in the Panel
container, or for controls that operate on the content of the Panel container. For example, you can use the
ControlBar container to display the subtotal of a shopping cart, where the shopping cart is defined in the Panel
container. For a product catalog, the ControlBar container can hold the Flex controls to specify quantity and to
add an item to a shopping cart. For more information on the ControlBar container, see “ControlBar layout
container” on page 478.
<?xml version="1.0"?>
<!-- containers\intro\ContainerDefaultB.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function submitLogin():void {
text1.text="You just tried to log in.";
}
]]>
</mx:Script>
A B
In this example, you use an HBox container to let users scroll an image, rather than rendering the complete image
at its full size:
<?xml version="1.0"?>
<!-- containers\intro\HBoxScroll.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
Note: If the clipContent property is false , a container lets its child extend past its boundaries. Therefore, no scroll
bars are necessary, and Flex never displays them, even if you set horizontalScrollPolicy and
verticalScrollPolicy to on.
<mx:Style>
HScrollBar, VScrollBar {
repeatDelay: 2000;
repeatInterval:1000;
436 CHAPTER 13
}
</mx:Style>
Coordinate Description
system
global Coordinates are relative to the upper-left corner of the Stage in Adobe Flash Player and Adobe® AIR™, that is, the outer-
most edge of the application.
The global coordinate system provides a universal set of coordinates that are independent of the component context.
Uses for this coordinate system include determining distances between objects and as an intermediate point in
converting between coordinates relative to a subcontrol into coordinates relative to a parent control.
The MouseEvent class includes stageX and stageY properties that are in the global coordinate system.
Flex uses the local coordinate system for mouse pointer locations; all components have mouseX and mouseY proper-
ties that use the local coordinate system.
The MouseEvent class includes localX and localY properties that are in the local coordinate system. Also, the Drag
Manager uses local coordinates in drag-and-drop operations. The doDrag() method’s xOffset and yOffset prop-
erties, for example, are offsets relative to the local coordinates.
content Coordinates are relative to the upper-left corner of the component’s content. Unlike the local and global coordinates,
the content coordinates include all of the component’s content area, including any regions that are currently clipped
and must be accessed by scrolling the component. Thus, if you scrolled down a Canvas container by 100 pixels, the
upper-left corner of the visible content is at position 0, 100 in the content coordinates.
You use the content coordinate system to set and get the positions of children of a container that uses absolute posi-
tioning. (For more information on absolute positioning, see “About component positioning” on page 187.)
The UIComponent contentMouseX and contentMouseY properties report the mouse pointer location in the
content coordinate system.
438 CHAPTER 13
The following image shows these coordinate systems and how they relate to each other.
A
content 0, 0
global 0, 0
local 0, 0
C
A. Content bounds B. Component bounds C. Stage bounds
• When you handle mouse events, it is best to use the coordinates from the MouseEvent object whenever
possible, because they represent the mouse coordinates at the time the event was generated. Although you can use
the container’s contentMouseX and contentMouseY properties to get the mouse pointer locations in the content
coordinate system, you should, instead, get the local coordinate values from the event object and convert them to
the content coordinate system.
• When you use local coordinates that are reported in an event object, such as the MouseEvent localX and
localY properties, you must remember that the event properties report the local coordinates of the mouse relative
to the event target. The target component can be a subcomponent of the component in which you determine the
position, such as a UITextField inside a Button component, not the component itself. In such cases, you must
convert the local coordinates into the global coordinate system first, and then convert the global coordinates into
the content coordinates container.
All Flex components provide two read-only properties and six methods that enable you to use and convert
between coordinate systems. The following table describes these properties and methods:
contentMouseX Returns the x position of the mouse, in the content coordinates of the component.
contentMouseY Returns the y position of the mouse, in the content coordinates of the component.
contentToGlobal Converts a Point object with x and y coordinates from the content coordinate system to the global
(point:Point):Point coordinate system.
contentToLocal Converts a Point object from the content coordinate system to the local coordinate system of the
(point:Point):Point component.
globalToContent Converts a Point object from the global coordinate system to the content coordinate system of the
(point:Point):Point component.
globalToLocal Converts a Point object from the global coordinate system to the local coordinate system of the
(point:Point):Point component.
localToContent Converts a Point object from the local coordinate system to the content coordinate system of the
(point:Point):Point component.
localToGlobal Converts a Point object from the local coordinate system to the global coordinate system.
(point:Point):Point
This example is somewhat artificial, in that production code would use the MouseEvent class stageX and stageY
properties, which represent the mouse position in the global coordinate system. The example uses the localX and
localY properties, instead, to show how you can convert between local and content coordinates, including how
first converting to using the global coordinates ensures the correct coordinate frame of reference.
<?xml version="1.0"?>
<!-- containers\intro\MousePosition.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="white">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
<mx:Canvas
width="150" height="150"
x="0" y="0"
backgroundColor="red">
<mx:Button label="I'm in Red"/>
</mx:Canvas>
<mx:Canvas
width="150" height="150"
x="150" y="0"
backgroundColor="green">
<mx:Button label="I'm in Green"/>
</mx:Canvas>
<mx:Canvas
width="150" height="150"
x="0" y="150"
backgroundColor="blue">
<mx:Button label="I'm in Blue"/>
</mx:Canvas>
<mx:Canvas
width="150" height="150"
x="150" y="150"
backgroundColor="magenta">
<mx:Button label="I'm in Magenta"/>
</mx:Canvas>
</mx:Canvas>
</mx:Application>
<mx:HBox id="myContainer">
<mx:Button click="clickHandler();"/>
<mx:TextInput/>
</mx:HBox>
You can access and modify a container’s child components at run time by using the addChild(), addChildAt(),
getChildren(), getChildAt(), getChildByName(), removeAllChildren(), removeChild(), and
removeChildAt() methods of the Container class. For example, you can iterate over all of the child componens
of a container, as the following example shows:
<?xml version="1.0"?>
<!-- containers\intro\VBoxNumChildren.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
// Import the Alert class.
import mx.controls.Alert;
<mx:Script>
<![CDATA[
import mx.controls.Button;
<mx:Script>
<![CDATA[
import mx.controls.Button;
<mx:HBox id="myHBox">
<mx:Button label="Add Button" click="addButton();"/>
</mx:HBox>
</mx:Application>
The following image shows the resulting application after the user presses the original (leftmost) button three
times:
ADOBE FLEX 3 445
Adobe Flex 3 Developer Guide
You use the removeChild() method to remove a control from a container. Flex sets the parent property of the
removed child. If the child is no longer referenced anywhere else in your application after the call to the
removeChild() method, it gets destroyed by a garbage collection process. The following example removes a
button from the application when the user presses it:
<?xml version="1.0"?>
<!-- containers\intro\ContainerRemoveChild.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function removeButton():void {
myHBox.removeChild(myButton);
}
<mx:HBox id="myHBox">
<mx:Button id="myButton"
label="Remove Me"
click="removeButton();"
/>
</mx:HBox>
<mx:Button label="Reset" click="resetApp();"/>
</mx:Application>
For additional methods that you can use with container children, see the Container class in the Adobe Flex
Language Reference.
<mx:Script>
<![CDATA[
<mx:VBox id="myVBox">
<mx:Button label="Add CheckBox"
click="addCB();"/>
<mx:Button label="Remove CheckBox"
click="delCB();"/>
</mx:VBox>
</mx:Application>
The following image shows the resulting application after the user presses the Add CheckBox button:
import mx.containers.HBox;
<mx:VBox>
<mx:Accordion id="myAcc" height="150" width="150">
<mx:HBox label="Initial HBox"/>
</mx:Accordion>
The following example modifies the example in “Example: Creating and removing a child of a VBox container”
on page 445. It uses the addChildAt() method to add the CheckBox control as the first child (index 0) of the
VBox. It also has a Reorder children button that uses the setChildIndex() method to move a CheckBox control
down the display list until it is the last the child in the VBox container. Boldface text indicates the lines that are
added to or changed from the previous example.
<?xml version="1.0"?>
<!-- containers\intro\ContainerComponentsReorder.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
// Import the CheckBox and Alert classes.
import mx.controls.CheckBox;
import mx.controls.Alert;
Topics
About the Application container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
About the Application object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457
Showing the download progress of an application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
Default padding 24 pixels for the top, bottom, left, and right properties.
452 CHAPTER 14
If you want to set a child container to fill the entire Application container, the easiest method is to set the child’s
MXML tag width and height properties to 100% (or, in ActionScript, set the percentWidth and
percentHeight properties to 100), and set the Application container padding to 0. If you base the child
container’s width and height properties on those of the Application container, you must subtract the Application
container’s padding, or your child container will be larger than the available space, and the application will have
scroll bars.
In the following example, the VBox container expands to fill all of the available space, except for the area defined
by the Application container padding:
<?xml version="1.0"?>
<!-- containers\application\AppVBoxSize.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="100" height="100">
<mx:VBox width="100%" height="100%" backgroundColor="#A9C0E7">
<!-- ... -->
</mx:VBox>
</mx:Application>
In the following example, the VBox container is larger than the available space within the Application container,
which results in scroll bars:
<?xml version="1.0"?>
<!-- containers\application\AppVBoxSizeScroll.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="100" height="100">
backgroundColor The color of the Stage area of Adobe® Flash® Player or Adobe® AIR™, which is visible during application
loading and initialization. This color is also visible if the application background is transparent. The
default value is 0x869CA7.
backgroundGradientColors [0x9CBOBA, 0x68808C], a grey background that is slightly darker at the bottom.
backgroundSize 100%. When you set this property at 100%, the background image takes up the entire Application
container.
horizontalAlign Centered.
paddingBottom 24 pixels.
paddingLeft 24 pixels.
paddingRight 24 pixels.
paddingTop 24 pixels.
You can override these default values in your application to define your own default style properties.
You can specify a gradient background for the application in two ways:
1 Set the backgroundGradientColors property to two values, as in the following example:
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"backgroundGradientColors="[0x0000FF,
0xCCCCCC]">
Flex calculates the gradient pattern between the two specified values.
2 Set the backgroundColor property to the desired value, as in the following example:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"backgroundColor="red">
Flex calculates the gradient pattern between a color slightly darker than red, and a color slightly lighter than
red.
To set a solid background to the application, specify the same two values to the backgroundGradientColors
property, as the following example shows:
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"backgroundGradientColors="[#FFFFFF, #FFFFFF]">
This example defines a solid white background.
The backgroundColor property specifies the background color of the Stage area in Flash Player, which is visible
during application loading and initialization, and a background gradient while the application is running. By
default, the backgroundColor property is set to 0x869CA7, which specifies a dark blue-grey color.
If you use the backgroundGradientColors property to set the application background, you should also set the
backgroundColor property to compliment the backgroundGradientColors property, as the following example
shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundGradientColors="[0x0000FF, 0xCCCCCC]"
backgroundColor="0x0000FF">
In this example, you use the backgroundGradientColors property to set a gradient pattern from a dark blue to
grey, and the backgroundColor property to set the Stage area in Flash Player to dark blue, which will be visible
during application loading and initialization.
frameRate Number Specifies the frame rate of the application, in frames per second. The default value is 24.
pageTitle String Specifies a String that appears in the title bar of the browser. This property provides the same
functionality as the HTML <title> tag.
preloader Path Specifies the path of a SWC component class or ActionScript component class that defines a
custom progress bar.
A SWC component must be in the same directory as the MXML file or in the WEB-
INF/flex/user_classes directory of your Flex web application.
For more information, see “Showing the download progress of an application” on page 462.
scriptRecursionLimit Number Specifies the maximum depth of the Flash Player or AIR call stack before Flash Player or AIR
stops. This is essentially the stack overflow limit.
scriptTimeLimit Number Specifies the maximum duration, in seconds, that an ActionScript event listener can execute
before Flash Player or AIR assumes that it has stopped processing and aborts it.
The default value is 60 seconds, which is also the maximum allowable value that you can set.
usePreloader Boolean Specifies whether to disable the application preloader (false) or not (true). The default
value is true. To use the default preloader, your application must be at least 160 pixels wide.
For more information, see “Showing the download progress of an application” on page 462.
Note: Properties frameRate, pageTitle, preloader, scriptRecursionLimit, and usePreloader, cannot be set in
ActionScript; they must be set in MXML code.
Flex provides the following properties that you can use to access parent documents:
mx.core.Application.application The top-level Application object, regardless of where in the document tree
your object executes.
mx.core.UIComponent.parentDocument The parent document of the current document. You can use
parentDocument.parentDocument to walk up the tree of multiple documents.
mx.core.UIComponent.parentApplication The Application object in which the current object exists. Flex
applications can load applications into applications, therefore, you can access the immediate parent application by
using this property. You can use parentApplication.parentApplication to walk up the tree of multiple appli-
cations.
<mx:Script>
<![CDATA[
// To refer to the members of the Application class,
// you must import mx.core.Application.
import mx.core.Application;
]]>
</mx:Script>
460 CHAPTER 14
</mx:Application>
To access the userName and call the getSalutation() method in your MXML components, you can use the
application property, as the following example from the MyComponent.mxml component shows:
<?xml version="1.0"?>
<!-- containers\application\myComponents\ButtonGetSalutation.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
<mx:Script>
<![CDATA[
/* To refer to the members of the Application class,
you must import mx.core.Application. */
import mx.core.Application;
]]>
</mx:Script>
<mx:Label id="myL"/>
<mx:Button label="Click Me"
click="myL.text=Application.application.getSalutation();"/>
</mx:VBox>
In this example, clicking the Button control executes the getSalutation() function to populate the Label
control.
ADOBE FLEX 3 461
Adobe Flex 3 Developer Guide
<mx:HBox/>
</mx:Accordion>
You use the parentDocument property in MXML scripts to go up a level in the chain of parent documents. You
can use the parentDocument to walk this chain by using multiple parentDocument properties, as the following
example shows:
parentDocument.parentDocument.doSomething();
The parentDocument property of the Application object is a reference to the application.
The parentDocument is typed as Object so that you can access properties and methods on ancestor Document
objects without casting.
Every UIComponent class has an isDocument property that is set to true if that UIComponent class is a
Document object, and false if it is not.
If a UIComponent class is a Document object, it has a documentDescriptor property. This is a reference to the
descriptor at the top of the generated descriptor tree in the generated Document class.
For example, suppose that AddressForm.mxml component creates a subclass of the Form container to define an
address form, and the MyApp.mxml component creates two instances of it: <AddressForm id="shipping"> and
<AddressForm id="billing">.
462 CHAPTER 14
In this example, the shipping object is a Document object. Its documentDescriptor property corresponds to the
<mx:Form> tag at the top of the AddressForm.mxml file (the definition of the component), while its descriptor
corresponds to the <AddressForm id="shipping"> tag in MyApp.mxml file (an instance of the component).
Walking the document chain by using the parentDocument property is similar to walking the application chain
by using the parentApplication property.
The download progress bar is not displayed if the SWF file is on your local host or if it is already cached. If the
SWF file is not on your local host and is not cached, the progress bar is displayed if less than half of the application
is downloaded after 700 milliseconds of downloading.
ADOBE FLEX 3 463
Adobe Flex 3 Developer Guide
Event Description
ProgressEvent.PROGRESS Dispatched when the application SWF file is being downloaded. The first PROGRESS event signifies
the beginning of the download process.
Event.COMPLETE Dispatched when the SWF file has finished downloading. Either zero or one COMPLETE event is
dispatched.
FlexEvent.INIT_COMPLETE Dispatched when the Flex application finishes initialization. This event is always dispatched once,
and is the last event that the Preloader dispatches.
The download progress bar must dispatch a COMPLETE event after it has received an
INIT_COMPLETE event. The COMPLETE event informs the Preloader that the download progress bar
has completed all operations and can be dismissed.
The download progress bar can perform additional tasks, such as playing an animation, after
receiving an INIT_COMPLETE event, and before dispatching the COMPLETE event. Dispatching the
COMPLETE event should be the last action of the download progress bar.
FlexEvent.INIT_PROGRESS Dispatched when the Flex application completes an initialization phase, as defined by calls to the
measure(), commitProperties(), or updateDisplayList() methods. This event describes
the progress of the application in the initialization phase.
RslEvent.RSL_LOADED Dispatched when an RSL finishes loading. The total bytes and total loaded bytes are included in the
event object. This event is dispatched for every RSL that is successfully loaded.
RSLEvent.RSL_PROGRESS Dispatched when an RSL is being downloaded. The first progress event signifies the beginning of the
RSL download.
The DownloadProgressBar class defines an event listener for all of these events. Within your override of the
DownloadProgressBar class, you can optionally override the default behavior of the event listener. If you create a
custom download progress bar as a subclass of the Sprite class, you must define an event listener for each of these
events.
Your example might define custom strings for the download progress bar, or set the minimum time that it appears,
as the following example shows:
package myComponents
{
import mx.preloaders.*;
import flash.events.ProgressEvent;
}
You can use your custom class in a Flex application, as the following example shows:
<?xml version="1.0"?>
<!-- containers\application\MainDPBMin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
preloader="myComponents.DownloadProgressBarSubClassMin">
package myComponents
{
import flash.display.*;
import flash.text.*;
import flash.utils.*;
import flash.events.*;
import mx.preloaders.*;
import mx.events.*;
preloader.addEventListener(
FlexEvent.INIT_PROGRESS, myHandleInitProgress);
preloader.addEventListener(
FlexEvent.INIT_COMPLETE, myHandleInitEnd);
}
The following example displays a SWF file as the download progress bar. This class must implement the IPreloa-
derDisplay interface.
package myComponents
{
import flash.display.*;
import flash.utils.*;
import flash.events.*;
import flash.net.*;
import mx.preloaders.*;
import mx.events.*;
preloader.addEventListener(
FlexEvent.INIT_PROGRESS, handleInitProgress);
preloader.addEventListener(
FlexEvent.INIT_COMPLETE, handleInitComplete);
}
// After the SWF file loads, set the size of the Loader control.
private function loader_completeHandler(event:Event):void
{
addChild(dpbImageControl);
dpbImageControl.width = 50;
dpbImageControl.height= 50;
dpbImageControl.x = 100;
dpbImageControl.y = 100;
}
Topics
About layout containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471
Canvas layout container. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
Box, HBox, and VBox layout containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
ControlBar layout container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
ApplicationControlBar layout container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479
DividedBox, HDividedBox, and VDividedBox layout containers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
Form, FormHeading, and FormItem layout containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484
Grid layout container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504
Panel layout container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
Tile layout container. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
TitleWindow layout container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
The following example shows a Canvas container with three LinkButton controls and three Image controls:
<mx:Canvas id="myCanvas"
height="200" width="200"
borderStyle="solid"
backgroundColor="white">
<mx:LinkButton label="Search"
x="10" y="30"
click="navigateToURL(new
URLRequest('http://www.adobe.com/cfusion/search/index.cfm'))"/>
<mx:Image
height="50" width="50"
x="100" y="10"
source="@Embed(source='assets/search.jpg')"
click="navigateToURL(new
URLRequest('http://www.adobe.com/cfusion/search/index.cfm'))"/>
<mx:LinkButton label="Help"
x="10" y="100"
click="navigateToURL(new URLRequest('http://www.adobe.com/go/gn_supp'))"/>
<mx:Image
height="50" width="50"
x="100" y="75"
source="@Embed(source='assets/help.jpg')"
click="navigateToURL(new URLRequest('http://www.adobe.com/go/gn_supp'))"/>
<mx:LinkButton label="Complaints"
x="10" y="170"
click="navigateToURL(
new URLRequest('http://www.adobe.com/go/gn_contact'))"/>
<mx:Image
height="50" width="50"
x="100" y="140"
source="@Embed(source='assets/complaint.jpg')"
click="navigateToURL(
new URLRequest('http://www.adobe.com/go/gn_contact'))"/>
474 CHAPTER 15
</mx:Canvas>
</mx:Application>
<mx:Canvas
width="150" height="150"
backgroundColor="#FFFFFF">
<mx:HBox id="hBox2"
left="30"
right="30"
y="50"
height="50"
backgroundColor="#A9C0E7">
</mx:HBox>
</mx:Canvas>
</mx:Application>
The example produces the following image:
In the following example, the size and position of each component is carefully calculated to ensure that none of
the components overlap:
<?xml version="1.0"?>
<!-- containers\layouts\CanvasOverlap.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="100" height="100"
backgroundGradientColors="[0xFFFFFF, 0xFFFFFF]">
<mx:Script>
<![CDATA[
[Embed(source="assets/BlackBox.jpg")]
[Bindable]
public var imgCls:Class;
]]>
</mx:Script>
If you set the width and height properties of one of the images to 20 pixels but don’t change the positions accord-
ingly, that image overlaps other images in the checkerboard. For example, if you replace the seventh <mx:Image>
tag in the preceding example with the following line, the resulting image looks like the following image:
<mx:Image source="{imgCls}" width="10" height="10" x="20" y="20"/>
<mx:Canvas
width="300" height="185"
backgroundColor="#FFFFFF">
<mx:TextInput id="text1"
text="Move me"
x="10" y="10"
/>
<mx:Button id="button1"
label="Move text1"
x="10" y="150"
click="text1.x=110; text1.y=110;"
/>
<mx:Button label="Reset" click="text1.x=10; text1.y=10;" x="111" y="150"/>
</mx:Canvas>
</mx:Application>
The following example shows one Box container with a horizontal layout and one with a vertical layout:
For complete reference information, see the Adobe Flex Language Reference.
<mx:Box direction="vertical"
borderStyle="solid"
paddingTop="10"
paddingBottom="10"
paddingLeft="10"
paddingRight="10">
<mx:VBox borderStyle="solid"
478 CHAPTER 15
paddingTop="10"
paddingBottom="10"
paddingLeft="10"
paddingRight="10">
For complete reference information, see the Adobe Flex Language Reference.
ADOBE FLEX 3 479
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
private function addToCart():void {
// Handle event.
}
]]>
</mx:Script>
<mx:ControlBar width="250">
<mx:Label text="Quantity"/>
<mx:NumericStepper/>
<!-- Use Spacer to push Button control to the right. -->
<mx:Spacer width="100%"/>
<mx:Button label="Add to Cart"
click="addToCart();"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
Typically, you place an ApplicationControlBar container at the top of the application, as the following example
shows:
If you dock the ApplicationControlBar container at the top of an application, it does not scroll with the application
contents.
For complete reference information, see the Adobe Flex Language Reference.
<mx:Script>
<![CDATA[
import mx.controls.Alert;
]]>
</mx:Script>
<mx:XMLList id="menuXML">
<menuitem label="File">
ADOBE FLEX 3 481
Adobe Flex 3 Developer Guide
In this example, the outermost container is a horizontal DividedBox container. The horizontal divider marks the
border between a Tree control and a vertical DividedBox container.
The vertical DividedBox container holds a DataGrid control (top) and a TextArea control (bottom). The vertical
divider marks the border between these two controls.
For complete reference information, see the Adobe Flex Language Reference.
<mx:Script>
<![CDATA[
private function myGrid_initialize():void {
myGrid.dataProvider = [
ADOBE FLEX 3 483
Adobe Flex 3 Developer Guide
When you specify a percentage value for the height or width properties of a child to make it resizable, Flex
initially sizes the child to the specified percentage, if possible. Then Flex can resize the child to take up all available
space.
You can use the dividers to resize a percentage-sized child up to its maximum size, or down to its minimum size.
To constrain the minimum size or maximum size of an area of the DividedBox, set an explicit value for the
minWidth and minHeight properties or the maxWidth and maxHeight properties of the children in that area.
About forms
Flex supports form development by using the Form layout container and several child components of the Form
container. The Form container lets you control the layout of a form, mark form fields as required or optional,
handle error messages, and bind your form data to the Flex data model to perform data checking and validation.
Also, you can apply style sheets to configure the appearance of your forms.
ADOBE FLEX 3 485
Adobe Flex 3 Developer Guide
You use three different components to create your forms, as the following example shows:
For complete reference information, see Form, FormHeading, and FormItem in the Adobe Flex Language
Reference.
Creating forms
You typically create a form by defining the following elements:
• The Form control
• FormHeading components, nested inside the Form control
• FormItem containers, nested inside the Form control
• Form fields, such as ComboBox and TextInput controls, nested inside the FormItem containers
You can also include other components inside a form, such as HRule controls, as needed.
486 CHAPTER 15
</mx:Form>
</mx:Application>
For complete reference information, see the Adobe Flex Language Reference.
</mx:Form>
</mx:Application>
For complete reference information, see the Adobe Flex Language Reference.
ADOBE FLEX 3 487
Adobe Flex 3 Developer Guide
In this example, you define three FormItem containers: one with the label First Name, one with the label Last
Name, and one with the label Address. The Address FormItem container holds two controls to let a user enter two
lines of address information. Each of the other two FormItem containers includes a single control.
For complete reference information, see FormItem in the Adobe Flex Language Reference.
<mx:Style>
.myFormItemLabelStyle {
color: #333399;
fontSize: 20;
}
</mx:Style>
<mx:Script>
<![CDATA[
private function processValues(zip:String, pn:String):void {
// Validate and process data.
}
]]>
</mx:Script>
<mx:FormItem>
<mx:Button label="Submit" id="mySubmitButton"
click="processValues(zipCode.text, phoneNumber.text);"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
<mx:Script>
<![CDATA[
private function submitForm():void {
// Handle the form submission.
}
]]>
</mx:Script>
</mx:FormItem>
<mx:FormItem label="Address">
<mx:TextInput id="addr1" width="100%"/>
<mx:TextInput id="addr2" width="100%"/>
</mx:FormItem>
<mx:FormItem label="Country">
<mx:ComboBox id="cntry">
<mx:ArrayCollection>
<mx:String>USA</mx:String>
<mx:String>UAE</mx:String>
<mx:String>UAW</mx:String>
</mx:ArrayCollection>
</mx:ComboBox>
</mx:FormItem>
<mx:FormItem>
<mx:HRule width="200" height="1"/>
<mx:Button label="Submit Form" click="submitForm();"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
A. Form container: labelWidth B. Form container: verticalGap = 6 C. FormItem container: verticalGap = 6 D. Form container: indica-
torGap = 14
ADOBE FLEX 3 491
Adobe Flex 3 Developer Guide
The following table describes the style properties that you use to control spacing and their default values:
indicatorGap Gap between the end of the area in the form 14 pixels
reserved for labels and the FormItem children
or FormHeading heading
labelWidth The width for the FormItem heading The width of the label text
indicatorGap Overrides the indicator gap set by the Determined by the <mx:Form> tag
<mx:Form> tag
492 CHAPTER 15
<mx:Script>
<![CDATA[
import flash.events.MouseEvent;
import mx.controls.Alert;
<mx:Form defaultButton="{mySubmitButton}">
<mx:FormItem label="Username">
<mx:TextInput id="username"
width="100"/>
</mx:FormItem>
<mx:FormItem label="Password">
<mx:TextInput id="password"
width="100"
displayAsPassword="true"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button id="mySubmitButton"
label="Login"
click="submitLogin(event);"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
Note: When the drop-down list of a ComboBox control is open, pressing Enter selects the currently highlighted item
in the ComboBox control; it does not activate the default button.
<mx:Form>
<mx:FormItem label="ZIP Code">
<mx:TextInput id="zipOptional"
width="100"/>
494 CHAPTER 15
</mx:FormItem>
<mx:Form>
<mx:FormItem label="Subscribe">
<mx:CheckBox label="Subscribe?"
click="emAddr.required=!emAddr.required;"/>
</mx:FormItem>
Flex provides a set of data validators for the most common types of data collected by a form. You can use Flex
validators with the following types of data.
• Credit card information
• Dates
• E-mail addresses
• Numbers
• Phone numbers
• Social Security Numbers
• Strings
• ZIP codes
As part of building your form, you can perform data validation by using your own custom logic, take advantage
of the Flex data validation mechanism, or use a combination of custom logic and Flex data validation.
The following sections include information on how to initiate validation in a form; for detailed information on
how to use Flex data validation, see “Validating Data” on page 1267.
<mx:Script>
<![CDATA[
private function processValues(zip:String, pn:String):void {
// Validate and process data.
}
]]>
</mx:Script>
<mx:Form id="myForm" defaultButton="{mySubmitButton}">
<mx:FormItem>
<mx:Button label="Submit" id="mySubmitButton"
click="processValues(zipCode.text, phoneNumber.text);"/>
</mx:FormItem>
496 CHAPTER 15
</mx:Form>
</mx:Application>
This example form defines two form controls: one for a ZIP code and one for a phone number. When you submit
the form, you call a function that takes the two arguments that correspond to the data stored in each control. Your
submit function can then perform any data validation on its inputs before processing the form data.
You don’t have to pass the data to the submit function. The submit function can access the form control data
directly, as the following example shows:
<?xml version="1.0"?>
<!-- containers\layouts\FormDataSubmitNoArg.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function processValues():void {
var inputZip:String = zipCode.text;
var inputPhone:String = phoneNumber.text;
// Check to see if pn is a number.
// Check to see if zip is less than 4 digits.
// Process data.
}
]]>
</mx:Script>
<mx:FormItem>
<mx:Button label="Submit" id="mySubmitButton"
click="processValues();"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
The technique of using the form fields directly, however, has the problem that the function is specific to the form
and cannot easily be used by other forms.
<mx:Script>
<![CDATA[
private function processValues():void {
var inputZip:String = zipCode.text;
var inputPhone:String = phoneNumber.text;
// Perform any additional validation.
// Process data.
}
]]>
</mx:Script>
<mx:ZipCodeValidator id="zcVal"
source="{zipCode}" property="text"
domain="US or Canada"/>
<mx:PhoneNumberValidator id="pnVal"
source="{phoneNumber}" property="text"/>
<mx:FormItem>
<mx:Button label="Submit" id="mySubmitButton"
click="processValues();"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
If you validate the input data every time the user enters it, you might not have to do so again in your submit
function. However, some validation in your submit function might still be necessary, especially if you want to
ensure that two fields are valid when compared with each other.
For example, you can use Flex validators to validate a ZIP code field and state field individually. But you might
want to validate that the ZIP code is valid for the specified state before submitting the form data. To do so, you
perform a second validation in the submit function.
For detailed information on using validators, see “Validating Data” on page 1267.
The following example defines a Flex data model that contains two values. The two values correspond to the two
input fields of a form.
<?xml version="1.0"?>
<!-- containers\layouts\FormDataModel.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- Define the submit function that validates and processes the data -->
<mx:Script>
<![CDATA[
private function processValues():void {
var inputZip:String = myFormModel.zipCodeModel;
var inputPhone:String = myFormModel.phoneNumberModel;
// Process data.
}
]]>
</mx:Script>
When the user enters data into the zipCode form field, Flex automatically copies that data to the data model. The
ZipCodeValidator validator gets invoked when the user exits the zipCode form field, as specified by the
validator’s trigger property and the default value of the triggerEvent property, valueCommit. Flex then draws
a red box around the zipCode field, as specified by the listener property.
When the user enters data into the phoneNumber form field, Flex automatically copies that data to the data model.
The PhoneNumberValidator validator gets invoked when the user clicks the Button control, as specified by the
validator’s trigger and triggerEvent properties. Flex then draws a red box around the phoneNumber field, as
specified by the listener property.
For detailed information on using validators, see “Validating Data” on page 1267.
<mx:Form>
<mx:FormItem label="First and Last Names">
<mx:TextInput id="firstName"/>
<mx:TextInput id="lastName"/>
</mx:FormItem>
<mx:FormItem label="Department">
<mx:TextInput id="dept" text="{myFormModel.department}"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
This department data is considered static because the form always shows the same value in the field. You could
also create a dynamic data model that takes the value of the department field from a web service, or calculates it
based on user input.
For more information on data models, see “Storing Data” on page 1257.
ADOBE FLEX 3 501
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
private function processValues():void {
// Check to see if ZIP code is valid.
WeatherService.GetWeather.send();
}
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="ZIP Code">
<mx:TextInput id="zipCode"
width="200"
text="ZIP code please."/>
<mx:Button
width="60"
label="Submit"
click="processValues();"/>
</mx:FormItem>
</mx:Form>
<mx:VBox>
<mx:TextArea
text=
502 CHAPTER 15
"{WeatherService.GetWeather.lastResult.CityShortName}"/>
<mx:TextArea
text=
"{WeatherService.GetWeather.lastResult.CurrentTemp}"/>
<mx:TextArea
text=
"{WeatherService.GetWeather.lastResult.DayForecast}"/>
</mx:VBox>
</mx:Application>
This example binds the form’s input zipCode field directly to the ZipCode field of the web service request. To
display the results from the web service, you bind the results to controls in a VBox container.
You have a great deal of flexibility when passing data to a web service. For example, you might modify this example
to bind the input form field to a data model, and then bind the data model to the web service request. For more
information on using web services, see “Accessing Server-Side Data with Flex” on page 1163.
You can also add event listeners for the web service to handle both a successful call to the web service, by using
the result event, and a call that generates an error, by using the fault event. An error condition might cause you
to display a message to the user with a description of the error. For a successful result, you might navigate to
another section of your application.
The following example adds a load event and a fault event to the form. In this example, the form is defined as
one child of a ViewStack container, and the form results are defined as a second child of the ViewStack container:
<?xml version="1.0"?>
<!-- containers\layouts\FormDataSubmitServerEvents.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
For more information on the TabNavigator, Accordion, and TitleWindow containers, see “Using Navigator
Containers” on page 529.
You can put zero or one child in each cell of a Grid container. If you include multiple children in a cell, put a
container in the cell, and then add children to the container. The height of all cells in a row is the same, but each
row can have a different height. The width of all cells in a column is the same, but each column can have a different
width.
You can define a different number of cells for each row or each column of the Grid container. In addition, a cell
can span multiple columns and/or multiple rows of the container.
If the default or explicit size of the child is larger than the size of an explicitly sized cell, the child is clipped at the
cell boundaries.
If the child’s default width or default height is smaller than the cell, the default horizontal alignment of the child
in the cell is left and the default vertical alignment is top. You can use the horizontalAlign and
verticalAlign properties of the <mx:GridItem> tag to control positioning of the child.
For complete reference information, see the Adobe Flex Language Reference. For information on the Tile
container, which creates a layout where all cells have the same size, see “Tile layout container” on page 513.
The <mx:GridItem> tag takes the following optional properties that control how the item is laid out:
rowSpan Number Property Specifies the number of rows of the Grid container spanned by the cell. The default value is 1. You
cannot extend a cell past the number of rows in the Grid container.
colSpan Number Property Specifies the number of columns of the Grid container spanned by the cell. The default value is 1.
You cannot extend a cell past the number of columns in the Grid container.
The following image shows a Grid container with three rows and three columns:
On the left, you see how the Grid container appears in Flash Player. On the right, you see the Grid container with
borders overlaying it to illustrate the configuration of the rows and columns. In this example, the buttons in the
first (top) row each occupy a single cell. The button in the second row spans three columns, and the button in the
third row spans the second and third columns.
You do not have to define the same number of cells for every row of a Grid container, as the following image shows.
The Grid container defines five cells in row one; row two has one item that spans three cells; and row 3 has one
empty cell, followed by an item that spans two cells.
The following MXML code creates the Grid container with three rows and three columns shown in the first image
in this section:
<?xml version="1.0"?>
<!-- containers\layouts\GridSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Grid id="myGrid">
<mx:GridItem>
<mx:Button label="Button 1"/>
</mx:GridItem>
<!-- Define the second cell of Row 1. -->
<mx:GridItem>
<mx:Button label="2"/>
</mx:GridItem>
<!-- Define the third cell of Row 1. -->
<mx:GridItem>
<mx:Button label="Button 3"/>
</mx:GridItem>
</mx:GridRow>
<!-- Define Row 2. -->
<mx:GridRow id="row2">
<!-- Define a single cell to span three columns of Row 2. -->
<mx:GridItem colSpan="3" horizontalAlign="center">
<mx:Button label="Long-Named Button 4"/>
</mx:GridItem>
</mx:GridRow>
<mx:Grid id="myGrid">
<mx:GridItem>
<mx:Button label="Button 3b"/>
</mx:GridItem>
</mx:GridRow>
</mx:Grid>
</mx:Application>
The following code shows the changes that were made to produce these results:
<?xml version="1.0"?>
<!-- containers\layouts\GridRowSpan.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Grid id="myGrid">
</mx:Grid>
</mx:Application>
This example makes several changes with the following effects:
• It sets the height of each row to 33% of the grid, ensuring that the rows have equal heights.
• It sets the rowSpan properties of the items with Buttons 3a and 3b to make them span two and three rows,
respectively.
• It sets the height properties of Buttons 3a and 3b to 100% to make these buttons fill all rows that they span.
If you omit this property on these buttons, Flex sets the buttons to their default height, so they do not appear to
span the rows.
ADOBE FLEX 3 509
Adobe Flex 3 Developer Guide
• It sets Button 5 to span three rows and sets a percentage-based width of 75%. In this example, the text requires
the button to fill the available width of the three columns, so Flex sizes the button to the default size that fits the
text, not the requested 75%. If you omit the width property, the result is identical. To see the effect of the
percentage width specification, keep the specification and shorten the label text; the button then spans three-
quarters of the three columns, centered on the middle column.
The resulting grid has the several additional characteristics. Although the second row definition specifies only a
single <mx:GridItem> tag that defines a cell spanning three columns, Flex automatically creates two additional
cells to allow Buttons 3a and 3b to expand into the row. The third row also has five cells. The first cell is defined
by the empty <mx:gridItem/> tag. The second through fourth cells are defined by the GridItem that contains
Button 5, which spans three columns. The fifth column is created because the last item in the first row spans all
three rows.
The following example shows a Panel container with a Form container as its child:
For complete reference information, see the Adobe Flex Language Reference.
<mx:Form width="300">
<mx:FormHeading label="Billing Information"/>
<!-- Form contents goes here -->
</mx:Form>
</mx:Panel>
</mx:Application>
ADOBE FLEX 3 511
Adobe Flex 3 Developer Guide
You specify the <mx:ControlBar> tag as the last child tag of an <mx:Panel> tag, as the following example shows:
<?xml version="1.0"?>
<!-- containers\layouts\PanelCBar.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function addToCart():void {
// Handle event.
}
]]>
</mx:Script>
<mx:HBox width="100%">
<!-- Area for your catalog. -->
</mx:HBox>
<mx:ControlBar width="100%">
512 CHAPTER 15
<mx:Label text="Quantity"/>
<mx:NumericStepper id="myNS"/>
<!-- Use Spacer to push Button control to the right. -->
<mx:Spacer width="100%"/>
<mx:Button label="Add to Cart" click="addToCart();"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
For more information on the ControlBar container, see “ControlBar layout container” on page 478.
You can also add the ControlBar container dynamically to a Panel container, as the following example shows:
<?xml version="1.0"?>
<!-- containers\layouts\PanelCBarDynamicAdd.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.containers.ControlBar;
import mx.controls.*;
import flash.events.MouseEvent;
myCB.percentWidth=100;
myCB.addChild(myLabel);
myCB.addChild(myNS);
myCB.addChild(mySpacer);
myCB.addChild(myButton);
}
}
<mx:Panel id="myPanel"
title="My Application"
paddingTop="10" paddingBottom="10"
paddingLeft="10" paddingRight="10"
width="300">
<mx:HBox width="100%">
<!-- Area for your catalog. -->
</mx:HBox>
<mx:Button label="Add ControlBar" click="addCBHandler();"/>
</mx:Panel>
</mx:Application>
The following image shows examples of horizontal and vertical Tile containers:
For complete reference information, see Tile in the Adobe Flex Language Reference.
<mx:Tile id="myFlow"
direction="horizontal"
borderStyle="solid"
paddingTop="10" paddingBottom="10"
paddingRight="10" paddingLeft="10"
verticalGap="15" horizontalGap="10">
<mx:Tile id="myFlow"
direction="horizontal"
borderStyle="solid"
paddingTop="10" paddingBottom="10"
paddingRight="10" paddingLeft="10"
verticalGap="15" horizontalGap="10"
tileWidth="100">
For complete reference information, see TitleWindow in the Adobe Flex Language Reference.
ADOBE FLEX 3 517
Adobe Flex 3 Developer Guide
Argument Description
class A reference to the class of object you want to create, typically a custom MXML component that implements a
TitleWindow container.
modal (Optional) A Boolean value that indicates whether the window is modal, and takes all mouse input until it is
closed (true), or whether interaction is allowed with other controls while the window is displayed ( false). The
default value is false.
Note: Flex continues executing code in the parent even after you create a modal pop-up window.
You can also create a pop-up window by passing an instance of a TitleWindow class or custom component to the
PopUpManager addPopUp() method. For more information, see “Using the addPopUp() method” on page 527.
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
518 CHAPTER 15
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import mx.core.IFlexDisplayObject;
import myComponents.MyLoginForm;
var helpWindow:IFlexDisplayObject =
PopUpManager.createPopUp(this, MyLoginForm, false);
}
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import mx.core.IFlexDisplayObject;
import myComponents.MyLoginForm;
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import myComponents.MyLoginForm;
import mx.core.IFlexDisplayObject;
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"showCloseButton="true"
close="PopUpManager.removePopUp(this);">
If you need to clean up, before closing the TitleWindow control, create an event listener function for the close
event and close the TitleWindow from within that handler, as the following example shows:
<?xml version="1.0"?>
<!-- containers\layouts\myComponents\MyLoginFormRemoveMe.mxml -->
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
showCloseButton="true"
close="removeMe();">
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
</mx:TitleWindow>
You can also use the PopUpManager mouseDownOutside event to close the pop-up window when a user clicks
the mouse outside the TitleWindow. To do this, you add an event listener to the TitleWindow instance for the
mouseDownOutside event, as the following example shows:
<?xml version="1.0"?>
<!-- containers\layouts\MainMyLoginFormMouseDown.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import mx.containers.TitleWindow;
import myComponents.MyLoginForm;
import mx.events.FlexMouseEvent;
</mx:VBox>
</mx:Application>
You define the event listener in the main application, and then assign it to the pop-up window when you create it.
This technique lets you use a generic pop-up window, defined by the component MyLoginForm.mxml, and then
modify the behavior of the component by assigning event listeners to it from the main application.
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import myComponents.ArrayEntryForm;
<mx:Script>
<![CDATA[
import mx.controls.TextInput;
import mx.managers.PopUpManager;
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
// Variables whose values are set by the main application.
// Data provider array for the component's ComboBox control.
[Bindable]
public var myArray:Array;
]]>
</mx:Script>
</mx:TitleWindow>
The main application defines the event listeners and registers them with the controls defined within the pop-up
window:
<?xml version="1.0"?>
<!-- containers\layouts\MainArrayEntryFormEvents.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import flash.events.Event;
import myComponents.ArrayEntryFormEvents;
<mx:VBox>
<mx:TextInput id="ti1" text=""/>
ADOBE FLEX 3 527
Adobe Flex 3 Developer Guide
</mx:VBox>
<mx:Button id="b1" label="Select File Type" click="displayForm();"/>
</mx:Application>
<mx:Script>
<![CDATA[
import mx.containers.TitleWindow;
import flash.events.*;
import mx.managers.PopUpManager;
import mx.controls.Button;
import mx.core.IFlexDisplayObject;
// The method to create and add the Button child control to the
// TitleWindow container.
public function populateWindow():void {
var btn1:Button = new Button();
528 CHAPTER 15
btn1.label="close";
btn1.addEventListener(MouseEvent.CLICK, closeTitleWindow);
myTitleWindow.addChild(btn1);
}
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import mx.controls.TextArea;
import mx.core.IFlexDisplayObject;
Topics
About navigator containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
ViewStack navigator container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
TabNavigator container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535
Accordion navigator container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538
The following image shows the stacked child containers in a ViewStack container:
A B
A. Child container 1 active B. Child container 0 active
On the left, you see a ViewStack container with the first child active. The index of a child in a ViewStack container
is numbered from 0 to n - 1, where n is the number of child containers. The container on the right is a ViewStack
container with the second child container active.
For complete reference information, see ViewStack in the Adobe Flex Language Reference.
The following example uses ActionScript to set the selectedChild property so that the active child container
is the child container with an identifier of search:
myViewStack.selectedChild=search;
3 numChildren Contains the number of child containers in the ViewStack container.
The following example uses the numChildren property in an ActionScript statement to set the active child
container to the last container in the stack:
myViewStack.selectedIndex=myViewStack.numChildren-1;
Note: The default creation policy for all containers, except the Application container, is the policy of the parent
container. The default policy for the Application container is auto. In most cases, therefore, the View Stack control’s
children are not created until they are selected. You cannot set the selectedChild property to a child that is not yet
created.
The following example creates a ViewStack container with three child containers. The example also defines three
Button controls that when clicked, select the active child container:
<?xml version="1.0"?>
<!-- containers\navigators\VSSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Button id="cInfoButton"
label="Customer Info Screen"
click="myViewStack.selectedChild=custInfo;"/>
<mx:Button id="aInfoButton"
label="Account Info Screen"
click="myViewStack.selectedChild=accountInfo;"/>
</mx:HBox>
<!-- Define the ViewStack and the three child containers and have it
resize up to the size of the container for the buttons. -->
<mx:ViewStack id="myViewStack"
borderStyle="solid" width="100%">
The items in the LinkBar control correspond to the values of the label property of each child of the ViewStack
container, as the following example shows:
<?xml version="1.0"?>
<!-- containers\navigators\VSLinkBar.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox>
<!-- Create a LinkBar control to navigate
the ViewStack container. -->
<mx:LinkBar dataProvider="{myViewStack}" borderStyle="solid"/>
<!-- Define the ViewStack and the three child containers. -->
<mx:ViewStack id="myViewStack"
borderStyle="solid"
width="100%">
</mx:Canvas>
<mx:VBox>
<mx:LinkBar dataProvider="{myViewStack}"
borderStyle="solid"
backgroundColor="#EEEEFF"/>
<mx:ViewStack id="myViewStack"
borderStyle="solid"
width="100%"
creationCompleteEffect="{myWR}">
<mx:Canvas id="search"
label="Search"
hideEffect="{myWD}"
showEffect="{myWU}">
<mx:Label text="Search Screen"/>
</mx:Canvas>
<mx:Canvas id="custInfo"
label="Customer Info"
hideEffect="{myWD}"
showEffect="{myWU}">
<mx:Label text="Customer Info"/>
</mx:Canvas>
<mx:Canvas id="accountInfo"
label="Account Info"
hideEffect="{myWD}"
showEffect="{myWU}">
<mx:Label text="Account Info"/>
</mx:Canvas>
</mx:ViewStack>
</mx:VBox>
</mx:Application>
Notice that the showEffect property of a container is only triggered when the container’s visibility changes from
false to true. Therefore, you use the creationCompleteEffect property to trigger the effect when Flex first
creates the component.
ADOBE FLEX 3 535
Adobe Flex 3 Developer Guide
TabNavigator container
A TabNavigator container creates and manages a set of tabs, which you use to navigate among its children. The
children of a TabNavigator container are other containers. The TabNavigator container creates one tab for each
child. When the user selects a tab, the TabNavigator container displays the associated child, as the following image
shows:
The TabNavigator container is a child class of the ViewStack container and inherits much of its functionality. For
complete reference information, see the Adobe Flex Language Reference.
<mx:VBox label="Accounts"
width="300"
height="150">
<!-- Accounts view goes here. -->
</mx:VBox>
<mx:VBox label="Stocks"
width="300"
height="150">
<!-- Stocks view goes here. -->
</mx:VBox>
<mx:VBox label="Futures"
width="300"
height="150">
<!-- Futures view goes here. -->
</mx:VBox>
</mx:TabNavigator>
</mx:Application>
You can also set the currently active child by using the selectedChild and selectedIndex properties inherited
from the ViewStack container as follows:
• numChildren The index of the currently active container if one or more child containers are defined. The
index is numbered from 0 to numChildren - 1, where numChildren is the number of child containers in the
TabNavigator container. Set this property to the index of the container that you want active.
• selectedChild The currently active container, if one or more child containers are defined. This property
is null if no child containers are defined. Set this property to the identifier of the container that you want active.
You can set this property only in an ActionScript statement, not in MXML.
For more information on the selectedChild and selectedIndex properties, including examples, see
“ViewStack navigator container” on page 529.
You use the showEffect and hideEffect properties of the children of a TabNavigator container to specify an
effect to play when the user changes the currently active child. The following example plays the WipeLeft effect
each time the selected tab changes:
<?xml version="1.0"?>
<!-- containers\navigators\TNEffect.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:WipeLeft id="myWL"/>
<mx:TabNavigator>
<mx:VBox label="Accounts"
width="300"
height="150"
showEffect="{myWL}">
ADOBE FLEX 3 537
Adobe Flex 3 Developer Guide
<mx:VBox label="Stocks"
width="300"
height="150"
showEffect="{myWL}">
<!-- Stocks view goes here. -->
<mx:Text text="This is a text control."/>
</mx:VBox>
<mx:VBox label="Futures"
width="300"
height="150"
showEffect="{myWL}">
<!-- Futures view goes here. -->
<mx:Text text="This is a text control."/>
</mx:VBox>
</mx:TabNavigator>
</mx:Application>
Key Action
Down Arrow Gives focus to the next tab, wrapping from last to first, without changing the selected child.
Right Arrow
Up Arrow Gives focus to the previous tab, wrapping from first to last, without changing the selected child.
Left Arrow
Page Down Selects the next child, wrapping from last to first.
Enter Selects the child associated with the tab displaying focus.
Spacebar
Flex includes the Accordion navigator container, which can greatly improve the look and navigation of a form.
The Accordion container defines a sequence of child panels, but displays only one panel at a time. The following
image shows an example of an Accordion container:
To navigate a container, the user clicks the navigation button that corresponds to the child panel that they want to
access. Accordion containers let users access the child panels in any order to move back and forth through the
form. For example, when the user is in the Credit Card Information panel, they might decide to change the infor-
mation in the Billing Address panel. To do so, they navigate to the Billing Address panel, edit the information, and
then navigate back to the Credit Card Information panel.
In HTML, a form that contains shipping address, billing address, and credit card information is often imple-
mented as three separate pages, which requires the user to submit each page to the server before moving on to the
next. An Accordion container can organize the information on three child panels with a single Submit button.
This architecture minimizes server traffic and lets the user maintain a better sense of progress and context.
Note: An empty Accordion container with no child panels cannot take focus.
Although Accordion containers are useful for working with forms and Form containers, you can use any Flex
component within a child panel of an Accordion container. For example, you could create a catalog of products
in an Accordion container, where each panel contains a group of similar products.
540 CHAPTER 16
For complete reference information, see Accordion in the Adobe Flex Language Reference.
</mx:Form>
</mx:Accordion>
</mx:Application>
This example defines each child panel by using a Form container. However, you can use any container to define a
child panel.
Note: You can use any container to define child panels. However, some containers do not belong in child panels, such
as a TabNavigator container because it has no child components, or an Accordion container.
ADOBE FLEX 3 541
Adobe Flex 3 Developer Guide
Key Action
Down Arrow Gives focus to the next button, wrapping from last to first, without changing the selected child.
Right Arrow
Up Arrow Gives focus to the previous button, wrapping from first to last, without changing the selected child.
Left Arrow
Page Up Moves to the previous child panel, wrapping from first to last.
Page Down Moves to the next child panel, wrapping from last to first.
Enter Selects the child associated with the tab displaying focus.
Spacebar
Property Description
numChildren Contains the total number of child panels defined in an Accordion container.
selectedIndex The index of the currently active child panel. Child panels are numbered from 0 to numChildren - 1. Setting the
selectedIndex property changes the currently active panel.
selectedChild The currently active child container if one or more child containers are defined. This property is null if no child
containers are defined. Set this property to the identifier of the container that you want active. You can set this
property only in an ActionScript statement, not in MXML.
For more information on these properties, see “ViewStack navigator container” on page 529.
542 CHAPTER 16
You can use the following two Button controls, for example, in the second panel of an Accordion container, panel
number 1, to move back to panel number 0 or ahead to panel number 2:
<?xml version="1.0"?>
<!-- containers\navigators\AccordionButtonNav.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
</mx:Form>
</mx:Accordion>
</mx:Application>
You can also use relative location with navigation buttons. The following Button controls move forward and
backward through Accordion container panels based on the current panel number:
<mx:Button id="backButton" label="Back"click="accordion1.selectedIndex =
accordion1.selectedIndex - 1;"/>
<mx:Button id="nextButton" label="Next"click="accordion1.selectedIndex =
accordion1.selectedIndex + 1;"/>
For the Next Button control, you also can use the selectedChild property to move to the next panel based on
the value of the id property of the panel’s container, as the following code shows:
<mx:Button id="nextButton" label="Next"
click="accordion1.selectedChild=creditCardInfo;"/>
The following Button control opens the last panel in the Accordion container:
<mx:Button id="lastButton" label="Last" click="accordion1.selectedIndex =
accordion1.numChildren - 1;"/>
ADOBE FLEX 3 543
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
public function setButtonStyles():void {
comp.getHeaderAt(0).setStyle('color', 0xAA0000);
comp.getHeaderAt(1).setStyle('color', 0x00AA00);
}
]]>
</mx:Script>
<mx:Accordion id="comp">
<mx:VBox label="First VBox">
<mx:TextInput/>
<mx:Button label="Button 1"/>
</mx:VBox>
<mx:VBox label="Second VBox">
<mx:TextInput/>
<mx:Button label="Button 2"/>
</mx:VBox>
544 CHAPTER 16
</mx:Accordion>
</mx:Application>
You can also control the appearance of the buttons by using the headerStyleName style property of the
Accordion class. For more information, see Accordion in the Adobe Flex Language Reference.
545
Topics
About behaviors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
Applying behaviors in MXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554
Applying behaviors in ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
Working with effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
About behaviors
A behavior is a combination of a trigger paired with an effect. A trigger is an action, such as a mouse click on a
component, a component getting focus, or a component becoming visible. An effect is a visible or audible change
to the target component that occurs over a period of time, measured in milliseconds. Examples of effects are
fading, resizing, or moving a component.
You can define multiple effects to play in response to a single trigger. For example, a pet store application might
contain a Button control to select a pet category. When the user clicks the Button control, a window that contains
breed names becomes visible. As the window becomes visible, it moves to the bottom-left corner of the screen,
and it resizes from 100 by 100 pixels to 300 by 300 pixels (the effects).
By default, Adobe® Flex® components do not play an effect when a trigger occurs. To configure a component to
use an effect, you associate an effect with a trigger.
Note: Triggers are not the same as events. For example, a Button control has both a mouseDown event and a
mouseDownEffect trigger. The event initiates the corresponding effect trigger when a user clicks on a component.
You use the mouseDown event property to specify the event listener that executes when the user clicks on the
component. You use the mouseDownEffect trigger property to associate an effect with the trigger.
546 CHAPTER 17
</mx:Application>
This example still uses an event to invoke the effect. To play an effect programmatically, you call the effect’s
play() method. For information on using ActionScript to configure and invoke effects, and for more information
on using MXML, see “Applying behaviors in MXML” on page 554.
The following diagram shows the class hierarchy of the Flex effect classes:
Effect
EffectInstance
As this diagram shows, there is a corresponding instance class for each factory class.
When you use effects, you perform the following steps.
1 Create a factory class object.
2 Configure the factory class object.
When Flex plays an effect, Flex performs the following actions:
3 Creates one object of the instance class for each target component of the effect.
4 Copies configuration information from the factory object to the instance object.
5 Plays the effect on the target using the instance object.
6 Deletes the instance object when the effect completes.
Any changes that you make to the factory object are not propagated to a currently playing instance object.
However, the next time the effect plays, the instance object uses your new settings.
ADOBE FLEX 3 549
Adobe Flex 3 Developer Guide
When you use effects in your application, you are concerned only with the factory class; the instance class is an
implementation detail. However, if you want to create custom effects classes, you must implement a factory and
an instance class. For more information, see “Effects” on page 199 in Creating and Extending Adobe Flex 3 Compo-
nents.
Available effects
The following table lists the effects that Flex supports:
Effect Description
AnimateProperty Animates a numeric property of a component, such as height, width, scaleX, or scaleY. You specify the prop-
erty name, start value, and end value of the property to animate. The effect first sets the property to the start
value, and then updates the property value over the duration of the effect until it reaches the end value.
For example, if you want to change the width of a Button control, you can specify width as the property to
animate, and starting and ending width values to the effect.
Blur Applies a blur visual effect to a component. A Blur effect softens the details of an image. You can produce blurs
that range from a softly unfocused look to a Gaussian blur, a hazy appearance like viewing an image through
semi-opaque glass.
The Blur effect uses the Flash BlurFilter class as part of its implementation. For more information, see
flash.filters.BlurFilter in the Adobe Flex Language Reference.
If you apply a Blur effect to a component, you cannot apply a BlurFilter or a second Blur effect to the component.
Dissolve Modifies the alpha property of an overlay to gradually have to target component appear or disappear.
• alphaFrom Specifies the initial alpha level (0.0= transparent, 1.0 =fully opaque). If omitted, Flex uses the
component’s current alpha level.
• color Value that represents the color of the overlay rectangle that the effect displays over the target
object. The default value is the color specified by the target component’s backgroundColor style property,
or 0xFFFFFF, if backgroundColor is not set.
If the target object is a container, only the children of the container dissolve. The container borders do not
dissolve.
Note: To use the Dissolve effect with the creationCompleteEffect trigger of a DataGrid control, you must
define the data provider of the control inline using a child tag of the DataGrid control, or using data binding. This
issue is a result of the data provider not being set until the creationComplete event is dispatched. Therefore,
when the effect starts playing, Flex has not completed the sizing of the DataGrid control.
550 CHAPTER 17
Effect Description
Fade Animate the component from transparent to opaque, or from opaque to transparent.
• alphaFrom Specifies the initial alpha level (0.0= transparent, 1.0 =fully opaque). If omitted, Flex uses the
component’s current alpha level.
If you specify the Fade effect for the showEffect or hideEffect trigger, and if you omit the alphaFrom and
alphaTo properties, the effect automatically transitions from 0.0 to the targets’ current alpha value for a show
trigger, and from the targets’ current alpha value to 0.0 for a hide trigger.
Note: To use the Fade effect with text, you must use an embedded font, not a device font. For more information,
see “Using Styles and Themes” on page 589.
Glow Applies a glow visual effect to a component. The Glow effect uses the Flash GlowFilter class as part of its imple-
mentation. For more information, see the flash.filters.GlowFilter class in the Adobe Flex Language Reference.
If you apply a Glow effect to a component, you cannot apply a GlowFilter or a second Glow effect to the compo-
nent.
Iris Animates the effect target by expanding or contracting a rectangular mask centered on the target. The effect can
either grow the mask from the center of the target to expose the target, or contract it toward the target center to
obscure the component.
Effect Description
Move Changes the position of a component over a specified time interval. You typically apply this effect to a target in a
container that uses absolute positioning, such as Canvas, or one with "layout=absolute", such as Application
or Panel. If you apply it to a target in a container that performs automatic layout, such as a VBox or Grid container,
the move occurs, but the next time the container updates its layout, it moves the target back to its original posi-
tion. You can set the container's autoLayout property to false to disable the move back, but that disables
layout for all controls in the container.
• xFrom and yFrom Specifies the initial position of the component. If omitted, Flex uses the current position.
• xBy and yBy Specifies the number of pixels to move the component in the x and y directions. Values can
be positive or negative.
For the xFrom, xTo, and xBy properties, you can specify any two of the three values; Flex calculates the third. If
you specify all three properties, Flex ignores the xBy property. The same is true for the yFrom, yTo, and yBy prop-
erties.
If you specify a Move effect for a trigger, and if you do not set the six From, To, and By properties, Flex sets them
to create a smooth transition between the object’s old position and its new position.
When the Move effect runs, the layout around the component that is moving does not readjust. Setting a
container’s autoLayout property to true has no effect on this behavior.
Pause Does nothing for a specified period of time. This effect is useful when you need to composite effects. For more
information, see “Creating composite effects” on page 567.
Resize Changes the width and height of a component over a specified time interval.
• widthFrom and heightFrom Specifies the initial width and height. If omitted, Flex uses the current size.
• widthBy and heightBy Specifies the number of pixels to modify the size as either a positive or negative
number relative to the initial width and height.
For widthFrom, widthTo, and widthBy, you can specify any two of the three values, and Flex calculates the
third. If you specify all three, Flex ignores widthBy. The same is true for heightFrom, heightTo, and heightBy.
If you specify a Resize effect for a resize trigger, and if you do not set the six From, To, and By properties, Flex sets
them to create a smooth transition between the object’s old size and its new size.
When you apply a Resize effect, the layout manager resizes neighboring components based on the size changes
to the target component. To run the effect without resizing other components, place the target component in a
Canvas container.
When you use the Resize effect with Panel containers, you can hide Panel children to improve performance. For
more information, see “Improving performance when resizing Panel containers” on page 586.
552 CHAPTER 17
Effect Description
Rotate Rotates a component around a specified point. You can specify the coordinates of the center of the rotation, and
the starting and ending angles of rotation. You can specify positive or negative values for the angles.
• angleFrom and angleTo Specifies the initial rotation and final rotation angles.
• originX and originY Specifies coordinate of the center point of the rotation.
Note: To use the Rotate effect with text, you must use an embedded font, not a device font. For more information,
see “Using Styles and Themes” on page 589.
SoundEffect Plays an MP3 audio file. For example, you could play a sound when a user clicks a Button control. This effect lets
you repeat the sound, select the source file, and control the volume and pan.
You specify the MP3 file using the source property. If you have already embedded the MP3 file, using the
Embed keyword, then you can pass the Class object of the MP3 file to the source property. Otherwise, specify the
full URL to the MP3 file.
WipeLeft Defines a bar Wipe effect. The before or after state of the component must be invisible.
WipeRight
WipeUp These effects have the following property:
WipeDown
• showTarget If true, causes the component to appear. If false, causes the component to disappear. The
default value is true.
If you specify a Wipe effect for a showEffect or hideEffect trigger, by default, Flex sets the showTarget
property to true if the component is invisible, and false if the component is visible.
• zoomHeightFrom, zoomWidthFrom Specifies a number that represents the scale at which to start the
zoom. The default value is 0.0.
• zoomHeightTo, zoomWidthTo Specifies a number to zoom to. The default value is 1.00. Specify a value
of 2.0 to double the size of the target.
• originX, originY The x-position and y-position of the origin, or registration point, of the zoom. The
default value is the coordinates of the center of the effect target.
Note: When you apply a Zoom effect to text rendered using a system font, Flex scales the text between whole
point sizes. Although you do not have to use embedded fonts when you apply a Zoom effect to text, the Zoom
will appear smoother when you apply it to embedded fonts. For more information, see “Using Styles and Themes”
on page 589.
ADOBE FLEX 3 553
Adobe Flex 3 Developer Guide
Available triggers
You use a trigger name to assign an effect to a target component. You can reference a trigger name as a property
of an MXML tag, in the <mx:Style> tag, or in an ActionScript setStyle() and getStyle() function. Trigger
names use the following naming convention:
triggerEventEffect
where triggerEvent is the event that invokes the effect. For example, the focusIn event occurs when a
component gains focus; you use the focusInEffect trigger property to specify the effect to invoke for the
focusIn event. The focusOut event occurs when a component loses focus; the corresponding trigger property is
focusOutEffect.
The following table lists the effect name that corresponds to each trigger:
hideEffect Component becomes invisible by changing the visible property of the component from true
to false.
mouseDownEffect User presses the mouse button while the mouse pointer is over the component.
showEffect Component becomes visible by changing the visible property of the component from false
to true.
554 CHAPTER 17
</mx:Application>
In the next example, you create two Resize effects for a Button control. One Resize effect expands the size of the
button by 10 pixels when the user clicks down on the button, and the second resizes it back to its original size when
the user releases the mouse button. The duration of each effect is 200 ms.
<?xml version="1.0"?>
<!-- behaviors\ButtonResize.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Resize id="myResizeUp"
widthBy="50" heightBy="50"
duration="200"
/>
<mx:Resize id="myResizeDown"
widthBy="-50" heightBy="-50"
duration="200"
/>
<mx:Button id="myButton"
label="Click Me"
mouseDownEffect="{myResizeUp}"
mouseUpEffect="{myResizeDown}"
/>
</mx:Application>
<mx:Zoom id="mZoom"
zoomHeightTo="{Number(zoomHeightInput.text)}"
zoomWidthTo="{Number(zoomWidthInput.text)}"
/>
<mx:Form>
<mx:FormItem label="Zoom Height:">
<mx:TextInput id="zoomHeightInput" text="1.0" width="30"/>
</mx:FormItem>
<mx:FormItem label="Zoom Width:">
<mx:TextInput id="zoomWidthInput" text="1.0" width="30"/>
</mx:FormItem>
</mx:Form>
<mx:Style>
TextArea { mouseDownEffect: slowWipe; }
</mx:Style>
<mx:TextArea id="myTA"
text="This TextArea slowly wipes in."
/>
<mx:TextArea id="myTA2"
text="This TextArea control has no effect."
mouseDownEffect="none"
/>
</mx:Application>
Setting the mouseDownEffect property in a component tag overrides any settings that you make in an
<mx:Style> tag. If you want to remove the associated effect defined in a type selector, you can explicitly set the
value of any trigger to none, as the following example shows:
556 CHAPTER 17
</mx:Application>
</mx:Application>
For more information on working with styles, see “Using Styles and Themes” on page 589.
resizeLarge.heightTo=150;
resizeLarge.duration=750;
}
]]>
</mx:Script>
<mx:VBox borderStyle="solid">
<mx:HBox>
<mx:Button label="Start" click="resizeLarge.end();resizeLarge.play();"/>
<mx:Button label="Reset" click="myTA.width=100;myTA.height=100;"/>
</mx:HBox>
<mx:TextArea id="myTA" height="100" width="100" text="Here is some text."/>
</mx:VBox>
</mx:Application>
In this example, use the application’s creationComplete event to configure the effect, and then invoke it by
calling the play() method in response to a user clicking the Button control. Because you invoke the effect
programmatically, you do not need an event trigger to invoke it.
Notice that this example first calls the Effect.end() method before it calls the play() method. You call the
end() method before you call the play() method to ensure that any previous instance of the effect has ended
before you start a new one.
This example also defines the effect using ActionScript. You are not required to define the effect in ActionScript.
You could rewrite this code using MXML to define the effect, as the following example shows:
<?xml version="1.0"?>
<!-- behaviors\MxmlPlay.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Resize id="resizeLarge"
target="{myTA}"
widthTo="150"
heightTo="150"
duration="750"
/>
Optionally, you can pass an Array of targets to the play() method to invoke the effect on all components specified
in the Array, as the following example shows:
resizeLarge.play([comp1, comp2, comp3]);
This example invokes the Zoom effect on three components. Notice that the end() method does not take an effect
target as an argument but an effect instance. Therefore, you end this effect by calling the end() method on the
effect itself, as the following example shows:
resizeLarge.end();
When you call the play() method, you essentially replace the effect trigger with the method call. You use the
Effect.target or Effect.targets properties to specify the target components of an effect when you invoke
them using the play() method. This example uses the target property of the effect to specify the single target
component. If you want to play the effect on multiple components, you can use the Effects.targets property
to specify an array of target components. For more information, see “Applying behaviors using the Effect.target
and Effect.targets properties” on page 563.
Rather than using the target property to specify the target component of the effect, you can also pass the target
component to the constructor, as the following example shows:
// Create a Resize effect.
var resizeLarge = new mx.effects.Resize(myTA);
Ending an effect
You can use the end() method to terminate an effect at any time, as the following example shows:
<?xml version="1.0"?>
<!-- behaviors\ASend.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="createEffect(event);"
>
<mx:Script>
<![CDATA[
// Import effect class.
import mx.effects.Resize;
You can also use the stop() method with an effect. The stop() method halts the effect in its current state, but
does not jump to the end state. A call to the stop() method dispatches the effectEnd event. Unlike a call to the
pause() method, you cannot call the resume() method after calling the stop() method. However, you can call
the play() method to restart the effect.
</mx:Application>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initializeEffect(event);"
>
<mx:Script>
<![CDATA[
import flash.events.Event;
private function initializeEffect(eventObj:Event):void {
myB.setStyle("mouseDownEffect", myWL);
}
]]>
</mx:Script>
<mx:WipeLeft id="myWL" duration="1000"/>
<mx:Script>
<![CDATA[
<mx:Button id="myButton"
label="Click Me"
click="changeEffect();"
mouseUpEffect="{myWL}"/>
</mx:Application>
<?xml version="1.0"?>
<!-- behaviors\TargetProp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Zoom id="myZoom"
zoomHeightFrom="0.10" zoomWidthFrom="0.10"
zoomHeightTo="1.00" zoomWidthTo="1.00"
target="{myButton}"/>
<mx:Button id="myButton"
label="Zoom target"
click="myZoom.end();myZoom.play();"/>
</mx:Application>
In this example, you use data binding to the target property to specify that the Button control is the target of the
Zoom effect. However, you do not associate the effect with a trigger, so you must call the effect’s play() method
to invoke it.
In the next example, you apply a Zoom effect to multiple Button controls by using data binding with the effect’s
targets property:
<?xml version="1.0"?>
<!-- behaviors\TargetProp3Buttons.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Zoom id="myZoom"
zoomHeightFrom="0.10"
zoomWidthFrom="0.10"
zoomHeightTo="1.00"
zoomWidthTo="1.00"
targets="{[myButton1, myButton2, myButton3]}"
/>
<mx:Button id="myButton4"
label="Zoom targets"
click="myZoom.end();myZoom.play();"
/>
</mx:Application>
You do not define a trigger to invoke the effect, so you must call the effect’s play() method to invoke it. Because
you specified three targets to the effect, the play() method invokes the effect on all three Button controls.
You can also set the target and targets properties in ActionScript, as the following example shows:
<?xml version="1.0"?>
<!-- behaviors\TargetPropAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="createEffect(event);"
>
<mx:Script>
<![CDATA[
import mx.effects.Fade;
import flash.events.Event;
ADOBE FLEX 3 565
Adobe Flex 3 Developer Guide
<mx:Zoom id="myZoom"
duration="2000"
zoomHeightFrom="0.10"
zoomWidthFrom="0.10"
zoomHeightTo="1.00"
zoomWidthTo="1.00"
/>
<mx:Panel id="myPanel1">
<mx:TextArea id="myTA"/>
</mx:Panel>
<mx:Panel id="myPanel2">
<mx:Button id="myButton" label="Click Me" click="playZoom(event);"/>
</mx:Panel>
</mx:Application>
In this example, you use the targets property of the Fade effect to specify the two Panel containers as the effect
target, and the target property of the Zoom effect to specify the Button control as the single target.
If you use the targets property to define multiple event targets, and you want to later use the end() method to
terminate the effect, you must save the return value of the play() method and pass it as an argument to the end()
method, as the following example shows:
var myFadeArray:Array = myFade.play();
Then you can pass the array to the end() method to end the effect on all targets, as the following example shows:
myFade.end(myFadeArray);
566 CHAPTER 17
<mx:Style>
@font-face {
src:url("../assets/MyriadWebPro.ttf");
font-family: myMyriadWebPro;
}
</mx:Style>
<mx:VBox>
<mx:VBox borderStyle="solid">
<mx:Label id="l1"
ADOBE FLEX 3 567
Adobe Flex 3 Developer Guide
fontFamily="myMyriadWebPro"
mouseDownEffect="{rotateForward}"
mouseUpEffect="{rotateBack}"
text="Embedded font. This text will rotate."
/>
</mx:VBox>
<mx:VBox borderStyle="solid">
<mx:Label id="l2"
mouseDownEffect="{rotateForward}"
mouseUpEffect="{rotateBack}"
text="System font. This text will not rotate."
/>
</mx:VBox>
</mx:VBox>
</mx:Application>
<mx:Parallel id="ZoomRotateShow">
<mx:Zoom id="myZoomShow"
zoomHeightFrom="0.0"
zoomWidthFrom="0.0"
zoomHeightTo="1.0"
zoomWidthTo="1.0"
/>
<mx:Rotate id="myRotateShow"/>
</mx:Parallel>
<mx:Sequence id="ZoomRotateHide">
<mx:Rotate id="myRotateHide"/>
<mx:Zoom id="myZoomHide"
zoomHeightFrom="1.0"
zoomWidthFrom="1.0"
zoomHeightTo="0.0"
zoomWidthTo="0.0"
/>
</mx:Sequence>
<mx:VBox id="myBox" height="100" width="200">
<mx:TextArea id="aTextArea"
568 CHAPTER 17
text="Hello world."
hideEffect="{ZoomRotateHide}"
showEffect="{ZoomRotateShow}"
/>
</mx:VBox>
<mx:Button id="myButton1"
label="Show!"
click="aTextArea.visible=true;"
/>
<mx:Button id="myButton2"
label="Hide!"
click="aTextArea.visible=false;"
/>
</mx:Application>
The event listenr for the click event for the Button control alternates making the VBox container visible and
invisible. When the VBox container becomes invisible, it uses the ZoomRotateShow effect as its hide effect, and
when it becomes invisible, it uses the ZoomRotateHide effect.
Notice that the VBox container sets the autoLayout property to false. This setting prevents Flex from updating
the layout of the container while the effect is playing. For more information, see “Disabling container layout for
effects” on page 584.
You can nest <mx:Parallel> and <mx:Sequence> tags inside each other. For example, two effects can run in
parallel, followed by a third effect running in sequence.
In a Parallel or Sequence effect, the duration property sets the duration of each effect. For example, if the a
Sequence effect has its duration property set to 3000, then each effect in the Sequence will take 3000 ms to play.
You can also create an event listener that combines effects into a composite effect, and then plays the composite
effect, as the following example shows:
<?xml version="1.0"?>
<!-- behaviors\CompositeEffectsAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="createEffect(event);">
<mx:Script>
<![CDATA[
<mx:Button id="myButton1"
label="Show!"
click="aTextArea.visible=true; ZRShow.end(); ZRShow.play();"/>
</mx:Application>
In this example, you use the Parallel.addChild() method to add each effect to the Parallel effect, and you then
invoke the effect using the Effect.play() method.
Repeating effects
All effects support the Effect.repeatCount and Effect.repeatDelay properties that let you configure
whether effects repeat, where:
• repeatCount Specifies the number of times to play the effect. A value of 0 means to play the effect indefi-
nitely until stopped by a call to the end() method. The default value is 1. For a repeated effect, the duration
property specifies the duration of a single instance of the effect. Therefore, if an effect has a duration property
set to 2000, and a repeatCount property set to 3, then the effect takes a total of 6000 ms (6 seconds) to play.
• repeatDelay Specifies the amount of time, in milliseconds, to pause before repeating the effect. The default
value is 0.
For example, the following example repeats the Rotate effect until the user clicks a Button control:
<?xml version="1.0"?>
<!-- behaviors\RepeatEff.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Rotate id="myRotate"
repeatCount="0"/>
The ViewStack and TabNavigator containers are each made up of a collection of child containers that let you select
the currently visible child container. When you change the currently visible child container, you can use the
hideEffect property of the container being hidden and the showEffect property of the newly visible child
container to apply effects to the child containers.
The ViewStack or TabNavigator container waits for the hideEffect of the child container being hidden to
complete before it reveals the new child container. You can interrupt a currently playing effect if you change the
selectedIndex property of the ViewStack or TabNavigator container while an effect is playing.
For more information on the ViewStack and TabNavigator container, see “Using Navigator Containers” on
page 529.
Using Dissolve and Fade effects with the Panel, TitleWindow, and Accordion
containers
The Fade and Dissolve effects are only applied to the content area of the Panel, TitleWindow, and Accordion
containers. Therefore, the title bar of the Panel and TitleWindow containers, and the navigation buttons of the
Accordion container are not modified by these effects.
To apply the Fade or Dissolve effect to the entire container, create a RoundedRectange instance that is the same
size as the container, and then use the targetArea property of the effect to specify the area on which to apply the
effect. In the following example, you apply a Dissolve effect to the first Panel container, and apply a Dissolve effect
to a RoundedRectange instance overlaid on top of the second Panel container:
<?xml version="1.0" encoding="utf-8"?>
<!-- behaviors\PanelDissolve.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init();">
<mx:Script>
<![CDATA[
import mx.graphics.*;
<mx:Dissolve id="dissolveP1"
duration="1000"
target="{panel1}"
alphaFrom="1.0" alphaTo="0.0"/>
572 CHAPTER 17
<!-- Apply the effect to the bounding box, not to Panel 2. -->
<mx:Dissolve id="dissolveP2"
duration="1000"
target="{panel2}"
alphaFrom="1.0" alphaTo="0.0"
targetArea="{tArea}"/>
<mx:Script>
<![CDATA[
<mx:SoundEffect id="soundEmbed"
useDuration="false"
loops="0"
source="{soundClass}"/>
<mx:Button id="myButton2"
label="Sound Embed"
mouseDownEffect="{soundEmbed}"/>
</mx:Application>
ADOBE FLEX 3 573
Adobe Flex 3 Developer Guide
In this example, you embed the sound1.mp3 file in your application. That means the file is compiled into the SWF
file.
The SoundEffect class has several properties that you can use to control the playback of the MP3 file, including
useDuration and loops. The useDuration property specifies whether to use the duration property to control
the play time of the MP3 file. If the useDuration property is true, the MP3 file will play for as long as the time
specified by the duration property, which defaults to 500 ms. If you set useDuration to false, the MP3 file
plays to completion.
The loops property specifies the number of times to repeat the MP3 file, where a value of 0 means play the effect
once, a value of 1 means play the effect twice, and so on. If you repeat the MP3 file, it still uses the setting of the
useDuration property to determine the playback time.
The duration property takes precedence over the loops property. If the effect duration is not long enough to play
the sound at least once, then the sound will not loop.
The SoundEffect class also defines the following events:
complete Dispatched when the sound file completes loading.
id3 Dispatched when ID3 data is available for an MP3 sound file.
ioError Dispatched when an error occurs during the loading of the sound file.
progress Dispatched periodically as the sound file loads. Within the event object, you can access the number of
bytes currently loaded and the total number of bytes to load. The event is not guaranteed to be dispatched, which
means that the complete event might be dispatched without any progress events being dispatched.
For more information, see the Adobe Flex Language Reference.
Often, you use these effects with the showEffect and hideEffect triggers. The showEffect trigger occurs when
a component becomes visible by changing its visible property from false to true. The hideEffect trigger
occurs when the component becomes invisible by changing its visible property from true to false. When
using a mask effect with the showEffect or hideEffect triggers, you can ignore the showTarget property; Flex
sets it for you automatically.
As the mask effect executes, the effect either covers the target component or uncovers it, based on the setting of
the showTarget property. The following diagram shows the action of the WipeLeft effect for the two different
settings of the showTarget property:
showTarget=false showTarget=true
initial mask
mask
effect completed
mask
mask direction
You can use several properties of the MaskEffect class to control the location and size of the mask, including the
following:
scaleXFrom, scaleYFrom, scaleXTo, and scaleX Specify the initial and final scale of the mask where a value of 1.0
corresponds to scaling the mask to the size of the target component, 2.0 scales the mask to twice the size of the
component, 0.5 scales the mask to half the size of the component, and so on. To use any one of these properties,
you must specify all four.
xFrom, yFrom, xTo, and yTo Specify the coordinates of the initial position and final position of the mask relative
to the target component, where (0, 0) corresponds to the upper-left corner of the target. To use any one of these
properties, you must specify all four.
The coordinates of the initial and final position of the mask depend on the type of effect and whether the
showTarget property is true or false. For example, for the WipeLeft effect with a showTarget value of false,
the coordinates of the initial mask position are (0, 0), corresponding to the upper-left corner of the target, and the
coordinates of the final position are the upper-right corner of the target (-width, 0), where width is the width of
the target.
For a showTarget value of true for the WipeLeft effect, the coordinates of the initial mask position are (width,
0), and the coordinates of the final position are (0, 0).
ADOBE FLEX 3 575
Adobe Flex 3 Developer Guide
return myMask;
}
Your custom mask function takes an argument that corresponds to the target component of the effect, and a
second argument that defines the dimensions of the target so that you can correctly size the mask. The function
returns a single Shape object that defines the mask.
The following example uses a custom mask with a WipeLeft effect:
<?xml version="1.0"?>
<!-- behaviors\CustomMaskSimple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
<mx:WipeLeft id="standardWL"
showTarget="false"/>
576 CHAPTER 17
<mx:HBox borderStyle="solid"
paddingLeft="10" paddingRight="10"
paddingTop="10" paddingBottom="10">
</mx:HBox>
</mx:Application>
<mx:Script>
<![CDATA[
import mx.effects.*;
import mx.events.EffectEvent;
import mx.core.UIComponent;
<?xml version="1.0"?>
<!-- behaviors\EventEffects.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
import mx.effects.*;
import mx.events.EffectEvent;
import mx.core.UIComponent;
<mx:Fade id="slowFade"
duration="2000"
effectEnd="endSlowFadeEffectListener(event);"/>
• A response may arrive from the server while the effect is playing, and the application must process the
response while the effect is still playing.
<mx:Script>
import mx.effects.easing.*;
</mx:Script>
<mx:Accordion
openEasingFunction="{Bounce.easeOut}"
openDuration="2000">
<mx:VBox label="Pane 1" width="400" height="400"/>
<mx:VBox label="Pane 2" width="400" height="400"/>
</mx:Accordion>
</mx:Application>
<mx:Script>
<![CDATA[
private function myEasingFunction(t:Number, b:Number,
c:Number, d:Number):Number {
if ((t /= d) < (1 / 2.75)) {
return c * (7.5625 * t * t) + b;
}
else if (t < (2 / 2.75)) {
return c * (7.5625 * (t-=(1.5/2.75)) * t + .75) + b;
}
else if (t < (2.5 / 2.75)) {
return c * (7.5625 * (t-=(2.25/2.75)) * t + .9375) + b;
}
else {
return c * (7.5625 * (t-=(2.625/2.75)) * t + .984375) + b;
}
};
]]>
</mx:Script>
<mx:Move id="moveLeftShow"
xFrom="600" xTo="0" yTo="0"
duration="3000"
easingFunction="myEasingFunction"/>
<mx:Move id="moveRightHide"
xFrom="0" xTo="600"
duration="3000"
easingFunction="myEasingFunction"/>
<mx:LinkBar dataProvider="myVS"/>
<mx:ViewStack id="myVS" borderStyle="solid">
<mx:Canvas id="Canvas0" label="Canvas0"
creationCompleteEffect="{moveLeftShow}"
showEffect="{moveLeftShow}"
hideEffect="{moveRightHide}" >
ADOBE FLEX 3 581
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.effects.DefaultListEffect;
import mx.collections.ArrayCollection;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection(
['A','B','C','D','E']);
<mx:List id="list0"
width="150"
dataProvider="{myDP}"
variableRowHeight="true"
fontSize="24"
ADOBE FLEX 3 583
Adobe Flex 3 Developer Guide
allowMultipleSelection="true"
itemsChangeEffect="{myDLE}"
/>
<mx:Button
label="Delete Item"
click="deleteItem();"
/>
<mx:Button
label="Add Item"
click="addItem();"
/>
</mx:Application>
To use a data effect with the TileList class, apply the DefaultTileListEffect effect to the control. When an item in
the TileList control is removed, this effect first fades out the item, and then moves the remaining items to their
new position. When you add an item to the TileList control, this effect moves the existing items to their new
position, and then fades in the new item.
You typically set the offscreenExtraRowsOrColumns property of the TileList control when you apply a data
effect. This property specifies the number of extra rows or columns of offscreen item renderers used in the layout
of the control. This property is useful because data effects work by first determining a before layout of the list-
based control, then determining an after layout, and finally setting the properties of the effect to create an
animation from the before layout to the after layout. Because many effects cause currently invisible items to
become visible, or currently visible items to become invisible, this property configures the control to create the
offscreen item renderers so that they already exist when the data effect plays.
You typically set the offscreenExtraRowsOrColumns property to a nonzero, even value, such as 2 or 4, for a
TileList control, as the following example shows:
<?xml version="1.0"?>
<!-- dataEffects\TileListEffectCustomDefaultEffect.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.effects.DefaultTileListEffect;
import mx.effects.easing.Elastic;
import mx.collections.ArrayCollection;
import mx.effects.Move;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection(
["A","B",'C','D','E','F','G','H','I','J','K','L','M','N','O','P']);
myDP.removeItemAt(myDP.getItemIndex(toRemove[i]));
}
<mx:TileList id="tlist0"
height="400" width="400"
columnCount="4" rowCount="4"
fontSize="30" fontWeight="bold"
direction="horizontal"
dataProvider="{myDP}"
allowMultipleSelection="true"
offscreenExtraRowsOrColumns="2"
itemsChangeEffect="{myDTLE}" />
<mx:Button
label="Delete Selected Item(s)"
click="deleteItems();"/>
<mx:Button
label="Add Item"
click="addItems();"/>
</mx:Application>
You set the autoLayout property to false when you use a Move effect in parallel with a Resize or Zoom effect.
You must do this because the Resize or Zoom effect can cause an update to the container’s layout, which can return
the child to its original location.
When you use the Zoom effect on its own, you can set the autoLayout property to false, or you may leave it
with its default value of true. For example, if you use a Zoom effect with the autoLayout property set to true,
as the child grows or shrinks, Flex automatically updates the layout of the container to reposition its children
based on the new size of the child. If you use a Zoom effect with the autoLayout property set to false, the child
resizes around its center point, and the remaining children do not change position.
The HBox container in the following example uses the default vertical alignment of top and the default horizontal
alignment of left. If you apply a Zoom effect to the image, the HBox container resizes to hold the image, and the
image remains aligned with the upper-left corner of the container:
<mx:HBox>
<mx:Image source="myImage.jpg"/>
</mx:HBox>
In the next example, the image is centered in the HBox container. If you apply a Zoom effect to the image, as it
resizes, it remains centered in the HBox container.
<mx:HBox horizontalAlign="center" verticalAlign="middle">
<mx:Image source="myImage.jpg"/>
</mx:HBox>
By default, the size of the HBox container is big enough to hold the image at it original size. If you disable layout
updates, and use the Zoom effect to enlarge the image, or use the Move effect to reposition the image, the image
might extend past the boundaries of the HBox container, as the following example shows:
<mx:HBox autoLayout="false">
<mx:Image source="myImage.jpg"/>
</mx:HBox>
You set the autoLayout property to false, so the HBox container does not resize as the image resizes. If the
image grows to a size so that it extends beyond the boundaries of the HBox container, the container adds scroll
bars and clips the image at its boundaries.
To prevent the scroll bars from appearing, you can use the height and width properties to explicitly size the
HBox container so that it is large enough to hold the modified image. Alternatively, you can set the clipContent
property of the container to false so that the image can extend past its boundaries.
586 CHAPTER 17
<mx:Button id="b1"
label="Reset"
click="panelOne.height=200;panelTwo.height=200;panelThree.height=200"
/>
<mx:HBox>
<mx:Panel id="panelOne" title="Panel 1" height="200" mouseDownEffect="{myResize}">
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
</mx:Panel>
<mx:Panel id="panelTwo" title="Panel 2" height="200" mouseDownEffect="{myResize}">
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
</mx:Panel>
<mx:Panel id="panelThree" title="Panel 3" height="200"
mouseDownEffect="{myResize}">
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
<mx:Button label="Click Me"/>
</mx:Panel>
</mx:HBox>
</mx:Application>
ADOBE FLEX 3 587
Adobe Flex 3 Developer Guide
For each Panel container in the hideChildrenTargets Array, the following effect triggers execute:
• resizeStartEffect Delivered before the Resize effect begins playing.
• resizeEndEffect Delivered after the Resize effect finishes playing.
If the resizeStartEffect trigger specifies an effect to play, the Resize effect is delayed until the effect finishes
playing.
The default value for the Panel container’s resizeStartEffect and resizeEndEffect triggers is Dissolve,
which plays the Dissolve effect. For more information about the Dissolve effect, see “Available effects” on
page 549.
To disable the Dissolve effect so that a Panel container’s children are hidden immediately, you must set the value
of the resizeStartEffect and resizeEndEffect triggers to none.
Typically, you leave the cachePolicy property with its default value of CachePolicy.AUTO. However, you might
want to set the property to CachePolicy.OFF because bitmap caching is interfering with your user interface, or
because you know something about your application’s behavior such that disabling bitmap caching will have a
beneficial effect on it.
589
Topics
About styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589
Using external style sheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
Using local style definitions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619
Using the StyleManager class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
Using the setStyle() and getStyle() methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 627
Using inline styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631
Loading style sheets at run time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
Using filters in Flex. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
About themes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
About styles
You modify the appearance of Flex components through style properties. These properties can define the size of
a font used in a Label control, or the background color used in the Tree control. In Flex, some styles are inherited
by children from their parent containers, and across style types and classes. This means that you can define a style
once, and then have that style apply to all controls of a single type or to a set of controls. In addition, you can
override individual properties for each control at a local, component, or global level, giving you great flexibility in
controlling the appearance of your applications.
This section introduces you to applying styles to controls. It also provides a primer for using Cascading Style
Sheets (CSS), an overview of the style value formats (Length, Color, and Time), and describes style inheritance.
Subsequent sections provide detailed information about different ways of applying styles in Flex.
Flex does not support controlling all aspects of component layout with CSS. Properties such as x, y, width, and
height are properties, not styles, of the UIComponent class, and therefore cannot be set in CSS. Other properties,
such as left, right, top, and bottom, are style properties and are used to manipulate a component’s location in
a container.
590 CHAPTER 18
<!-- This button has the custom style applied to it. -->
<mx:Button id="myButton" styleName="myFontStyle" label="Click Me"/>
</mx:Application>
The following example defines a new style that applies to all instances of the Button class:
<?xml version="1.0"?>
<!-- styles/TypeSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
fontSize: 15;
color: #9933FF;
}
</mx:Style>
</mx:Application>
For more information, see “Using local style definitions” on page 619.
StyleManager class
Use the StyleManager class to apply styles to all classes or all instances of specified classes. The following example
sets the fontSize style to 15 and the color to 0x9933FF on all Button controls:
<?xml version="1.0"?>
<!-- styles/StyleManagerExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
public function initApp():void {
StyleManager.getStyleDeclaration("Button").setStyle("fontSize",15);
StyleManager.getStyleDeclaration("Button").setStyle("color",0x9933FF);
}
]]></mx:Script>
<mx:Script><![CDATA[
public function initApp():void {
myButton.setStyle("fontSize",15);
myButton.setStyle("color",0x9933FF);
}
]]></mx:Script>
<mx:Button id="myButton" label="Click Me"/>
</mx:Application>
For more information, see “Using the setStyle() and getStyle() methods” on page 627.
Inline styles
Use attributes of MXML tags to apply style properties. These properties apply only to the instance of the control.
This is the most efficient method of applying instance properties because no ActionScript code blocks or method
calls are required.
The following example sets the fontSize to 15 and the color to 0x9933FF on the myButton instance:
<?xml version="1.0"?>
<!-- styles/InlineExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
</mx:Application>
In an MXML tag, you must use the camel-case version of the style property. For example, you must use
“fontSize” rather than “font-size” (the CSS convention) in the previous example. For more information on
style property names, see “About property and selector names” on page 601.
As with other style properties, you can bind inline style properties to variables.
For more information, see “Using inline styles” on page 631.
ADOBE FLEX 3 593
Adobe Flex 3 Developer Guide
Length format
The Length format applies to any style property that takes a size value, such as the size of a font (or fontSize).
Length is of type Number.
The Length type has the following syntax:
length[length_unit]
The following example defines the fontSize property with a value of 20 pixels:
<?xml version="1.0"?>
<!-- styles/LengthFormat.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myFontStyle {
fontSize: 20px;
color: #9933FF;
}
594 CHAPTER 18
</mx:Style>
<mx:Button id="myButton" styleName="myFontStyle" label="Click Here"/>
</mx:Application>
If you do not specify a unit, the unit is assumed to be pixels. The following example defines two styles with the
same font size:
<?xml version="1.0"?>
<!-- styles/LengthFormat2.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myFontStyle {
fontSize: 20px;
color: #9933FF;
}
.myOtherFontStyle {
fontSize: 20;
color: #9933FF;
}
</mx:Style>
<mx:Button id="myButton" styleName="myFontStyle" label="Click Here"/>
<mx:Button id="myButton2" styleName="myOtherFontStyle" label="Click Here"/>
</mx:Application>
Note: Spaces are not allowed between the length value and the unit.
The following table describes the supported length units:
px Relative Pixels.
in Absolute Inches.
cm Absolute Centimeters.
mm Absolute Millimeters.
pt Absolute Points.
pc Absolute Picas.
Note: The numeric values specified for font size in Flex are actual character sizes in the chosen units. These values are
not equivalent to the relative font size specified in HTML using the <font> tag.
Flex does not support the em and ex units. You can convert these to px units by using the following scales:
1em = 10.06667px
1ex = 6px
In Flex, all lengths are converted to pixels prior to being displayed. In this conversion, Flex assumes that an inch
equals 72 pixels. All other lengths are based on that assumption. For example, 1 cm is equal to 1/2.54 of an inch.
To get the number of pixels in 1 cm, multiply 1 by 72, and divide by 2.54.
ADOBE FLEX 3 595
Adobe Flex 3 Developer Guide
When you use inline styles, Flex ignores units and uses pixels as the default.
The fontSize style property allows a set of keywords in addition to numbered units. You can use the following
keywords when setting the fontSize style property. The exact sizes are defined by the client browser:
• xx-small
• x-small
• small
• medium
• large
• x-large
• xx-large
The following example class selector defines the fontSize as x-small:
<?xml version="1.0"?>
<!-- styles/SmallFont.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.smallFont {
fontFamily: Arial, Helvetica, "_sans";
fontSize: x-small;
fontStyle: oblique;
}
</mx:Style>
</mx:Application>
Time format
You use the Time format for component properties that move or have built-in effects, such as the ComboBox
component when it drops down and pops up. The Time format is of type Number and is represented in milli-
seconds. Do not specify the units when entering a value in the Time format.
The following example sets the openDuration style property of the myTree control to 1000 milliseconds. The
default value is 250, so this example opens the tree nodes considerably more slowly than normal.
<?xml version="1.0"?>
<!-- styles/TimeFormat.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
public function initApp():void {
myTree.setStyle("openDuration", 1000);
}
]]></mx:Script>
<mx:XMLList id="treeData">
596 CHAPTER 18
</mx:Application>
Color format
You define Color in several formats. You can use most of the formats only in the CSS style definitions. The
following table describes the recognized Color formats for a style property:
Format Description
hexadecimal Hexadecimal colors are represented by a six-digit code preceded by either a zero and small x (0x) or a pound sign (#).
The range of valid values is 0x000000 to 0xFFFFFF (or #000000 to #FFFFFF).
You use the 0x prefix when defining colors in calls to the setStyle() method and in MXML tags. You use the # prefix
in CSS style sheets and in <mx:Style> tag blocks.
RGB RGB colors are a mixture of the colors red, green, and blue, and are represented in percentages of the color’s saturation.
The format for setting RGB colors is color:rgb(x%, y%, z%), where the first value is the percentage of red satura-
tion, the second value is the percentage of green saturation, and the third value is the percentage of blue saturation.
You can use the RGB format only in style sheet definitions.
VGA color VGA color names are a set of 16 basic colors supported by all browsers that support CSS. The available color names are
names Aqua, Black, Blue, Fuchsia, Gray, Green, Lime, Maroon, Navy, Olive, Purple, Red, Silver, Teal, White,
Yellow.
You can use the VGA color names format in style sheet definitions and inline style declarations.
Color formats are of type Number. When you specify a format such as a VGA color name, Flex converts that String
to a Number.
ADOBE FLEX 3 597
Adobe Flex 3 Developer Guide
CSS style definitions and the <mx:Style> tag support the following color value formats:
<?xml version="1.0"?>
<!-- styles/ColorFormatCSS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myStyle {
themeColor: #6666CC; /* CSS hexadecimal format */
color: Blue; /* VGA color name */
}
</mx:Style>
<mx:Button id="myButton" styleName="myStyle" label="Click Here"/>
</mx:Application>
You can use the following color value formats when setting the styles inline or using the setStyle() method:
<?xml version="1.0"?>
<!-- styles/ColorFormatStyleManager.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
public function initApp():void {
StyleManager.getStyleDeclaration("Button").
setStyle("themeColor",0x6666CC);
StyleManager.getStyleDeclaration("Button").
setStyle("color","Blue");
}
<mx:Style>
Tree {
depthColors: #FFCC33, #FFCC99, #CC9900;
alternatingItemColors: red, green;
}
</mx:Style>
<mx:XMLList id="treeData">
<node label="Mail Box">
<node label="Inbox">
<node label="Marketing"/>
<node label="Product Management"/>
<node label="Personal"/>
</node>
<node label="Outbox">
<node label="Professional"/>
<node label="Personal"/>
</node>
<node label="Spam"/>
<node label="Sent"/>
</node>
</mx:XMLList>
</mx:XMLList>
<mx:Tree id="myOtherTree"
width="100%"
labelField="@label"
dataProvider="{treeData}"
depthColors="[0xFFCC33, 0xFFCC99, 0xCC9900]"
alternatingItemColors="['red', 'green']"
/>
</mx:Panel>
</mx:Application>
This example also shows that you can set the properties that use Arrays inline.
Finally, you can set the values of the Array in MXML syntax and apply those values inline, as the following
example shows:
<?xml version="1.0"?>
<!-- styles/ArrayOfColorsMXML.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Array id="myDepthColors">
<mx:Object>0xFFCC33</mx:Object>
<mx:Object>0xFFCC99</mx:Object>
<mx:Object>0xCC9900</mx:Object>
</mx:Array>
<mx:Array id="myAlternatingRowColors">
<mx:Object>red</mx:Object>
<mx:Object>green</mx:Object>
</mx:Array>
<mx:XMLList id="treeData">
<node label="Mail Box">
<node label="Inbox">
<node label="Marketing"/>
<node label="Product Management"/>
<node label="Personal"/>
</node>
<node label="Outbox">
<node label="Professional"/>
<node label="Personal"/>
</node>
<node label="Spam"/>
<node label="Sent"/>
</node>
</mx:XMLList>
<mx:Panel title="Tree Control Example" width="100%">
<mx:Tree id="myTree"
width="100%"
600 CHAPTER 18
labelField="@label"
dataProvider="{treeData}"
depthColors="{myDepthColors}"
alternatingItemColors="{myAlternatingRowColors}"
/>
</mx:Panel>
</mx:Application>
<!-- This button has the custom style applied to it. -->
<mx:Button id="myButton" styleName="myFontStyle" label="Click Me"/>
</mx:Application>
In this example, myFontStyle defines a new class of styles, so it is called a class selector. In the markup, you can
explicitly apply the myFontStyle style to a control or class of controls.
A type selector implicitly applies itself to all components of a particular type, as well as all subclasses of that type.
The following example defines a type selector named Button:
<?xml version="1.0"?>
<!-- styles/TypeSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
fontSize: 15;
color: #9933FF;
}
</mx:Style>
</mx:Application>
Flex applies this style to all Button controls, and all subclasses of Button controls. If you define a type selector on
a container, that style applies to all children of that container if the style is an inheriting style.
When determining styles for a new component instance, Flex examines all the parent classes looking for type
selectors. Flex applies settings in all type selectors, not just the exact match. For example, suppose that class
MyButton extends Button. For an instance of MyButton, Flex first checks for a MyButton type selector. Flex
applies styles in the MyButton type selector, and then checks for a Button type selector. Flex applies styles in the
Button selector, and then checks for a UIComponent type selector. Flex stops at UIComponent. Flex does not
continue up the parent chain past UIComponent because Flex does not support type selectors for Sprite (the
parent of UIComponent) or any of Sprite’s parent classes, up to the base Object class.
Note: The names of class selectors cannot include hyphens in Flex. If you use a hyphenated class selector name, such
as my-class-selector, Flex ignores the style.
You can programmatically define new class and type selectors using the StyleManager class. For more infor-
mation, see “Using the StyleManager class” on page 621.
.myOtherFontStyle {
font-size: 15; /* Note the hyphen. */
}
</mx:Style>
</mx:Application>
602 CHAPTER 18
In ActionScript or an MXML tag, you cannot use hyphenated style property names, so you must use the camel-
case version of the style property. For the style name in a style sheet, you cannot use a hyphenated name, as the
following example shows:
.myClass { ... } /* Valid style name */
.my-class { ... } /* Not a valid style name */
CSS differences
There are some major differences in Flex between support of CSS and the CSS specification:
• Flex supports a subset of the style properties that are available in CSS. Flex controls also have unique style
properties that are not defined by the CSS specification. For a list of styles that you can apply to your Flex controls,
see “Supported CSS properties” on page 607.
• Flex controls only support styles that are defined by the current theme. If a theme does not use a particular
style, applying that style to a control or group of controls has no effect. For example, the default theme, Halo Aeon,
does not support styles such as symbolColor and symbolBackgroundColor. For more information, see “About
themes” on page 645.
• Flex style sheets can define skins for controls using the Embed keyword. For more information, see “Creating
Skins” on page 689.
ADOBE FLEX 3 603
Adobe Flex 3 Developer Guide
<!-- This button has the custom style applied to it. -->
<mx:Button id="myButton" styleName="myFontStyle" label="Click Me"/>
</mx:Application>
Class selector names must start with a period when you access them with the getStyleDeclaration() method,
as the following example shows:
<?xml version="1.0"?>
<!-- styles/ClassSelectorStyleManager.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myFontStyle {
fontSize: 15;
color: #9933FF;
}
</mx:Style>
<mx:Script><![CDATA[
public function changeStyles(e:Event):void {
StyleManager.getStyleDeclaration('.myFontStyle').setStyle('color',0x3399CC);
}
]]></mx:Script>
</mx:Application>
You do not precede the class selector with a period when you use the styleName property for inline styles.
604 CHAPTER 18
</mx:Application>
In this example, Flex applies the color style to all Button controls in the current document, and all Button
controls in all the child documents. In addition, Flex applies the color style to all subclasses of Button.
You can set the same style declaration for multiple component types by using a comma-separated list of compo-
nents. The following example defines style information for all Button, TextInput, and Label components:
<?xml version="1.0"?>
<!-- styles/MultipleTypeSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button, TextInput, Label {
fontStyle: italic;
fontSize: 24;
}
</mx:Style>
Then, in a local style declaration, you can set all Labels to use the font size 10, as the following example shows:
<?xml version="1.0"?>
<!-- styles/TypeSelectorWithExternalCSS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style source="../assets/SimpleTypeSelector.css"/>
<mx:Style>
Button {
fontSize: 15;
}
</mx:Style>
<mx:Button id="myButton" label="Click Here"/>
</mx:Application>
The local style declaration does not interfere with external style declarations. Flex applies only the style properties
that you specified. The result of this example is that Label controls that are children of the current document use
Blue for the color and 10 for the font size.
All styles are shared across all documents in an application and across all applications that are loaded inside the
same application. For example, if you load two SWF files inside separate tabs in a TabNavigator container, both
SWF files share the external style definitions.
<mx:Style>
Label {
fontSize: 10pt;
}
.myLabel {
color: Blue;
}
</mx:Style>
Button {
fontSize: 10pt;
color: Yellow;
}
</mx:Style>
<mx:Style>
VBox {
color:blue
}
</mx:Style>
</mx:Application>
If the same style property is applied in multiple type selectors that apply to a class, the closest type to that class
takes precedence. For example, the VBox class is a subclass of Box, which is a subclass of Container. If there were
Box and Container type selectors rather than a VBox type selector, then the value of the VBox control’s color
property would come from the Box type selector rather than the Container type selector, as the following example
shows:
ADOBE FLEX 3 607
Adobe Flex 3 Developer Guide
<?xml version="1.0"?>
<!-- styles/ContainerInheritance.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Container {
color:red
}
Box {
color:green
}
</mx:Style>
Style definitions in <mx:Style> tags, external style sheets, and the defaults.css style sheet follow an order of prece-
dence. The same style definition in defaults.css is overridden by an external style sheet that is specified by an
<mx:Style source="stylesheet"/> tag, which is overridden by a style definition within an <mx:Style> tag.
The following example defines a type selector for Panel that sets the fontFamily property to Times and the
fontSize property to 24. As a result, all controls inside the Panel container, as well as all subclasses such as Button
and TextArea, inherit those styles. However, button2 overrides the inherited styles by defining them inline. When
the application renders, button2 uses Arial for the font and 12 for the font size.
<?xml version="1.0"?>
<!-- skins/MoreContainerInheritance.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Panel {
fontFamily: Times, "_serif";
fontSize: 24;
}
</mx:Style>
<mx:Panel title="My Panel">
<mx:Button id="button1" label="Button 1"/>
<mx:Button id="button2" label="Button 2" fontFamily="Arial" fontSize="12"/>
<mx:TextArea text="Flex has is own set of style properties which are
extensible so you can add to that list when you create a custom
component." width="425" height="400"/>
</mx:Panel>
</mx:Application>
Subcomponent styles
Some Flex controls are made up of other components. For example, the DateField control includes a DateChooser
subcomponent, the calendar that pops up when you click on the DateField’s icon. The DateChooser subcom-
ponent itself contains Button subcomponents for navigation and TextField subcomponents for labels.
Inheritable styles are passed from the parent control to the subcomponent. These include all text styles like color
and textDecoration, as well as other inheritable styles. If you set the color style property on a DateField
control, Flex applies that color to the text in the DateChooser subcomponent, too.
If you do not want an inheritable style property to be applied to the subcontrol, you can override the parent’s style
by defining a custom class selector. For example, to apply styles to the subcomponents of a ComboBox control,
you can use the dropdownStyleName or textInputStyleName style properties to define custom selectors.
Most controls that have subcomponents have custom class selectors that apply styles to their subcomponents. In
some cases, controls have multiple custom class selectors so that you can set style properties on more than one
subcomponent.
ADOBE FLEX 3 611
Adobe Flex 3 Developer Guide
The following example sets the color style property on the DateField control. To prevent this color from being
applied to the DateChooser subcomponent, the DCStyle custom class selector overrides the value of the color
style property. This custom class selector is applied to the DateField control with the dateChooserStyleName
property.
<?xml version="1.0" encoding="utf-8"?>
<!-- styles/SubComponentStylesSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.DCStyle {
color:blue;
}
</mx:Style>
<mx:VBox>
<mx:VBox>
<mx:Label text="Overrides the color property of the subcontrol:"/>
<mx:DateField
id="dateField1"
yearNavigationEnabled="true"
color="red"
dateChooserStyleName="DCStyle"
/>
</mx:VBox>
<mx:HRule width="200" height="1"/>
<mx:VBox>
<mx:Label text="Applies the color property to the subcontrol:"/>
<mx:DateField
id="dateField2"
yearNavigationEnabled="true"
color="red"
/>
</mx:VBox>
</mx:VBox>
</mx:Application>
Noninheritable style properties are not passed from the parent component to the subcomponent. For example, if
you customize the value of the cornerRadius property on the DateChooser control, the property does not affect
the buttons that are subcomponents of the calendar. To pass that value to the subcomponent, you can modify the
control’s filter. Filters specify which style properties to pass to their subcomponents. A filter is an Array of objects
that define the style properties that the parent control passes through to the subcomponent. Inheritable style
properties are always passed; they cannot be filtered.
Most controls with subcomponents have at least one filter. For example, the ComboBox subcontrol has a
dropDownStyleFilters property that defines which style properties the ComboBox passes through to the drop
down List subcomponent.
612 CHAPTER 18
Some controls with subcomponents have multiple filters. For example, the DateChooser control has separate
filters for each of the buttons on the calendar: the previous month button (prevMonthStyleFilters), the next
month button (nextMonthStyleFilters ), the previous year button (prevYearStyleFilters), and the next
year button (nextYearStyleFilters).
The filters properties are read-only, but you can customize them by subclassing the control and adding or
removing objects in the filter Array.
The following example includes two DateField controls. The first DateField control does not use a custom filter.
The second DateField control is a custom class that uses two custom filters (one for the properties of the next
month button and one for the properties of the previous month button).
<?xml version="1.0" encoding="utf-8"?>
<!-- versioning/StyleFilterOverride.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:comps="*">
<mx:HBox>
<mx:VBox>
<mx:Text width="200" text="Standard DateChooser control. Does not pass the
cornerRadius property to the button subcomponents:"/>
<mx:DateChooser cornerRadius="10"/>
</mx:VBox>
<mx:VBox>
<mx:Text width="200">
<mx:text>
Custom DateChooser control. Passes the cornerRadius property
to the button subcomponents:
</mx:text>
</mx:Text>
<comps:MyDateChooser cornerRadius="10"/>
</mx:VBox>
</mx:HBox>
</mx:Application>
The following class extends DateChooser and defines custom filters Arrays for two of the button subcomponents:
package {
import mx.controls.DateChooser;
public class MyDateChooser extends DateChooser {
private static var myNextMonthStyleFilters:Object = {
"highlightAlphas" : "highlightAlphas",
"nextMonthUpSkin" : "nextMonthUpSkin",
"nextMonthOverSkin" : "nextMonthOverSkin",
"nextMonthDownSkin" : "nextMonthDownSkin",
"nextMonthDisabledSkin" : "nextMonthDisabledSkin",
"nextMonthSkin" : "nextMonthSkin",
"repeatDelay" : "repeatDelay",
"repeatInterval" : "repeatInterval",
"cornerRadius" : "cornerRadius" // This property is not normally included.
}
ADOBE FLEX 3 613
Adobe Flex 3 Developer Guide
<mx:RichTextEditor/>
<mx:ComboBox>
<mx:dataProvider>
<mx:String>2005</mx:String>
<mx:String>2006</mx:String>
<mx:String>2007</mx:String>
</mx:dataProvider>
</mx:ComboBox>
<mx:NumericStepper/>
</mx:Application>
614 CHAPTER 18
Inheritance exceptions
Not all styles are inheritable, and not all styles are supported by all components and themes. In general, color and
text styles are inheritable, regardless of how they are set (using CSS or style properties). All other styles are not
inheritable unless otherwise noted.
A style is inherited only if it meets the following conditions:
• The style is inheritable. You can see a list of inherited style for each control by viewing that control’s entry in
the Adobe Flex Language Reference. You can programmatically determine if a style is inheritable using the static
isInheritingStyle() or isInheritingTextFormatStyle() methods on the StyleManager class.
• The style is supported by the theme. For a list of styles supported by the default Flex theme, see “About
supported styles” on page 614.
• The style is supported by the control. For information about which controls support which styles, see the
control’s description in the Adobe Flex Language Reference.
• The style is set on the control’s parent container or the container’s parent. A style is not inherited from another
class, unless that class is a parent container of the control, or a parent container of the control’s parent container.
(The exception to this condition is if you use type selectors to apply the style property. In that case, Flex applies
properties of the class’s type selector, as well as any properties set in the base class’s type selector.)
• The style is not overridden at a lower level. For example, if you define a style type selector (such as Button {
color:red }), but then set an instance property on a control (such as <mx:Button color="blue"/>), the type
selector style will not override the style instance property even if the style is inheritable.
You can apply noninheritable styles to all controls by using the global selector. For more information, see “Using
the global selector” on page 620.
Some styles are only used by skins in the theme, while others are used by the component code itself. The display
text of components is not skinnable, so support for text styles is theme-independent.
In addition to color values such as 0xCCCCCC (for silver) or 0x0066FF (for blue), the following values for the
themeColor property are valid:
• haloOrange
• haloBlue
• haloSilver
• haloGreen
The default value is haloBlue. The following example sets the value of themeColor to haloOrange :
<?xml version="1.0"?>
<!-- styles/ThemeColorExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" themeColor="haloOrange">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var themes:ArrayCollection = new ArrayCollection(
[ "haloOrange", "haloBlue", "haloSilver", "haloGreen"]);
</mx:Application>
<mx:Style source="../assets/SimpleTypeSelector.css"/>
</mx:Application>
The value of the source property is the URL of a file that contains style declarations. When you use the source
property, the contents of that <mx:Style> tag must be empty. You can use additional <mx:Style> tags to define
other styles. Do not add <mx:Style> tags to your included file; it should follow standard CSS file syntax.
The external style sheet file can contain both type and class selectors.
If you are using Adobe® Flex® Builder™, you can generate style sheets from existing component definitions by using
the Convert to CSS button in the Style pop-up menu in the Flex Properties view. You can export a custom style
sheet for a single component type or class of components, or use that component’s style properties to create a
global style sheet. For more information, see “Using the CSS editor in Design mode” on page 81 in Using Adobe
Flex Builder 3.
You can also compile CSS files into SWF files and load them at run time. For more information, see “Loading style
sheets at run time” on page 633.
You can specify a CSS file as an argument to the source-path compiler argument. This lets you toggle among
style sheets with that compiler argument.
Button {
fontStyle: italic;
}
</mx:Style>
</mx:Application>
You can use the Application type selector to set the background image and other display settings that define the
way the Flex application appears in a browser. The following sample Application style definition aligns the appli-
cation file to the left, removes margins, and sets the background image to be empty:
<?xml version="1.0"?>
<!-- styles/ApplicationTypeSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Application {
paddingLeft: 0px;
paddingRight: 0px;
paddingTop: 0px;
paddingBottom: 0px;
horizontalAlign: "left";
backgroundColor: #FFFFFF; /* Change color of background to white. */
backgroundImage: " "; /* The empty string sets the image to nothing. */
}
</mx:Style>
</mx:Application>
When the background image is set to the empty string, Flex does not draw the default gray gradient.
You can programmatically define values in the Application type selector using the StyleManager class. For more
information, see “Using the StyleManager class” on page 621.
</mx:Application>
ADOBE FLEX 3 621
Adobe Flex 3 Developer Guide
You can also use the getStyleDeclaration() method to apply the styles with the global selector, as the
following example shows:
<?xml version="1.0"?>
<!-- styles/GlobalTypeSelectorAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp(event)">
<mx:Script><![CDATA[
public function initApp(e:Event):void {
StyleManager.getStyleDeclaration("global").setStyle("fontSize", 22);
StyleManager.getStyleDeclaration("global").setStyle("textDecoration",
"underline");
}
]]></mx:Script>
</mx:Application>
Class selectors, type selectors, and inline styles all override the global selector.
The following examples illustrate applying style properties to the Button, myStyle, and global style names:
<?xml version="1.0"?>
<!-- styles/UsingStyleManager.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp(event)">
<mx:Style>
.myStyle {
color: red;
}
</mx:Style>
<mx:Script><![CDATA[
import mx.styles.StyleManager;
</mx:Application>
Note: If you set either an inheritable or noninheritable style to the global style, Flex applies it to all controls,
regardless of their location in the hierarchy.
<mx:Style>
.unusedStyleTest {
fontSize:17;
color:green;
}
</mx:Style>
<mx:Script>
<![CDATA[
import mx.styles.StyleManager;
The following example creates a new CSSStyleDeclaration object, applies several style properties to the object, and
then applies the new style to all Button controls with the StyleManager’s setStyleDeclaration() method:
<?xml version="1.0"?>
<!-- styles/StyleDeclarationTypeSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.styles.StyleManager;
myDynStyle.setStyle('color', 'blue');
myDynStyle.setStyle('fontFamily', 'georgia');
myDynStyle.setStyle('themeColor', 'green');
myDynStyle.setStyle('fontSize', 24);
</mx:Application>
When you set a new CSSStyleDeclaration on a type selector, you are replacing the entire existing type selector with
your own selector. All style properties that you do not explicitly define in the new CSSStyleDeclaration are set to
null. This can remove skins, margins, and other properties that are defined in the defaults.css file or other style
sheet that you may have applied already.
To avoid nullifying all style properties, you can use a class selector to apply the new CSSStyleDeclaration object.
Because a class selector’s style properties do not replace existing type selector properties, the components
maintain their default settings, as the following example shows:
<?xml version="1.0"?>
<!-- styles/StyleDeclarationClassSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.styles.StyleManager;
myDynStyle.setStyle('color', 'blue');
myDynStyle.setStyle('fontFamily', 'georgia');
myDynStyle.setStyle('themeColor', 'green');
myDynStyle.setStyle('fontSize', 24);
ADOBE FLEX 3 625
Adobe Flex 3 Developer Guide
}
]]></mx:Script>
</mx:Application>
To remove a CSSStyleDeclaration object, use the StyleManager’s clearStyleDeclaration() method, as the
following example shows:
<?xml version="1.0"?>
<!-- styles/ClearStyleDeclarationExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.styles.StyleManager;
myDynStyle.setStyle('color', 'blue');
myDynStyle.setStyle('fontFamily', 'georgia');
myDynStyle.setStyle('themeColor', 'green');
myDynStyle.setStyle('fontSize', 24);
}
private function resetStyles():void {
StyleManager.clearStyleDeclaration(".myButtonStyle", true);
}
]]></mx:Script>
<mx:Button id="myButton"
label="Click Me"
styleName="myButtonStyle"
click="resetStyles()"
/>
</mx:Application>
626 CHAPTER 18
Using the clearStyleDeclaration() method removes only the specified selector’s styles. If you apply a class
selector to a component, and then call the method on that component’s class selector, the component’s type
selector styles remain.
The setStyleDeclaration() and clearStyleDeclaration() methods are computationally expensive. You
can prevent Flash Player from applying or clearing the new styles immediately by setting the update parameter
to false.
The following example sets new class selectors on different targets, but does not trigger the update until the last
style declaration is applied:
<?xml version="1.0"?>
<!-- styles/UpdateParameter.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.styles.StyleManager;
</mx:Application>
When you pass false for the update parameter, Adobe® Flash® Player stores the selector but does not apply the
style. When you pass true for the update parameter, Flash Player recomputes the styles for every visual
component in the application.
ADOBE FLEX 3 627
Adobe Flex 3 Developer Guide
Setting styles
The getStyle() method has the following signature:
var:return_type componentInstance.getStyle(property_name)
The return_type depends on the style that you access. Styles can be of type String, Number, Boolean, or, in the
case of skins, Class. The property_name is a String that indicates the name of the style property—for example,
fontSize.
The setStyle() method has the following signature:
componentInstance.setStyle(property_name, property_value)
The property_value sets the new value of the specified property. To determine valid values for properties, see
the Adobe Flex Language Reference.
The following example uses the getStyle() and setStyle() methods to change the Button’s fontSize style and
display the new size in the TextInput:
<?xml version="1.0"?>
<!-- styles/SetSizeGetSize.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
[Bindable]
private var curSize:int = 10;
ip1.setStyle("fontSize", curSize);
b1.setStyle("fontSize", curSize);
b2.setStyle("fontSize", curSize);
}
]]></mx:Script>
<mx:VBox id="vb">
<mx:TextInput id="ip1"
styleName="myClass"
text="This is a TextInput control."
width="400"
/>
<mx:Form>
<mx:FormItem label="Enter new size:">
<mx:HBox>
<mx:TextInput text="{curSize}" id="ip2" width="50"/>
<mx:Button id="b2" label="Set Style" click="setNewStyles();"/>
</mx:HBox>
</mx:FormItem>
</mx:Form>
</mx:VBox>
</mx:Application>
You can use the getStyle() method to access style properties regardless of how they were set. If you defined a
style property as a tag property inline rather than in an <mx:Style> tag, you can get and set this style. You can
override style properties that were applied in any way, such as in an <mx:Style> tag or in an external style sheet.
The following example sets a style property inline, and then reads that property with the getStyle() method:
<?xml version="1.0"?>
<!-- styles/GetStyleInline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
private function readStyle():void {
myLabel.text = "Label style is: " + myLabel.getStyle("fontStyle");
}
]]></mx:Script>
</mx:VBox>
</mx:Application>
ADOBE FLEX 3 629
Adobe Flex 3 Developer Guide
When setting color style properties with the setStyle() method, you can use the hexadecimal format or the
VGA color name, as the following example shows:
<?xml version="1.0"?>
<!-- styles/ColorFormatStyleManager.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
public function initApp():void {
StyleManager.getStyleDeclaration("Button").
setStyle("themeColor",0x6666CC);
StyleManager.getStyleDeclaration("Button").
setStyle("color","Blue");
}
<mx:Style>
Button {
color: #66CCFF;
}
</mx:Style>
<mx:Script><![CDATA[
[Bindable]
private var n:Number;
myButton.setStyle("color", "Red");
}
</mx:Application>
When you use the setStyle() method to change an existing style (for example, to set the color property of a
Button control to something other than 0x000000, the default), Flex does not overwrite the original style setting.
You can return to the original setting by setting the style property to null. The following example toggles the color
of the Button control between blue and the default by using this technique:
<?xml version="1.0"?>
<!-- styles/ResetStyles.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function toggleStyle():void {
if (cb1.selected == true) {
b1.setStyle("color","blue");
//b1.setStyle("fontSize", 8);
} else {
b1.setStyle("color", null);
//b1.setStyle("fontSize", null);
}
}
]]>
</mx:Script>
<mx:Style>
Button {
color: red;
/*fontSize: 25;*/
}
</mx:Style>
<mx:CheckBox id="cb1"
label="Set Style/Unset Style"
click="toggleStyle()"
selected="false"
color="Black"
/>
</mx:Application>
ADOBE FLEX 3 631
Adobe Flex 3 Developer Guide
When setting style properties inline, you must adhere to the ActionScript style property naming syntax rather
than the CSS naming syntax. For example, you can set a Button control’s fontSize property as font-size or
fontSize in an <mx:Style> declaration, but you must set it as fontSize in a tag definition:
<?xml version="1.0"?>
<!-- styles/CamelCase.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myFontStyle {
fontSize: 15; /* Note the camelCase. */
}
.myOtherFontStyle {
font-size: 15; /* Note the hyphen. */
}
</mx:Style>
</mx:Application>
For more information, see “About property and selector names” on page 601.
When setting color style properties inline, you can use the hexadecimal format or the VGA color name, as the
following example shows:
<?xml version="1.0"?>
<!-- styles/ColorFormatInline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
</mx:Application>
You can remove an inline style definition by using the clearStyle() method.
You can bind inline style properties to variables, as long as you tag the variable as [Bindable]. The following
example binds the value of the backgroundColor property of the HBox controls to the value of the colorValue
variable:
<?xml version="1.0"?>
<!-- styles/PropertyBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
[Bindable]
public var colorValue:int = 0x333999;
Label {
fontSize: 24;
color: #FF9933;
}
Or the style sheet can be a complex style sheet that embeds programmatic and graphical skins, fonts, and other
style properties, and uses type and class selectors, as the following example shows:
/* styles/runtime/assets/ComplexStyles.css */
Application {
backgroundImage: "greenBackground.gif";
theme-color: #9DBAEB;
}
Button {
fontFamily: Tahoma;
color: #000000;
fontSize: 11;
fontWeight: normal;
text-roll-over-color: #000000;
upSkin: Embed(source="orb_up_skin.gif");
overSkin: Embed(source="orb_over_skin.gif");
downSkin: Embed(source="orb_down_skin.gif");
}
.noMargins {
margin-right: 0;
margin-left: 0;
margin-top: 0;
margin-bottom: 0;
horizontal-gap: 0;
vertical-gap: 0;
}
To create a new style sheet in Flex Builder, you select File > New > CSS File. Create the CSS file in the project’s
main directory or another subdirectory that is not the bin directory. You should not create the CSS file in the bin
directory. Flex Builder will compile the SWF file to the bin directory for you.
To compile the CSS file into a SWF file, you use the mxmlc command-line compiler or Flex Builder’s compiler.
The default result of the compilation is a SWF file with the same name as the CSS file, but with the .swf extension.
The following example produces the BasicStyles.swf file by using the mxmlc command-line compiler:
mxmlc BasicStyles.css
To compile the SWF file with Flex Builder, right-click the CSS file and select Compile CSS to SWF. Flex Builder
saves the SWF file in the project’s bin directory. If the original CSS file is in the bin directory, you cannot compile
it into a SWF file. You must move it to a different directory before you can compile it.
When you compile your Flex application, the compiler does not perform any compile-time link checking against
the CSS-based SWF files used by the application. This means that you are not required to create the SWF file
before you compile your main application. This also means that if you mistype the name or location of the SWF
file, or if the SWF file does not exist, the application will fail silently. The application will not throw an error at run
time.
import mx.styles.StyleManager;
</mx:Application>
ADOBE FLEX 3 637
Adobe Flex 3 Developer Guide
</mx:Application>
<mx:CheckBox id="cb1"
label="Load style sheet"
click="toggleStyleSheet()"
selected="false"
/>
</mx:Application>
The unloadStyleDeclarations() method takes a second parameter, update. As with loading style sheets,
Flash Player and AIR do not reapply the styles (in this case, reapply default styles when the loaded styles are
unloaded) if you set the value of the update parameter to false. For more information about the update
parameter, see “Loading style sheets at run time” on page 635.
ADOBE FLEX 3 639
Adobe Flex 3 Developer Guide
import mx.controls.Button;
import mx.events.*;
import mx.styles.StyleManager;
<custom:MyButton/>
</mx:Application>
640 CHAPTER 18
The following example illustrates loading the run-time style sheet into a child application domain and the current
application domain:
CSS SWF file in child domain CSS SWF file in application domain
Child_App.swf Child_App.swf
Module Module
Application domain 3
Styles.swf
Styles.swf CSS SWF
ModuleLoader ModuleLoader
CSS SWF
In the first approach, the module and the run-time style sheet are loaded into separate child application domains
(application domains 2 and 3). The styles can be applied only to the applications within the parent domain and
that child domain, so the styles will not be properly applied to the module, which is in a separate child domain.
The second approach loads the module into a child application domain and the run-time style sheet into the same
domain as the main application. In this case, the styles can be applied to the module and the main application
properly.
The reason you must use the second approach is that the ModuleManager class is responsible for loading all
modules, including CSS SWF files. This class is a Singleton that is defined by the main application. Even though
you call methods on the ModuleManager from within the module, you are calling those methods from within the
context of the main application. As a result, the default domain that the ModuleManager loads SWF files into is a
child of the main application’s domain and not a child domain of whatever SWF file the methods happen to be
executed in.
Because SWF files in sibling application domains cannot communicate, styles loaded into one child application
domain will not be applied properly to SWF files loaded into another child application domain. By specifying the
ApplicationDomain.currentDomain in the loadStyleDeclarations() method, you instruct the ModuleM-
anager to not load the CSS SWF file into a new child application domain, but instead to load it into the main appli-
cation’s application domain so it can be used by your main application and the module.
For more information about application domains, see “Using the ApplicationDomain class” on page 550 in
Programming ActionScript 3.0.
642 CHAPTER 18
label1.filters = null;
}
}
]]></mx:Script>
<mx:Label id="label1" text="ActionScript-applied filter."/>
<mx:Button id="b1" label="Toggle Filter" click="toggleFilter()"/>
</mx:Application>
You cannot bind the filter properties to other values.
If you change a filter, you must reassign it to the component so that the changes take effect. The following example
changes the color of the filters when you click the button:
<?xml version="1.0"?>
<!-- styles/FilterChange.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="createFilters()">
<mx:Script><![CDATA[
import flash.filters.*;
applyFilters();
}
<mx:RichTextEditor id="rte1"/>
644 CHAPTER 18
<mx:DateChooser id="dc1"/>
<mx:HSlider id="hs1"/>
<mx:Button id="b1" label="Click me" click="changeFilters()"/>
</mx:Application>
Some Flex containers and controls have a dropShadowEnabled property. You can set this property to true to add
a drop shadow filter to those components. However, when you use this property, the Flex components draw their
own drop shadows for performance reasons. They copy the edges of the target and then draw the shadow onto a
bitmap, which is then attached the target. If the target component is rotated, the drop shadow might appear jagged
because of the way rotated vectors are rendered.
To avoid this and have smooth drop shadow filters on rotated components, you use the DropShadowFilter class,
as described in the examples in this section.
The following example shows the difference between drawing a filter with the dropShadowEnabled property and
using the DropShadowFilter class:
<?xml version="1.0" encoding="utf-8"?>
<!-- styles/SmoothFilter.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="0xFFFFFF"
layout="absolute"
>
<mx:Style>
Canvas {
borderStyle:solid;
cornerRadius:10;
borderColor:#000000;
backgroundColor:#FFFFFF;
}
</mx:Style>
<mx:Script>
<![CDATA[
private function getBitmapFilter():DropShadowFilter {
var distance:Number = 3;
var angle:Number = 90;
var color:Number = 0x000000;
var alpha:Number = 1;
var blurX:Number = 8;
var blurY:Number = 8;
var strength:Number = 0.65;
var quality:Number = BitmapFilterQuality.LOW;
var inner:Boolean = false;
var knockout:Boolean = false;
dropShadowEnabled="true"
creationComplete="canvas1.rotation=-10"
x="50" y="80"
width="400"
height="300"
/>
<!-- This rotated canvas applies a bitmap filter. As a result,
the edges are smoother. -->
<mx:Canvas id="canvas2"
filters="{[getBitmapFilter()]}"
creationComplete="canvas2.rotation=-10"
x="50" y="420"
width="400"
height="300"
/>
</mx:Application>
For information about using filters with chart controls, see “Using filters with chart controls” on page 116 in Adobe
Flex 3 Data Visualization Developer Guide.
About themes
A theme defines the look and feel of a Flex application. A theme can define something as simple as the color
scheme or common font for an application, or it can be a complete reskinning of all the components used by the
application.
Themes usually take the form of a SWC file. However, themes can also be a CSS file and embedded graphical
resources, such as symbols from a SWF file. Theme SWC files can also be compiled into style SWF files so that
they can be loaded at run time. For more information, see “Using theme SWC files as run-time style sheets” on
page 640.
The default theme, Halo, is a combination of graphical and programmatic skins in a SWC file. It is defined by the
defaults.css file in the framework.swc file. This file sets many properties of the Flex components. In some cases it
uses classes in the mx.skins.halo package. Flex also includes several predefined themes that you can apply to your
applications. For more information, see “About the included theme files” on page 647.
To apply the contents of a SWC file to your Flex application, use the instructions in “Using themes” on page 646.
To create your own theme, use the instructions in “Creating a theme SWC file” on page 647. You can affect the
theme of a Flex application without creating a new theme. You do this with the themeColor property. For more
information, see “Creating themes” on page 698.
646 CHAPTER 18
Using themes
Themes generally take the form of a theme SWC file. These SWC files contain style sheets and skinning assets.
You use the assets inside theme SWC files for programmatic skins or graphical assets, such as SWF, GIF, or JPEG
files. Themes can also contain just stand-alone CSS files.
Packaging a theme as a SWC file rather than as a loose collection of files has the following benefits:
• SWC files are easier to distribute.
• SWC files cannot be modified and reapplied to the application without recompiling.
• SWC files are precompiled. This reduces application compile time, compared to compile time for skin classes
that are not in a SWC file.
You apply a theme to your Flex application by specifying the SWC or CSS file with the theme compiler option.
The following example uses the mxmlc command-line compiler to compile an application that uses the Bully-
Buster theme SWC file:
mxmlc -theme c:/theme/BullyBuster.swc c:/myfiles/flex/misc/MainApp.mxml
When compiling an application by using options in the flex-config.xml file, you specify the theme as follows:
<compiler>
<theme>
<filename>c:/theme/BullyBuster.swc</filename>
</theme>
</compiler>
When you add a SWC file to the list of themes, the compiler adds the classes in the SWC file to the application’s
library-path, and applies any CSS files contained in the SWC file to your application. The converse is not true,
however. If you add a SWC file to the library-path, but do not specify that SWC file with the theme option, the
compiler does not apply CSS files in that SWC file to the application.
For more information, see “Using the Flex Compilers” on page 125 in Building and Deploying Adobe Flex 3 Appli-
cations.
You can specify more than one theme file to be applied to the application. If there are no overlapping styles, both
themes are applied completely. The ordering of the theme files is important, though. If you specify the same style
property in more than one theme file, Flex uses the property from the last theme in the list. In the following
example, style properties in the Wooden.css file take precedence, but unique properties in the first two theme files
are also applied:
<compiler>
<theme>
<filename>../themes/Institutional.css</filename>
<filename>../themes/Ice.css</filename>
<filename>../themes/Wooden.css</filename>
</theme>
</compiler>
ADOBE FLEX 3 647
Adobe Flex 3 Developer Guide
Theme Description
Aeon Graphical Contains the AeonGraphical.css file and the AeonGraphical.swf file. This is the graphical version of the default Halo
theme
The source FLA file for the graphical assets is in the AeonGraphical Source directory. You change the graphical assets in
this file by using the Flash IDE. You must ensure that you export the SWF file, which is used by the theme in Flex.
This theme is provided as a starting point for graphically reskinning your application. While it might be more efficient,
you lose some ability to apply run-time styles if you use it.
The Halo theme uses the defaults.css file in the framework.swc file and the classes in the mx.skins.halo package. For more
information about the default theme assets, see “About the default style sheet” on page 618.
HaloClassic Provides the look and feel of previous versions of Flex. This theme comprises the haloclassic.swc file. Included in this file
are the CSS file and SWF file that provide graphical assets.
To add graphic files to the theme’s CSS file, you use the Embed statement. The following example defines new
graphical skins for the Button class:
Button {
upSkin: Embed("upIcon.jpg");
downSkin: Embed("downIcon.jpg");
overSkin: Embed("overIcon.jpg");
}
The name you provide for the Embed keyword is the same name that you use for the skin asset when compiling
the SWC file.
To add programmatic skin classes to the theme’s CSS file, you use the ClassReference statement to specify the
class name (not the file name), as the following example shows:
Button {
upSkin:ClassReference('myskins.ButtonSkin');
downSkin:ClassReference('myskins.ButtonSkin');
overSkin:ClassReference('myskins.ButtonSkin');
}
In the preceding example, all skins are defined by a single programmatic skin class file. For more information, see
“Creating programmatic skins” on page 713.
The CSS file can include any number of class selectors, as well as type selectors. Style definitions for your theme
do not have to use skins. You can simply set style properties in the style sheet, as the following example shows:
ControlBar {
disabledOverlayAlpha: 0;
paddingBottom: 10;
paddingLeft: 10;
paddingRight: 10;
paddingTop: 10;
verticalAlign: "middle";
}
This type selector for ControlBar components is taken from the default style sheet, defaults.css, inside the
framework.swc file. It can be a good place to start when designing a theme. For more information about
defaults.css, see “About the default style sheet” on page 618.
You use the include-file option to add the CSS file and graphics files to the theme SWC file. This is described
in “Using the include-file option to compile theme SWC files” on page 649. You use the include-classes option
to add programmatic skin classes to the theme SWC file. This is described in “Using the include-classes option to
compile theme SWC files” on page 649.
To simplify the commands for compiling theme SWC files, you can use configuration files. For more information,
see “Using a configuration file to compile theme SWC files” on page 650.
The following command-line example compiles a theme SWC file that includes the CSS file and a single program-
matic skin class, MyButtonSkin, which is in the themes directory:
compc -source-path c:/myfiles/flex/themes
-include-file mycss.css c:/myfiles/flex/themes/mycss.css
-include-classes MyButtonSkin -o c:/myfiles/flex/themes/MyTheme.swc
You can pass a list of classes to the include-classes option by space-delimiting each class, as the following
example shows:
-include-classes MyButtonSkin MyControlBarSkin MyAccordionHeaderSkin
For more information about creating skin classes, see “Creating Skins” on page 689.
Topics
About fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
Using device fonts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655
Using embedded fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
Using multiple typefaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668
About the font managers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 672
Setting character ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
Embedding double-byte fonts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
Embedding fonts from SWF files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677
Troubleshooting fonts in Flex applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686
About fonts
When you compile a Flex application, the application stores the names of the fonts that you used to create the text.
Adobe® Flash® Player 9 uses the font names to locate identical or similar fonts on the user’s system when the Flex
application runs. You can also embed fonts in the Flex application so that the exact font is used, regardless of
whether the client’s system has that font.
You define the font that appears in each of your components by using the fontFamily style property. You can set
this property in an external style sheet, a <mx:Style> block, or inline. This property can take a list of fonts, as the
following example shows:
.myClass {
fontFamily: Arial, Helvetica;
color: Red;
fontSize: 22;
fontWeight: bold;
}
If the client’s system does not have the first font in the list, Flash Player attempts to find the second, and so on,
until it finds a font that matches. If no fonts match, Flash Player makes a best guess to determine which font the
client uses.
654 CHAPTER 19
Fonts are inheritable style properties. So, if you set a font style on a container, all controls inside that container
inherit that style, as the following example shows:
<?xml version="1.0"?>
<!-- fonts/InheritableExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
VBox {
fontFamily: Helvetica;
fontSize: 13pt;
}
HBox {
fontFamily: Times;
fontSize: 13pt;
}
Panel {
paddingLeft: 10;
paddingTop: 10;
paddingBottom: 10;
paddingRight: 10;
}
</mx:Style>
Panel {
paddingLeft: 10;
paddingTop: 10;
paddingBottom: 10;
paddingRight: 10;
}
</mx:Style>
Flash Player supports three device fonts. The following table describes these fonts:
_sans The _sans device font is a sans-serif typeface; for example, Helvetica or Arial.
_serif The _serif device font is a serif typeface; for example, Times Roman.
_typewriter The _typewriter device font is a monospace font; for example, Courier.
Using device fonts does not affect the size of the SWF file because the fonts reside on the client. However, using
device fonts can affect performance of the application because it requires that Flash Player interact with the local
operating system. Also, if you use only device fonts, your selection is limited to three fonts.
Using embedded fonts is not always the best solution, however. Embedded fonts have the following limitations
and drawbacks:
• Embed only TrueType or OpenType fonts. To embed other font types such as Type 1 PostScript fonts, embed
that font in a SWF file that you create in Flash 8, and then embed that SWF file in your Flex application. For more
information, see “Embedding fonts from SWF files” on page 677.
• Embedded fonts increase the file size of your application, because the document must contain font outlines
for the text. This can result in longer download times for your users.
• Embedded fonts, in general, decrease the legibility of the text at sizes smaller than 10 points. All embedded
fonts use anti-aliasing to render the font information on the client screen. As a result, fonts may look fuzzy or
illegible at small sizes. To avoid this fuzziness, you can use advanced anti-aliasing to render fonts in Flex applica-
tions. For more information, see “Using advanced anti-aliasing” on page 663.
• In some cases, embedded fonts can be truncated when they are used in visual components. In these cases, you
might be required to change the padding properties of the component by using style properties or subclassing it.
This only occurs with some fonts.
You typically use Cascading Style Sheets (CSS) syntax for embedding fonts in Flex applications. You use the
@font-face “at-rule” declaration to specify the source of the embedded font and then define the name of the font
by using the fontFamily property. You must specify the @font-face declaration for each face of the font for the
same family that you use. The source can be a local Java Runtime Environment (JRE) font or one that is accessible
by using a file path. You use this font family name in your MXML code to refer to the embedded font.
Note: Check your font licenses before embedding any font files in your Flex applications. Fonts might have licensing
restrictions that preclude them from being stored as vector information.
If you attempt to embed a font that the Flex compiler cannot find, Flex throws an error and your application does
not compile.
The src property specifies how the compiler should look for the font and the name of the font to look for. You
can load a font either by its filename (by using src:url) or by its system font name (by using src:local). This
property is required. For more information, see “Locating embedded fonts” on page 660. The src property also
helps determine which font manager the compiler will use; for more information, see “About the font managers”
on page 672.
The fontFamily property sets the alias for the font that you use to apply the font in style sheets. This property is
required. If you embed a font with a family name that matches the family name of a system font, the Flex compiler
gives you a warning. You can disable this warning by setting the show-shadows-system-font-warnings
compiler option to false.
The fontStyle and fontWeight properties set the type face values for the font. These properties are optional.
The default values are normal.
The advancedAntiAliasing property determines whether to include the advanced anti-aliasing information
when embedding the font. This property is optional. The default value is true. You cannot use this option when
embedding fonts from a SWF file (see “Embedding fonts from SWF files” on page 677). For more information on
using advanced anti-aliasing, see “Using advanced anti-aliasing” on page 663.
The following example embeds the MyriadWebPro.ttf font file:
@font-face {
src: url("../assets/MyriadWebPro.ttf");
fontFamily: myFontFamily;
advancedAntiAliasing: true;
}
The following example embeds that same font, but by using its system font name:
@font-face {
src: local("Myriad Web Pro");
fontFamily: myFontFamily;
advancedAntiAliasing: true;
}
After you embed a font with an @font-face declaration, you can use the value of the fontFamily property, or
alias, in a type or class selector. The following example uses myFontFamily, the value of the fontFamily property,
as the font in the VBox type selector:
<?xml version="1.0"?>
<!-- fonts/EmbeddedFontFace.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
@font-face {
src:url("../assets/MyriadWebPro.ttf");
fontFamily: myFontFamily;
advancedAntiAliasing: true;
}
VBox {
fontFamily: myFontFamily;
ADOBE FLEX 3 659
Adobe Flex 3 Developer Guide
fontSize: 15;
}
Panel {
paddingLeft: 10;
paddingTop: 10;
paddingBottom: 10;
paddingRight: 10;
}
</mx:Style>
</mx:Application>
You can also apply the embedded font inline by specifying the alias as the value of the control’s fontFamily
property, as the following example shows:
<?xml version="1.0"?>
<!-- fonts/EmbeddedFontFaceInline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
@font-face {
src:url("../assets/MyriadWebPro.ttf");
fontFamily: myFontFamily;
advancedAntiAliasing: true;
}
Panel {
paddingLeft: 10;
paddingTop: 10;
paddingBottom: 10;
paddingRight: 10;
}
</mx:Style>
<mx:text>
The text in the TextArea control is Myriad Web Pro.
</mx:text>
</mx:TextArea>
</mx:VBox>
</mx:Panel>
</mx:Application>
When you run this example, you might notice that the Button control’s label uses a system font. This is because
the default style of a Button control’s label uses a bold typeface. However, the embedded font’s typeface (Myriad
Web Pro) does not contain a definition for the bold typeface. To have the Button control’s label use the proper
typeface, you must either embed a font’s bold typeface so that the label of a Button control is rendered with the
correct font, or change the Button control’s typeface to be non-bold. For information on embedding bold
typefaces, see “Using multiple typefaces” on page 668.
Attribute Description
url Embeds a TrueType or OpenType font by location by specifying a valid URI to the font. The URI can be relative (for example,
../fontfolder/akbar.ttf) or absolute (for example, c:/myfonts/akbar.ttf ).
local Embeds a locally accessible TrueType or OpenType font by name rather than location. You use the font name, and not the
filename, for the font. For example, you specify “Akbar Bold Italic” rather than “AkbarBI.ttf”.
You can embed fonts that are locally accessible by the application server’s Java Runtime Environment (JRE). These fonts
include the *.ttf files in the jre/lib/fonts folder, fonts that are mapped in the jre/lib/font.properties file, and fonts that are
made available to the JRE by the operating system (OS).
On Windows, TTF files in the /windows/fonts directory (or /winnt/fonts) are available to the local function. On Solaris or
Linux, fonts that are registered with a font server, such as xfs, are available.
The font name that you specify is determined by the operating system. In general, you do not include the font file’s extension,
but this is OS-dependent. For more information, consult your operating system documentation.
You must specify the url or local function of the src property in the @font-face declaration. All other
properties are optional. In general, you should use url rather than local, because pointing to a file is more
reliable than using a reference controlled by the operating system.
Do not mix embedded and nonembedded fonts in the same fontFamily property.
ADOBE FLEX 3 661
Adobe Flex 3 Developer Guide
<mx:Script>
/*
* Embed a font by location.
*/
[Embed(source='../assets/MyriadWebPro.ttf',
fontName='myMyriadFont',
mimeType='application/x-font'
)]
// You do not use this variable directly. It exists so that
// the compiler will link in the font.
private var font1:Class;
/*
* Embed a font with bold typeface by location.
*/
[Embed(source='../assets/MyriadWebPro-Bold.ttf',
fontWeight='bold',
fontName='myBoldMyriadFont',
mimeType='application/x-font',
advancedAntiAliasing='true'
)]
private var font2:Class;
</mx:Script>
<mx:Label
width="100%"
height="75"
styleName="mystyle2"
text="This text uses the MyriadWebPro-Bold font."
rotation="15"
/>
</mx:VBox>
</mx:Panel>
</mx:Application>
You use the value of the fontName property that you set in the [Embed] tag as the alias (fontFamily) in your style
definition.
To embed a font with a different typeface (such as bold or italic), you specify the fontWeight or fontStyle
properties in the [Embed] statement and in the style definition. For more information on embedding different
typefaces, see “Using multiple typefaces” on page 668.
To show you that the example runs correctly, the Label controls are rotated. If the fonts were not correctly
embedded, the text in the Label controls would disappear when you rotated the text.
To embed local or system fonts, you use the system font name rather than the filename for the font. You also
specify that name using the systemFont property in the [Embed] tag rather than the source attribute. Otherwise,
you use the same syntax, as the following example shows:
<?xml version="1.0"?>
<!-- fonts/EmbeddedFontFaceActionScriptByName.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.mystyle1 {
fontFamily:myPlainFont;
fontSize: 32pt;
}
.mystyle2 {
fontFamily:myItalicFont;
fontSize: 32pt;
fontStyle: italic;
}
</mx:Style>
<mx:Script>
/*
* Embed a font by name.
*/
[Embed(systemFont='Myriad Web Pro',
fontName='myPlainFont',
mimeType='application/x-font'
)]
// You do not use this variable directly. It exists so that
// the compiler will link in the font.
private var font1:Class;
/*
* Embed a font with italic typeface by name.
*/
ADOBE FLEX 3 663
Adobe Flex 3 Developer Guide
</mx:Script>
src:url("../assets/MyriadWebPro.ttf");
fontFamily: myFontFamily;
advancedAntiAliasing: false;
}
Using advanced anti-aliasing can degrade the performance of your compiler. This is not a run-time concern, but
can be noticeable if you compile your applications frequently or use the web-tier compiler. Using advanced anti-
aliasing can also cause a slight delay when you load SWF files. You notice this delay especially if you are using
several different character sets, so be aware of the number of fonts that you use. The presence of advanced anti-
aliasing information may also cause an increase in the memory usage in Flash Player and Adobe® AIR™. Using four
or five fonts, for example, can increase memory usage by approximately 4 MB.
When you embed fonts that use advanced anti-aliasing in your Flex applications, the fonts function exactly as
other embedded fonts. They are anti-aliased, you can rotate them, and you can make them partially or wholly
transparent.
Font definitions that use advanced anti-aliasing support several additional styles properties:
fontAntiAliasType, fontGridFitType, fontSharpness, and fontThickness . These properties are all inher-
iting styles.
Because the advanced anti-aliasing-related style properties are CSS styles, you can use them in the same way that
you use standard style properties, such as fontFamily and fontSize. For example, a text-based component
could use subpixel-fitted advanced anti-aliasing of New Century 14 at sharpness 50 and thickness -35, while all
Button controls could use pixel-fitted advanced anti-aliasing of Tahoma 10 at sharpness 0 and thickness 0. These
styles apply to all the text in a TextField control; you cannot apply them to some characters and not others.
The default values for the advanced anti-aliasing styles properties are defined in the defaults.css file. If you replace
this file or use another style sheet that overrides these properties, Flash Player and AIR use the standard font
renderer to render the fonts that use advanced anti-aliasing. If you embed fonts that use advanced anti-aliasing,
you must set the fontAntiAliasType property to advanced, or you lose the benefits of the advanced anti-
aliasing information.
ADOBE FLEX 3 665
Adobe Flex 3 Developer Guide
fontAntiAliasType Sets the antiAliasType property of internal TextField controls. The valid values are normal and
advanced. The default value is advanced, which enables advanced anti-aliasing for the font.
Set this property to normal to prevent the compiler from using advanced anti-aliasing.
This style has no effect for system fonts or fonts embedded without the advanced anti-aliasing information.
fontGridFitType Sets the gridFitType property of internal TextField controls. The valid values are none, pixel, and
subpixel. The default value is pixel. For more information, see the TextField and GridFitType classes in
the Adobe Flex Language Reference.
This property has the same effect as the gridFitType style property of the TextField control for system
fonts, only it applies when you embed fonts with advanced anti-aliasing.
Changing the value of this property has no effect unless the fontAntiAliasType property is set to
advanced.
fontSharpness Sets the sharpness property of internal TextField controls. The valid values are numbers from -400 to 400.
The default value is 0.
This property has the same effect as the fontSharpness style property on the TextField control for system
fonts, only it applies when you embed fonts with advanced anti-aliasing.
Changing the value of this property has no effect unless the fontAntiAliasType property is set to
advanced.
fontThickness Sets the thickness property of internal TextField controls. The valid values are numbers from -200 to 200.
The default value is 0.
This property has the same effect as the fontThickness style property on the TextField control for system
fonts, only it applies when you embed fonts with advanced anti-aliasing.
Changing the value of this property has no effect unless the fontAntiAliasType property is set to
advanced.
@font-face {
src: url(../assets/MyriadWebPro.ttf);
fontFamily: myPlainFont;
advancedAntiAliasing: true;
}
.myStyle1 {
fontFamily: myPlainFont;
fontSize:12pt
}
</mx:Style>
<mx:Script><![CDATA[
import mx.managers.SystemManager;
import flash.text.TextFormat;
<mx:HBox>
<mx:Button label="Rotate +1" click="++text1.rotation;"/>
<mx:Button label="Rotate -1" click="--text1.rotation;"/>
</mx:HBox>
<mx:Form>
<mx:FormItem label="isFontFaceEmbedded:">
<mx:Label id="l1"/>
</mx:FormItem>
<mx:FormItem label="isFontFaceEmbedded:">
<mx:Label id="l2"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
You can use the Font class’s enumerateFonts() method to output information about device or embedded fonts.
The following example lists embedded fonts:
<?xml version="1.0"?>
<!-- fonts/EnumerateFonts.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="listFonts()">
<mx:Style>
@font-face {
src:url("../assets/MyriadWebPro.ttf");
fontFamily: myFont;
ADOBE FLEX 3 667
Adobe Flex 3 Developer Guide
advancedAntiAliasing: true;
}
@font-face {
src:url("../assets/MyriadWebPro-Bold.ttf");
fontFamily: myFont;
fontWeight: bold;
advancedAntiAliasing: true;
}
@font-face {
src:url("../assets/MyriadWebPro-Italic.ttf");
fontFamily: myFont;
fontStyle: italic;
advancedAntiAliasing: true;
}
.myPlainStyle {
fontSize: 20;
fontFamily: myFont;
}
.myBoldStyle {
fontSize: 20;
fontFamily: myFont;
fontWeight: bold;
}
.myItalicStyle {
fontSize: 20;
fontFamily: myFont;
fontStyle: italic;
}
</mx:Style>
<mx:Script><![CDATA[
private function listFonts():void {
var fontArray:Array = Font.enumerateFonts(false);
for(var i:int = 0; i < fontArray.length; i++) {
var thisFont:Font = fontArray[i];
if (thisFont.fontType == "embedded") {
ta1.text += "FONT " + i + ":: name: " + thisFont.fontName + "; typeface: " +
thisFont.fontStyle + "; type: " + thisFont.fontType + "\n";
}
}
}
]]></mx:Script>
<mx:HBox borderStyle="solid">
<mx:Label text="Plain Label" styleName="myPlainStyle"/>
<mx:Label text="Bold Label" styleName="myBoldStyle"/>
<mx:Label text="Italic Label" styleName="myItalicStyle"/>
</mx:HBox>
</mx:Application>
668 CHAPTER 19
@font-face {
/* Note the different filename for boldface. */
src:url("../assets/MyriadWebPro-Bold.ttf");
ADOBE FLEX 3 669
Adobe Flex 3 Developer Guide
@font-face {
/* Note the different filename for italic face. */
src:url("../assets/MyriadWebPro-Italic.ttf");
fontFamily: myFont; /* Notice that this is the same alias. */
fontStyle: italic;
advancedAntiAliasing: true;
}
.myPlainStyle {
fontSize: 32;
fontFamily: myFont;
}
.myBoldStyle {
fontSize: 32;
fontFamily: myFont;
fontWeight: bold;
}
.myItalicStyle {
fontSize: 32;
fontFamily: myFont;
fontStyle: italic;
}
</mx:Style>
<mx:VBox>
<mx:Label text="Plain Label" styleName="myPlainStyle"/>
<mx:Label text="Italic Label" styleName="myItalicStyle"/>
<mx:Label text="Bold Label" styleName="myBoldStyle"/>
</mx:VBox>
</mx:Application>
Optionally, you can apply the boldface or oblique type to controls inline, as the following example shows:
<?xml version="1.0"?>
<!-- fonts/MultipleFacesAppliedInline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
@font-face {
src:url("../assets/MyriadWebPro.ttf");
fontFamily: myFont;
advancedAntiAliasing: true;
}
@font-face {
src:url("../assets/MyriadWebPro-Bold.ttf");
fontFamily: myFont;
fontWeight: bold;
advancedAntiAliasing: true;
}
670 CHAPTER 19
@font-face {
src:url("../assets/MyriadWebPro-Italic.ttf");
fontFamily: myFont;
fontStyle: italic;
advancedAntiAliasing: true;
}
.myStyle1 {
fontSize: 32;
fontFamily: myFont;
}
</mx:Style>
<mx:VBox styleName="myStyle1">
<mx:Label text="Plain Label"/>
<mx:Label text="Italic Label" fontStyle="italic"/>
<mx:Label text="Bold Label" fontWeight="bold"/>
</mx:VBox>
</mx:Application>
If you embed a system font by name rather than by a font file by location, you use the font’s family name (such as
Myriad Web Pro) in the @font-face rule and not the typeface name (such as MyriadWebPro-Bold). The
following example embeds a plain typeface and an italic typeface by using the system font names:
<?xml version="1.0"?>
<!-- fonts/EmbeddedFontFaceCSSByName.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
@font-face {
src:local("Myriad Web Pro");
fontFamily: myPlainFont;
advancedAntiAliasing: true;
}
@font-face {
src:local("Myriad Web Pro");
fontFamily: myItalicFont;
fontStyle: italic;
advancedAntiAliasing: true;
}
.mystyle1 {
fontFamily:myPlainFont;
fontSize: 32pt;
}
.mystyle2 {
fontFamily:myItalicFont;
fontSize: 32pt;
fontStyle: italic;
}
</mx:Style>
<mx:Panel title="Embedded Fonts Using CSS">
<mx:VBox>
<mx:Label
width="100%"
ADOBE FLEX 3 671
Adobe Flex 3 Developer Guide
height="75"
styleName="mystyle1"
text="This text uses the plain typeface."
rotation="15"
/>
<mx:Label
width="100%"
height="75"
styleName="mystyle2"
text="This text uses the italic typeface."
rotation="15"
/>
</mx:VBox>
</mx:Panel>
</mx:Application>
Flex also supports using the <b> and <i> HTML tags in text-based controls, such as Label, to apply the boldface
or italic font to the text.
If you use a bold-italic font, the font must have a separate typeface for that font. You specify both properties
(fontWeight and fontStyle) in the @font-face and selector blocks, as the following example shows:
@font-face {
src:url("../assets/KNIZIA-BI.TTF");
fontStyle: italic;
fontWeight: bold;
fontFamily: myFont;
advancedAntiAliasing: true;
}
.myBoldItalicStyle {
fontFamily:myFont;
fontWeight:bold;
fontStyle:italic;
fontSize: 32;
}
In the @font-face definition, you can specify whether the font is boldface or italic font by using the fontWeight
and fontStyle properties. For a bold font, you can set fontWeight to bold or an integer greater than or equal
to 700. You can specify the fontWeight as plain or normal for a nonboldface font. For an italic font, you can set
fontStyle to italic or oblique. You can specify the fontStyle as plain or normal for a nonitalic face. If you
do not specify a fontWeight or fontStyle, Flex assumes you embedded the plain or regular font face.
You can also add any other properties for the embedded font, such as fontSize, to the selector, as you would with
any class or type selector.
By default, Flex includes the entire font definition for each embedded font in the application, so you should limit
the number of fonts that you use to reduce the size of the application. You can limit the size of the font definition
by defining the character range of the font. For more information, see “Setting character ranges” on page 673.
672 CHAPTER 19
You determine which font managers the compiler can use in the flex-config.xml file. The default setting is to use
all of them, as the following example shows:
<fonts>
<managers>
<manager-class>flash.fonts.JREFontManager</manager-class>
<manager-class>flash.fonts.AFEFontManager</manager-class>
<manager-class>flash.fonts.BatikFontManager</manager-class>
</managers>
</fonts>
ADOBE FLEX 3 673
Adobe Flex 3 Developer Guide
The preference of <manager> elements is in reverse order. This means that by default the Batik font manager is
the preferred font manager; the compiler checks to see if a font can be transcoded using it first. If not, then the
compiler checks to see whether the font can be transcoded using the AFE font manager. Finally, if the other font
managers fail, the compiler checks to see whether the JRE font manager can transcode the font.
If you experience compilation or transcoding errors related to fonts, you should first try changing the order of the
font managers in the flex-config.xml file or by using the command-line compiler arguments.
TextArea {
fontFamily: myFontFamily;
fontSize: 32;
}
</mx:Style>
@font-face{
font-family: myWideRangeFont;
advancedAntiAliasing: true;
src:url("../assets/MyriadWebPro.ttf");
/*
* Set range to the 128 characters in
* the Basic Latin block.
*/
unicodeRange: U+0041-U+007F;
}
</mx:Style>
<mx:Script><![CDATA[
public function checkCharacterSupport():void {
var fontArray:Array = Font.enumerateFonts(false);
for(var i:int = 0; i < fontArray.length; i++) {
var thisFont:Font = fontArray[i];
if (thisFont.hasGlyphs("DHARMA")) {
ta1.text += "The font '" + thisFont.fontName +
676 CHAPTER 19
<mx:Text>
<mx:text>
myABFont unicodeRange: U+0041-U+0042 (letters A and B)
</mx:text>
</mx:Text>
<mx:Text>
<mx:text>
myWideRangeFont unicodeRange: U+0041-U+007F (Basic Latin chars)
</mx:text>
</mx:Text>
</mx:Application>
<languages>
<language-range>
<lang>thai</lang>
<range>U+0E01-U+0E5B</range>
</language-range>
</languages>
</fonts>
...
</flex-config>
You can change the value of the <lang> element to anything you want. When you embed the font by using CSS,
you refer to the language by using this value in the unicodeRange property of the @font-face declaration, as the
following example shows:
@font-face {
fontFamily:"Thai_font";
src: url("../assets/THAN.TTF"); /* Embed from file */
advancedAntiAliasing: true;
unicodeRange:"thai"
}
5 In the Properties panel, select Dynamic Text from the drop-down list to make this text dynamic.
6 If you use advanced anti-aliasing in your fonts, ensure that either the Anti-Alias for Readability or Custom
Anti-Alias option is the selected anti-aliasing mode. If you select any other option, Flash does not include
advanced anti-aliasing information with your fonts’ SWF file. For more information about using advanced anti-
aliasing, see “Using advanced anti-aliasing” on page 663.
ADOBE FLEX 3 679
Adobe Flex 3 Developer Guide
8 Select one or more character ranges to use. Select only the ranges that are necessary.
You should select All only if it is absolutely necessary. The more glyphs that you add to the SWF file, the
greater its size. For example, if you select All for Century Gothic, the final SWF file size is about 270 KB. If
you select Uppercase, Lowercase, and Punctuation only, the final SWF file size is about 14 KB.
Do not select Auto Fill unless you know exactly which characters you are going to use in your Flex application.
9 Create additional text-based controls, one for each of the typefaces you want (such as bold and italic). For the
bold control, apply the bold typeface. For the italic control, apply the italic typeface. For the bold and italic control
(if applicable), apply the bold and italic typefaces. For each typeface, select the range of glyphs to include in the
SWF file.
680 CHAPTER 19
You specify the location of the SWF file by using the src property. You set the value of the fontFamily
property to the name of the font as it appears in the list of available fonts in Flash. You must specify a new
@font-face entry for each of the typeface properties if the font face is not plain. For more information on
using the @font-face declaration, see “Embedded font syntax” on page 657.
Do not specify a value for the advancedAntiAliasing property in the @font-face declaration. This is
because anti-aliasing settings in Flash determine whether to include the advanced anti-aliasing information.
After a SWF file that contains fonts has been generated, you cannot add the hinting information to the SWF
file by using the Flex compiler or from within the Flex application. For more information on using advanced
anti-aliasing, see “Using advanced anti-aliasing” on page 663.
2 Define a style for each embedded font typeface. You can define this style as an external style sheet or in a
<mx:Style> block, as the following example shows:
/* assets/FlashTypeClassSelectors.css */
.myPlainStyle {
fontFamily: "Myriad Web Pro";
fontSize: 24;
}
.myItalicStyle {
fontFamily: "Myriad Web Pro";
fontSize: 24;
fontStyle: italic;
}
.myBoldStyle {
fontFamily: "Myriad Web Pro";
fontSize: 24;
fontWeight: bold;
}
You must specify the fontFamily property in the style definition, and it must match the fontFamily
property set in the @font-face declaration. Regardless of which typeface you are defining, the value of the
fontFamily property is the same. For example, if the typeface is boldface, you do not set the fontFamily
property to Myriad Web Pro Bold, but just Myriad Web Pro.
You must also specify all typeface properties in the style definition, just as you did in the @font-face decla-
ration.
3 Apply the new style to your Flex controls, as the following example shows:
<?xml version="1.0"?>
<!-- fonts/EmbedAntiAliasedFonts.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style source="../assets/FlashTypeStyles.css"/>
<mx:Style source="../assets/FlashTypeClassSelectors.css"/>
</mx:Panel>
</mx:Application>
You can also define and apply the styles inline, rather than define them in a style sheet and apply them with
the styleName property. The following example sets the value of the fontFamily and fontStyle properties
inline to apply the Myriad Web Pro font’s italic and bold typefaces to the Label controls:
<?xml version="1.0"?>
<!-- fonts/EmbedAntiAliasedFontsInline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style source="../assets/FlashTypeStyles.css"/>
fontWeight: bold;
}
</mx:Style>
<mx:Script><![CDATA[
[Embed(source='../assets/MyriadWebProEmbed.swf',
fontName='Myriad Web Pro'
)]
private static var plainFont:Class;
684 CHAPTER 19
[Embed(source='../assets/MyriadWebProEmbedWithFontSymbols.swf',
fontName='Myriad Web Pro',
fontStyle='italic'
)]
private static var italicFont:Class;
[Embed(source='../assets/MyriadWebProEmbedWithFontSymbols.swf',
fontName='Myriad Web Pro',
fontWeight='bold'
)]
private static var boldFont:Class;
]]></mx:Script>
<!-- Rotate the Text controls. If the text disappears when the control is
rotated, then the font is not properly embedded. -->
<mx:Button
label="Rotate +1"
click="++text1.rotation;++text2.rotation;++text3.rotation;"
/>
<mx:Button
label="Rotate -1"
click="--text1.rotation;--text2.rotation;--text3.rotation;"
/>
</mx:Application>
You must define a variable of type Class so that the compiler links the fonts into the final Flex application SWF
file. This example sets the value of the static plainFont, boldFont, and italicFont variables, but they are not
used in the rest of the application.
When you use the [Embed] statement to embed fonts in your Flex application, you must still define styles for those
fonts so that those styles can be applied to Flex components, as you would if you embedded the fonts with the
@font-face declaration.
You can also access fonts from SWF files as a font symbol. You can do this only if you embed the fonts in your Flex
application with the [Embed] metadata syntax.
4 In the Font Symbol Properties dialog box, give the new font symbol a name and select the applicable font
symbol properties (such as bold or italic). You use the symbol name you specify here in your [Embed] statement.
Do this for each font typeface (such as plain, bold, italic, and bold italic).
Note: Do not set the value of the symbol name to be the same as the font name in the Font Symbol Properties
dialog box. For example, if you are creating a new symbol for the font named Myriad Web Pro, set the symbol
name to something other than Myriad Web Pro.
5 After you create a font symbol in the library, right-click the symbol in the library and select Linkage.
6 In the Linkage Properties dialog box, select Export for ActionScript, and click OK. The Identifier in this dialog
box should match the symbol name you specified in the previous step. Do this for each font symbol in the library.
7 In your Flex application’s [Embed] statement, point to the font symbol using the symbol attribute. Do not
specify any other characteristics of the font such as the MIME type, fontStyle, fontWeight , or fontName in the
[Embed] statement.
The following example embeds the Myriad Web Pro font that was exported from Flash 8 with font symbols in the
library:
<?xml version="1.0"?>
<!-- fonts/EmbedAntiAliasedFontsActionScript.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myPlainStyle {
fontFamily: "Myriad Web Pro";
fontSize: 24;
}
.myItalicStyle {
fontFamily: "Myriad Web Pro";
fontSize: 24;
fontStyle: italic;
}
.myBoldStyle {
fontFamily: "Myriad Web Pro";
fontSize: 24;
fontWeight: bold;
}
</mx:Style>
<mx:Script><![CDATA[
[Embed(source='../assets/MyriadWebProEmbedWithFontSymbols.swf',
symbol='MyriadPlain'
)]
private var font1:Class;
[Embed(source='../assets/MyriadWebProEmbedWithFontSymbols.swf',
symbol='MyriadBold'
)]
private var font2:Class;
[Embed(source='../assets/MyriadWebProEmbedWithFontSymbols.swf',
symbol='MyriadItalic'
686 CHAPTER 19
)]
private var font3:Class;
]]></mx:Script>
<!-- Rotate the Text controls. If the text disappears when the control is
rotated, then the font is not properly embedded. -->
<mx:Button
label="Rotate +1"
click="++text1.rotation;++text2.rotation;++text3.rotation;"
/>
<mx:Button
label="Rotate -1"
click="--text1.rotation;--text2.rotation;--text3.rotation;"
/>
</mx:Application>
You can try changing the order of font managers, as the following example shows:
<fonts>
<managers>
<manager-class>flash.fonts.AFEFontManager</manager-class>
<manager-class>flash.fonts.BatikFontManager</manager-class>
<manager-class>flash.fonts.JREFontManager</manager-class>
</managers>
</fonts>
Error Solution
Unable to resolve Indicates that the font was not found by the compiler. Ensure that the path to the font is
‘swf_file_name’ for correct in the @font-face declaration or the [Embed] tag and that the path is accessible by
transcoding the compiler.
If you are using the local property to specify the location of the font in the @font-face
declaration, ensure that the font is locally accessible. Check that it is an entry in the fonts.prop-
erties file or that the font is in the system font search path. For more information, see
“Embedded font syntax” on page 657.
Font ‘font_name’ with Indicates that the fontName property used in the [Embed] statement might not match the
style_description not found name of the font.
For fonts in SWF files, ensure that the spelling and word spacing of the font name in the list of
available fonts in Flash is the same as the fontName property in your [Embed] statement and
the fontFamily property that you use in your style definitions.
This error can also mean that the font’s style was not properly embedded in Flash. Open the
FLA file and ensure that there is a text area with the font and style described, that the text is
dynamic, and that you selected a character range for that text.
• In your Flex application, ensure that you set all properties for each font typeface in the @font-face decla-
ration or [Embed] statement. To embed a bold typeface, you must set the fontWeight property to bold, as the
following example shows:
@font-face {
src: url(../assets/MyriadWebProEmbed.ttf);
fontFamily: "Myriad Web Pro";
fontWeight: bold;
}
You also must set the fontWeight style property in your style definition:
.myStyle2 {
fontFamily:"Myriad Web Pro";
fontWeight:bold;
fontSize:12pt;
}
If you use the [Embed] statement, you must set the fontWeight property to bold as the following example
shows:
[Embed(source="MyriadWebProEmbed.ttf", fontName="Myriad Web Pro",fontWeight="bold")]
• For fonts in SWF files, open the FLA file in Flash and ensure that all of the typefaces were added properly.
Select each text area and do the following:
• Check that the font name is correct. Ensure that the spelling and word spacing of the font name in the list
of available fonts in Flash is the same as the fontFamily property in the @font-face declaration or the
fontName property in your [Embed] statement. This value must also match the fontFamily property that
you use in your style definitions.
If you did not select an anti-aliasing option for the font in Flash 8 (for example, you chose Bitmap Text
(no anti-alias)), you might need to change the value of the font name to a format that matches
fontName_fontSizept_st (for example, "Wingdings_8pt_st"). In the CSS for that bitmap font, be sure to set
fontAntiAliasType to normal.
To determine the exact font name exported by Flash (which you must match as the value of the
fontFamily property in your Flex application), open the SWF file in Flash 8 and select Debug > Variables.
• Check that the style is properly applied. For example, select the bold text area and check that the typeface
really is bold.
• Click the Embed button and ensure that the range of embedded characters includes the characters that
you use in your Flex application.
• Check that each text area is set to Dynamic Text and not Static Text or Input Text. The type of text is
indicated by the first drop-down box in the text’s Properties tab.
• For fonts in SWF files, ensure that you are using the latest SWF file that contains your fonts and was generated
in Flash. Regenerate the SWF file in Flash if necessary.
689
Topics
About skinning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
Applying skins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
Creating graphical skins. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
Creating programmatic skins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713
Creating stateful skins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727
Creating advanced programmatic skins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735
About skinning
Skinning is the process of changing the appearance of a component by modifying or replacing its visual elements.
These elements can be made up of bitmap images, SWF files, or class files that contain drawing methods that
define vector images.
Skins can define the entire appearance, or only a part of the appearance, of a component in various states. For
example, a Button control has eight possible states, and eight associated skin properties, as the following example
shows:
up upSkin mx.skins.halo.ButtonSkin
The default skins for the up, over, and down states appear as follows:
A B C
A. up B. over C. down
Other controls have similar states with associated skins. For example, RadioButton controls, which are subclasses
of Button, also have up, down, and over skins. The ComboBox control has skins the define the appearance of the
control when it is in the disabled, down, and over states.
You create a skin by using a bitmap image, a SWF file, or a class defined in ActionScript or in MXML. All Flex
components have a default skin class that can represent more than one state of the component. As you can see in
the previous table, the eight states of the Button control use the same default skin class, mx.skins.halo.ButtonSkin,
to draw the skin. Logic within the class determines the appearance of the Button control based on its current state.
You assign a skin to a component by using style properties. You can set a style property by using MXML tag
properties, the StyleManager class, <mx:Style> blocks, or style sheets. Most Flex application use style sheets to
organize and apply skins. Style sheets can be loaded at compile time or at run time. For information on loading
style sheets at run time, see “Loading style sheets at run time” on page 633.
Types of skins
You typically define a skin as a bitmap graphic or as a vector graphic. Bitmap graphics, called graphical skins in
Flex, are made up of individual pixels that together form an image. The downside of a bitmap graphic is that it is
typically defined for a specific resolution and, if you scale or transform the image, you might notice a degradation
in image quality.
A vector graphic, called a programmatic skin in Flex, consists of a set of line definitions that specify a line’s starting
and end point, thickness, color, and other information required by Adobe® Flash® Player to draw the line. When
a vector graphic is scaled, rotated, or modified in some other way, it is relatively simple for Flash Player to calculate
the new layout of the vector graphic by transforming the line definitions. Therefore, you can perform many types
of modifications to vector graphics without noticing any degradation in quality.
ADOBE FLEX 3 691
Adobe Flex 3 Developer Guide
One advantage of programmatic skins is you can create vector graphics that allow you a great deal of program-
matic control over the skin. For example, you can control the radius of a Button control’s corners by using
programmatic skins, something you cannot do with graphical skins. You can develop programmatic skins directly
in your Flex authoring environment or any text editor, without using a graphics tool such as Adobe Flash.
Programmatic skins also tend to use less memory because they contain no external image files.
The following table describes the different types of skins:
Graphical skins Images that define the appearance of the skin. These images can JPEG, GIF, or PNG files, or they can be
symbols embedded in SWF files. Typically you use drawing software such as Adobe® PhotoShop® or Adobe®
Illustrator® to create graphical skins.
Programmatic skins ActionScript or MXML classes that define a skin. To change the appearance of controls that use programmatic
skins, you edit an ActionScript or MXML file. You can use a single class to define multiple skins.
Stateful skins A type of programmatic skin that uses view states, where each view state corresponds to a state of the compo-
nent. The definition of the view state controls the look of the skin. Since you can have multiple view states in
a component, you can use a single component to define multiple skins.
<mx:Style>
Button {
upSkin: Embed("../assets/orb_up_skin.gif");
}
</mx:Style>
You can assign the same graphic or programmatic skin to two or more skins so that the skins display the same
image, as the following example shows:
<?xml version="1.0"?>
<!-- skins/SimpleButtonGraphicSkinTwoSkins.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
upSkin: Embed("../assets/orb_up_skin.gif");
overSkin: Embed("../assets/orb_up_skin.gif");
}
</mx:Style>
import mx.skins.ProgrammaticSkin;
// Constructor.
public function ButtonUpSkinAS() {
super();
}
<mx:Style>
Button {
upSkin: ClassReference("ButtonUpSkinAS");
}
</mx:Style>
</skins:ProgrammaticSkin>
Notice that you have to include the xmlns:skins="mx.skins.*" namespace declaration in MXML. This is
necessary because by default you cannot use the ProgrammaticSkin class as the base class of an MXML
component.
In the following example, you create a component that defines skins for multiple Button states. In this example,
you use a case statement to determine the current state of the Button control based on the name property of the
skin, where the name property contains the current name of the skin. For example, if you define a programmatic
skin for a Button control, the name property could be any of the skin states: downSkin, upSkin, overSkin,
disabledSkin, selectedDisabledSkin, selectedDownSkin, selectedOverSkin , or selectedUpSkin.
package {
// skins\ButtonUpAndOverSkinAS.as
import mx.skins.ProgrammaticSkin;
public class ButtonUpAndOverSkinAS extends ProgrammaticSkin {
// Constructor.
public function ButtonUpAndOverSkinAS() {
super();
}
694 CHAPTER 20
case "overSkin": {
graphics.lineStyle(1, 0x0066FF);
graphics.beginFill(0x00CCFF, 0.50);
graphics.drawRoundRect(0, 0, unscaledWidth, unscaledHeight, 10, 10);
}
}
}
}
}
You then assign the ActionScript class to the appropriate skin properties:
<?xml version="1.0"?>
<!-- skins/ApplyButtonUpOverSkinAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
upSkin: ClassReference("ButtonUpAndOverSkinAS");
overSkin: ClassReference("ButtonUpAndOverSkinAS");
}
</mx:Style>
<mx:Script>
<![CDATA[
<mx:states>
<mx:State name="up"/>
<mx:State name="over">
<mx:SetProperty target="{this}"
name="rectFill" value="0x00CCFF"/>
</mx:State>
</mx:states>
</mx:UIComponent>
You typically define a stateful skin as a subclass of UIComponent, in ActionScript or in MXML, because the view
state mechanism is built into the UIComponent class. For more information, see “Creating stateful skins” on
page 727.
You can create a stateful skin in either ActionScript or MXML. This examples uses MXML because it requires
fewer lines of code to define view states. You then assign the MXML component to the skin property of the
Button control, as the following example shows:
<?xml version="1.0"?>
<!-- skins/SimpleButtonStatefulSkin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
skin: ClassReference("ButtonUpStatefulSkin");
downSkin: ClassReference("mx.skins.halo.ButtonSkin");
disabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedUpSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedOverSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDownSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDisabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
When using stateful skins, you must explicitly specify the default skin for all states not defined by the stateful skin
component.
696 CHAPTER 20
Sizing skins
Before a component applies a skin, it first determines its size without the skin. The component then examines the
skin to determine whether the skin defines a specific size. If not, the component scales the skin to fit. If the skin
defines a size, the component sizes itself to the skin.
Most skins do not define any size constraints, which allows the component to scale the skin as necessary. For more
information on writing skins that contain size information, see “Implementing measuredWidth and measured-
Height getters” on page 724.
Skinning subcomponents
In some cases, you want to reskin subcomponents. The following example reskins the vertical ScrollBar control
that appears in List controls:
<?xml version="1.0"?>
<!-- skins/SubComponentSkins.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
[Bindable]
private var theText:String = "Lorem ipsum dolor sit amet, consectetur " +
"adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore " +
"magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
"laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " +
"in reprehenderit in voluptate velit esse cillum dolore eu fugiat " +
"nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt " +
"in culpa qui officia deserunt mollit anim id est laborum.";
]]></mx:Script>
<mx:Style>
.myScrollStyle {
upArrowUpSkin: Embed("../assets/uparrow_up_skin.gif");
downArrowUpSkin: Embed("../assets/downarrow_up_skin.gif");
}
</mx:Style>
<mx:TextArea id="ta1"
width="400"
height="50"
verticalScrollPolicy="on"
verticalScrollBarStyleName="myScrollStyle"
text="{theText}"
/>
</mx:Application>
By setting the value of the verticalScrollBarStyleName property in the List type selector, all vertical ScrollBar
controls in List components have a custom skin. The ScrollBar controls in other parts of the application do not
have the custom skin.
ADOBE FLEX 3 697
Adobe Flex 3 Developer Guide
As with all style sheets, you can define the skins in a separate CSS file and use the source property of the
<mx:Style> tag to point to that file; for example:
<mx:Style source="../stylesheets/MySkins.css"/>
Creating themes
A theme is a collection of style definitions and skins that define the look and feel of a Flex application. Theme files
can include both graphical and programmatic skins, as well as style sheets.
A theme takes the form of a SWC file that can be applied to a Flex application. You compile a SWC file using the
compc command-line compiler utility.
By compiling a SWC file and then using that SWC file as a theme in your application, you remove the burden of
compiling all the skin files when you compile your main application. This can make compilation faster and make
problems with the application code easier to debug. In addition, a SWC file is easier to transplant onto another
application than are a set of classes and image files.
Halo, the default theme set that ships with Flex, is almost entirely made up of programmatic skins, although there
are some static graphic elements. Flex includes programmatic and graphical skins that use the Halo look and feel.
You can edit the skins by using either the programmatic or graphical technique to reskin Halo components.
For more information on creating and applying themes, see “About themes” on page 645.
Skin resources
Flex includes the following graphical and programmatic source files for skins:
Base skin classes in the mx.skins package These abstract skin classes define the basic functionality of skin classes
in Flex. For more information, see “Creating programmatic skins” on page 713.
Programmatic Halo skins in the mx.skins.halo package These concrete skin classes extend the base skin classes in
the mx.skins package. You can extend or edit these skins to create new programmatic skins based on the default
Flex look and feel. For more information, see “Creating programmatic skins” on page 713.
HaloClassic skins These skins were used in Flex 1.x. You can retain the look of Flex 1.x applications by using these
skins. The HaloClassic.swc file is located in the framework/themes directory. For more information, see “About
themes” on page 645.
Graphical Aeon theme The Aeon theme includes the AeonGraphical.css file and the AeonGraphical.swf file that
defines the skin symbols. These are in the framework/themes directory. In addition, Flex includes the FLA source
file for the AeonGraphical.swf file. For more information, see “About themes” on page 645.
You use these files to create skins based on the Flex look and feel, or create your own.
698 CHAPTER 20
Applying skins
You apply skins by using CSS, by specifying them inline in MXML, by calling the setStyle() method, or by using
the StyleManager class.
downSkin="@Embed(source='../assets/orb_down_skin.gif')"/>
</mx:Application>
The location of the skin asset is relative to the location of the MXML file that embeds it.
When embedding inline, you use @Embed (with an at [@] sign prefix) rather than Embed, which you use in CSS
files.
<mx:Button id="b1"
label="Click Me"
overSkin="{ButtonStatesSkin}"
upSkin="{ButtonStatesSkin}"
downSkin="{ButtonStatesSkin}"
disabledSkin="{ButtonStatesSkin}"/>
</mx:Application>
In this example, the SampleButtonSkin.mxml file is in the same directory as the application. If the skin class is in
another directory, you must import the class into the application so that the compiler can resolve the class name,
as the following example shows:
<?xml version="1.0"?>
<!-- skins/ApplyProgrammaticSkinsInlinePackage.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
import myComponents.*;
</mx:Script>
<mx:Button id="b1"
label="Click Me"
overSkin="{myComponents.ButtonStatesSkin}"
upSkin="{myComponents.ButtonStatesSkin}"
downSkin="{myComponents.ButtonStatesSkin}"
disabledSkin="{myComponents.ButtonStatesSkin}"/>
</mx:Application>
When you define stateful skin, you set the skin style property of the control to the class name of your skin
component, as the following example shows:
<?xml version="1.0"?>
<!-- skins/ApplyButtonStatefulSkinInlineAll.mxml -->
ADOBE FLEX 3 701
Adobe Flex 3 Developer Guide
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
import myComponents.*;
</mx:Script>
<mx:Button id="b"
label="Hello"
skin="{myComponents.MyButtonStatefulSkinAll}"/>
</mx:Application>
</mx:Application>
You can apply skins to a single instance of a component by defining a class selector. The following example applies
the custom style to the second button only:
<?xml version="1.0"?>
<!-- skins/EmbedImagesClassSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
.myButtonStyle {
overSkin: Embed("../assets/orb_over_skin.gif");
upSkin: Embed("../assets/orb_up_skin.gif");
downSkin: Embed("../assets/orb_down_skin.gif");
}
</mx:Style>
<mx:Style>
Button {
skin: ClassReference("myComponents.MyButtonStatefulSkinAll");
}
</mx:Style>
<mx:Script>
<![CDATA[
[Embed("../assets/orb_over_skin.gif")]
public var os:Class;
[Embed("../assets/orb_down_skin.gif")]
public var ds:Class;
[Embed("../assets/orb_up_skin.gif")]
public var us:Class;
private function init():void {
704 CHAPTER 20
b1.setStyle("upSkin", us);
b1.setStyle("overSkin", os);
b1.setStyle("downSkin", ds);
}
]]>
</mx:Script>
<mx:Button label="Click Me" id="b1"/>
</mx:Application>
<mx:Script>
<![CDATA[
public function changeSkins():void {
if (cb1.selected) {
b1.setStyle("upSkin", ButtonStatesSkin);
b1.setStyle("downSkin", ButtonStatesSkin);
b1.setStyle("overSkin", ButtonStatesSkin);
b1.setStyle("disabledSkin", ButtonStatesSkin);
} else {
b1.setStyle("upSkin", null);
b1.setStyle("downSkin", null);
b1.setStyle("overSkin", null);
b1.setStyle("disabledSkin", null);
}
}
]]>
</mx:Script>
</mx:Application>
The reference to the ButtonStatesSkin class in the setStyle() method causes the compiler to link in the entire
ButtonStatesSkin class at compile time. The resulting SWF file will be larger than if there were no reference to this
class, even if the changeSkins() method is never called.
In the previous example, the SampleButtonSkin.mxml file is in the same directory as the application. If the skin
class is in another directory, you must import the class into the application so that the compiler can resolve the
class name, as the following example shows:
<?xml version="1.0"?>
<!-- skins/ApplyProgrammaticSkinsSetStylePackage.mxml -->
ADOBE FLEX 3 705
Adobe Flex 3 Developer Guide
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import myComponents.*;
</mx:Application>
When you define stateful skin, you use the setStyle() method to set the skin style property of the control to
the class name of your skin component. For more information on applying stateful skins, see “Creating stateful
skins” on page 727.
<mx:Script>
<![CDATA[
import mx.styles.StyleManager;
[Embed("../assets/orb_over_skin.gif")]
public var os:Class;
[Embed("../assets/orb_down_skin.gif")]
public var ds:Class;
[Embed("../assets/orb_up_skin.gif")]
public var us:Class;
StyleManager.getStyleDeclaration("Button").setStyle("overSkin", os);
StyleManager.getStyleDeclaration("Button").setStyle("downSkin", ds);
}
]]>
</mx:Script>
</mx:Application>
For more information on using the StyleManager class, see “Using the StyleManager class” on page 621.
A B C
A. orb_down_skin.gif B. orb_over_skin.gif C. orb_up_skin.gif
The following example uses graphical skins for the up, over, and down states of the Button control:
<?xml version="1.0"?>
<!-- skins/EmbedImagesTypeSelector.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
overSkin: Embed("../assets/orb_over_skin.gif");
ADOBE FLEX 3 707
Adobe Flex 3 Developer Guide
upSkin: Embed("../assets/orb_up_skin.gif");
downSkin: Embed("../assets/orb_down_skin.gif");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
The reason that you must embed the file is that in order to determine a component’s minimum and preferred sizes,
skin assets must be present as soon as the component is created. If you reference external assets at run time, Flex
does not have the sizing information and, therefore, cannot render the skins properly.
Because skins are embedded, if you change the graphics files that comprise one or more skins, you must recompile
your Flex application for the changes to take effect. For more information on embedding assets, see “Embedding
Assets” on page 969.
One drawback to embedding images as skins is that they can become distorted if you resize the component that
has a skin. You can use a technique called 9-slice scaling to create skins that do not become distorted when the
component is resized. For information on the 9-slice scaling technique, see “Using 9-slice scaling with embedded
images” on page 981.
overSkin: Embed(source='../assets/SubmitButtonSkins.swf',
symbol='MyOverSkin');
downSkin: Embed(source='../assets/SubmitButtonSkins.swf',
symbol='MyDownSkin');
}
</mx:Style>
<mx:Button id="b1"/>
</mx:Application>
You use the same syntax when embedding skin symbols inline, as follows:
<?xml version="1.0"?>
<!-- skins/EmbedSymbolsInline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Button id="b1"
overSkin="@Embed(source='../assets/SubmitButtonSkins.swf',
symbol='MyOverSkin')"
upSkin="@Embed(source='../assets/SubmitButtonSkins.swf',
symbol='MyUpSkin')"
downSkin="@Embed(source='../assets/SubmitButtonSkins.swf',
symbol='MyDownSkin')"/>
</mx:Application>
In the source FLA file, all symbols that you use must meet the following conditions:
• The symbol must be on the Stage. After you create an image file and convert it to a symbol, you must drag it
from the library to the Stage. Flash does not export symbols that are not on the Stage. Alternatively, you can select
the Export in First Frame option in the Linkage Properties dialog box.
• The symbol must have been exported for ActionScript with a linkage name. In Flash, you select the Export for
ActionScript option in the symbol’s Linkage Properties dialog box, as the following example shows:
The linkage name is the name used by Flex. Symbol names are ignored.
ADOBE FLEX 3 709
Adobe Flex 3 Developer Guide
1 You can use 9-slice scaling with image files (a grid with nine regions) so that the skin scales well when the
component’s size changes. You define the properties for 9-slice scaling of images when you apply the skin in CSS,
as the following example shows:
Button {
overSkin: Embed(
"../assets/orb_over_skin.gif",
scaleGridTop=6,
scaleGridLeft=12,
scaleGridBottom=44,
scaleGridRight=49
);
}
For information on embedding assets that use the 9-slice scaling technique, see “Using 9-slice scaling with
embedded images” on page 981.
You can modify programmatic skins that come with Flex or create your own. The programmatic skins used by
Flex components are in the mx.skins.halo package. All of the skins extend one of the following classes: UICom-
ponent, ProgrammaticSkin, Border, or RectangularBorder.
For information on creating your own skins, see “Programmatic skins recipe” on page 713.
One type of programmatic skin, called a stateful skin, uses view states. For information on creating stateful skins,
see “Creating stateful skins” on page 727.
// Extend ProgrammaticSkin.
public class MySkinOutline extends ProgrammaticSkin {
// Constructor.
public function MySkinOutline() {
// Set default values here.
}
ADOBE FLEX 3 711
Adobe Flex 3 Developer Guide
// Override updateDisplayList().
override protected function updateDisplayList(w:Number,
h:Number):void {
// Add styleable properties here.
// Add logic to detect components state and set properties here.
// Add drawing methods here.
}
}
} // Close unnamed package.
In your Flex application, you can apply a programmatic skin using the ClassReference statement in CSS:
<?xml version="1.0"?>
<!-- skins/ApplyMySkinOutline.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
overSkin: ClassReference("MySkinOutline");
upSkin: ClassReference("MySkinOutline");
downSkin: ClassReference("MySkinOutline");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
Most skins extend the mx.skins.ProgrammaticSkin class, but you can select any one of the following as a super-
class for your skin:
• The ProgrammaticSkin class implements the IFlexDisplayObject, ILayoutManagerClient, IInvalidating, and
ISimpleStyleClient interfaces, so it is the easiest and most common superclass to use.
• The Border class extends the ProgrammaticSkin class and adds support for the borderMetrics property. Use
this class or the RectangularBorder class if your skin defines the component’s border.
• The RectangularBorder class extends the Border class and adds support for the backgroundImage style.
• The UIComponent class implements the IStateCleint interface, making it easy to use for stateful skins. It is
also the component that you use when implementing skins in MXML.
Use the following list of steps to create programmatic skins for your Flex controls. Each step is explained in more
detail in the following sections.
To use the methods of the Graphics package, you must import the flash.display.Graphics class, and any other
classes in the flash.display package that you use, such as GradientType or Font. The following example imports all
classes in the flash.display package:
import flash.display.*;
The following example draws a rectangle as a border around the component with the drawRect() method:
g.drawRect(0, 0, width, height);
The following example draws an X with a border around it:
package { // Use unnamed package if this skin is not in its own package.
// skins/CheckboxSkin.as
You check the state by using the name property of the skin. The name is the current name of the skin. For example,
if you define a programmatic skin for a Button control, the name property could be any of the skin states:
downSkin, upSkin, overSkin, disabledSkin, selectedDisabledSkin, selectedDownSkin ,
selectedOverSkin, or selectedUpSkin.
The following example checks which state the Button control is in and adjusts the line thickness and background
fill color appropriately. The result is that when the user clicks the Button control, Flex redraws the skin to change
the line thickness to 2 points. When the user releases the mouse button, the skin redraws again and the line
thickness returns to its default value of 4. The background fill color also changes depending on the Button
control’s state.
package { // Use unnamed package if this skin is not in its own package.
// skins/ButtonStatesSkin.as
// Constructor.
public function ButtonStatesSkin() {
// Set default values.
backgroundFillColor = 0xFFFFFF;
lineThickness = 4;
}
Drawing programmatically
You use the drawing methods of the Graphics class to draw the parts of a programmatic skin. These methods let
you describe fills or gradient fills, define line sizes and shapes, and draw lines. By combining these very simple
drawing methods, you can create complex shapes that make up your component skins.
ADOBE FLEX 3 717
Adobe Flex 3 Developer Guide
The following table briefly describes the most commonly used drawing methods in the Graphics package:
Method Summary
beginFill(0xCCCCFF,1);
If an open path exists (that is, if the current drawing position does not equal the previous position that you
specified in a moveTo() method) and it has a fill associated with it, that path is closed with a line, and then
filled.
beginGradientFill() Begins drawing a gradient fill. If an open path exists (that is, if the current drawing position does not equal
the previous position that you specified in a moveTo() method), and it has a fill associated with it, that path
is closed with a line, and then filled.
clear() Removes all the drawing output associated with the current object. The clear() method takes no argu-
ments.
curveTo() Draws a curve using the current line style; for example:
moveTo(500, 500);
curveTo(600, 500, 600, 400);
curveTo(600, 300, 500, 300);
curveTo(400, 300, 400, 400);
curveTo(400, 500, 500, 500);
drawCircle() Draws a circle after you set the line style and fill. You pass the method the x and y positions of the circle, as
well as the radius, as the following example shows:
drawCircle(10,10,50);
drawRect() Draws a rectangle once you set the line style and fill. You pass the method the x and y positions of the rect-
angle, as well as the length and width of the rectangle, as the following example shows:
drawRect(10,10,100,20);
drawRoundRect() Draws a rectangle with rounded corners, after you set the line and fill. You pass the method the x and y posi-
tion of the rectangle, length and height of the rectangle, and the width and height of the ellipse that is used
to draw the rounded corners, as the following example shows:
drawRoundRect(10,10,100,20,9,5)
endFill() Ends the fill specified by the beginFill() or beginGradientFill() methods. The endFill()
method takes no arguments. If the current drawing position does not equal the previous position that you
specified in a moveTo() method and a fill is defined, the path is closed with a line, and then filled.
lineStyle() Defines the stroke of lines created with subsequent calls to the lineTo() and curveTo() methods. The
following example sets the line style to a 2-point gray line with 100% opacity:
lineStyle(2,0xCCCCCC,1)
You can call the lineStyle() method in the middle of drawing a path to specify different styles for
different line segments within a path. Calls to the clear() method reset line styles back to undefined.
718 CHAPTER 20
Method Summary
lineTo() Draws a line using the current line style. The following example draws a triangle:
If you call the lineTo() method before any calls to the moveTo() method, the current drawing position
returns to the default value of (0, 0).
moveTo() Moves the current drawing position to the specified coordinates; for example:
moveTo(100,10);
var arrowColor:Number;
switch (name) {
case "upIcon":
case "selectedUpIcon": {
arrowColor = 0x666666;
break;
}
case "overIcon":
case "downIcon":
case "selectedOverIcon":
case "selectedDownIcon": {
arrowColor = 0xCCCCCC;
break;
}
}
ADOBE FLEX 3 719
Adobe Flex 3 Developer Guide
// Draw an arrow.
graphics.lineStyle(1, 1, 1);
graphics.beginFill(arrowColor);
graphics.moveTo(unscaledWidth, unscaledHeight-20);
graphics.lineTo(unscaledWidth-30, unscaledHeight+20);
graphics.lineTo(unscaledWidth+30, unscaledHeight+20);
graphics.lineTo(unscaledWidth, unscaledHeight-20);
graphics.endFill();
}
}
} // Close unnamed package.
The ProgrammaticSkin class also defines drawing methods, the most common of which is the drawRoundRect()
method. This method programmatically draws a rectangle and lets you set the corner radius, gradients, and other
properties. You can use this method to customize borders of containers so that they might appear as the following
example shows:
The following code uses the drawRoundRect() method to draw this custom VBox border:
package { // Use unnamed package if this skin is not in its own package.
// skins/CustomContainerBorderSkin.as
// Constructor.
public function CustomContainerBorderSkin() {
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
// Background
drawRoundRect(0, 0, unscaledWidth, unscaledHeight,
{tl: 0, tr:cornerRadius, bl: cornerRadius, br: 0},
720 CHAPTER 20
backgroundColor, backgroundAlpha);
// Shadow
if (!dropShadow)
dropShadow = new RectangularDropShadow();
dropShadow.distance = 8;
dropShadow.angle = 45;
dropShadow.color = 0;
dropShadow.alpha = 0.4;
dropShadow.tlRadius = 0;
dropShadow.trRadius = cornerRadius;
dropShadow.blRadius = cornerRadius;
dropShadow.brRadius = 0;
dropShadow.drawShadow(graphics, 0, 0, unscaledWidth, unscaledHeight);
}
}
}
In your Flex application, you apply this skin as the following example shows:
<?xml version="1.0"?>
<!-- skins/ApplyContainerBorderSkin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox id="vb1"
borderSkin="CustomContainerBorderSkin"
backgroundColor="0xCCCC99"
backgroundAlpha="0.8"
cornerRadius="14"
paddingLeft="20"
paddingTop="20"
paddingRight="20"
paddingBottom="20"
>
<mx:Label text="This is a VBox with a custom skin."/>
</mx:VBox>
</mx:Application>
The unscaledWidth and unscaledHeight properties in the previous examples refer to the measurements of the
skin as the skin itself understands them. These measurements ignore the fact that external components might
have changed the dimensions of the skin. When working inside the component, it is best to use the unscaled
measurements.
The measuredWidth and measuredHeight getters typically return a constant number. The Flex application
usually honors the measured sizes, but not always. If these getters are omitted, the values of measuredWidth and
measuredHeight are set to the default value of 0.
The following example sets the measuredWidth and measuredHeight properties to 10, and then overrides the
getters:
package { // Use unnamed package if this skin is not in its own package.
// skins/ButtonStatesWithMeasuredSizesSkin.as
break;
case "disabledSkin":
lineThickness = 2;
backgroundFillColor = 0xCCCCCC;
break;
}
// Draw the box using the new values.
var g:Graphics = graphics;
g.clear();
g.beginFill(backgroundFillColor,1.0);
g.lineStyle(lineThickness, 0xFF0000);
g.drawRect(0, 0, w, h);
g.endFill();
g.moveTo(0, 0);
g.lineTo(w, h);
g.moveTo(0, h);
g.lineTo(w, 0);
}
}
} // Close unnamed package.
// Constructor.
public function ButtonStatesWithBorderMetricsSkin() {
// Set default values.
backgroundFillColor = 0xFFFFFF;
lineThickness = 4;
}
ADOBE FLEX 3 723
Adobe Flex 3 Developer Guide
<mx:State name="over">
</mx:State>
...
<mx:State name="selectedUp">
</mx:State>
</mx:states>
<mx:Script>
<![CDATA[
<!-- Define the skin by using the Flash drawing API. -->
]]>
</mx:Script>
</mx:UIComponent>
Note: You can create a stateful skin in either ActionScript or MXML. The examples in this section use MXML because
it requires fewer lines of code to define view states.
ADOBE FLEX 3 725
Adobe Flex 3 Developer Guide
After defining your stateful skin, you assign it to the skin style property of the control. You can assign the stateful
control by using CSS, the setStyle() method, by using inline styles, or by using the StyleManager class. The
following example sets it by using CSS:
<?xml version="1.0"?>
<!-- skins/ApplyButtonStatefulSkinAll.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
skin: ClassReference("myComponents.MyButtonStatefulSkinAll");
}
</mx:Style>
<mx:State name="over">
</mx:State>
</mx:states>
...
</mx:UIComponent>
You then specify this component as the value of the skin style property, and specify the default skins for the
remaining six properties, as the following example shows:
<?xml version="1.0"?>
<!-- skins/SimpleButtonStatefulSkin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style>
Button {
skin: ClassReference("ButtonUpStatefulSkin");
downSkin: ClassReference("mx.skins.halo.ButtonSkin");
disabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedUpSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedOverSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDownSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDisabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
}
</mx:Style>
<mx:Button id="b1" label="Click Me"/>
</mx:Application>
726 CHAPTER 20
<mx:Script>
<![CDATA[
import flash.filters.DropShadowFilter;
<mx:Style>
Button {
skin: ClassReference("myComponents.MyButtonStatefulSkin");
disabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedUpSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedOverSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDownSkin: ClassReference("mx.skins.halo.ButtonSkin");
selectedDisabledSkin: ClassReference("mx.skins.halo.ButtonSkin");
}
</mx:Style>
728 CHAPTER 20
<mx:Script>
<![CDATA[
// Embed the skin images.
[Bindable]
[Embed(source="../../assets/orb_up_skin.gif")]
private var buttonUp:Class;
[Bindable]
[Embed(source="../../assets/orb_over_skin.gif")]
private var buttonOver:Class;
[Bindable]
[Embed(source="../../assets/orb_down_skin.gif")]
private var buttonDown:Class;
[Bindable]
[Embed(source="../../assets/orb_disabled_skin.gif")]
private var buttonDisabled:Class;
]]>
</mx:Script>
<mx:states>
<mx:State name="up"/>
<mx:State name="notBase">
<mx:RemoveChild target="{baseButton}"/>
</mx:State>
<mx:State name="over" basedOn="notBase">
<mx:AddChild creationPolicy="all">
<mx:Image source="{buttonOver}"
maintainAspectRatio="false"
width="100%" height="100%"/>
</mx:AddChild>
</mx:State>
<mx:State name="down" basedOn="notBase">
<mx:AddChild creationPolicy="all">
<mx:Image source="{buttonDown}"
maintainAspectRatio="false"
width="100%" height="100%"/>
ADOBE FLEX 3 729
Adobe Flex 3 Developer Guide
</mx:AddChild>
</mx:State>
<mx:State name="disabled" basedOn="notBase">
<mx:AddChild creationPolicy="all">
<mx:Image source="{buttonDisabled}"
maintainAspectRatio="false"
width="100%" height="100%"/>
</mx:AddChild>
</mx:State>
</mx:states>
<mx:Image id="baseButton"
width="100%" height="100%"
source="{buttonUp}"
maintainAspectRatio="false"/>
</mx:Canvas>
In this example the skin performs the following actions:
• Defines no changes from the base view state to create the up view state.
• Defines the notBase view state to remove the image defined by the base view state. All other view states, except
for the up view state, are based on the notBase view state.
• Sets the creationPolicy property to all for each AddChild tag. This property specifies to create the child
instance at application startup, rather than on the first change to the view state. This prevents flickering when
viewing a view state for the first time. For more information, see “Using View States” on page 853.
• Sets the width and height properties to 100% for the Image tags because the Canvas container is what is
being resized by the skin parent, not the individual Image controls. This setting configures the Image control to
size itself to its parent.
• Sets the maintainAspectRatio property to false on each Image tag so that the image stretches to fill the
full size of the Canvas container.
<mx:Script>
<![CDATA[
730 CHAPTER 20
import flash.filters.DropShadowFilter;
<mx:states>
<mx:State name="up">
</mx:State>
<mx:State name="over">
<mx:SetProperty target="{this}"
name="rectFill" value="0x00CC33"/>
<mx:SetProperty target="{myFilter}"
name="distance" value="4"/>
</mx:State>
<mx:State name="down">
<mx:SetProperty target="{this}"
ADOBE FLEX 3 731
Adobe Flex 3 Developer Guide
name="rectFill" value="0x00CC33"/>
<mx:SetProperty target="{myFilter}"
name="inner" value="true"/>
<mx:SetProperty target="{myFilter}"
name="distance" value="2"/>
</mx:State>
</mx:states>
<mx:transitions>
<mx:Transition>
<mx:AnimateProperty target="{this}"
property="rectFill" duration="100"/>
</mx:Transition>
</mx:transitions>
</mx:UIComponent>
import flash.display.GradientType;
import flash.display.Graphics;
import mx.skins.Border;
import mx.styles.StyleManager;
732 CHAPTER 20
import mx.utils.ColorUtil;
import mx.skins.halo.HaloColors;
import mx.core.UIComponent;
// User-defined styles
var borderColor:uint = getStyle("borderColor");
var fillAlphas:Array = getStyle("fillAlphas");
var fillColors:Array = getStyle("fillColors");
StyleManager.getColorNames(fillColors);
var highlightAlphas:Array = getStyle("highlightAlphas");
var themeColor:uint = getStyle("themeColor");
switch (name) {
case "upIcon": {
upFillColors = [ fillColors[0], fillColors[1] ];
upFillAlphas = [ fillAlphas[0], fillAlphas[1] ];
if (parent is UIComponent) {
myParent = String(UIComponent(parent).className);
}
if (myParent=="RadioButton") {
// RadioButton border
g.beginGradientFill(GradientType.LINEAR,
[ borderColor, 0x000000 ],
[100,100], [0,0xFF],
verticalGradientMatrix(0,0,w,h));
g.drawCircle(r,r,r);
g.drawCircle(r,r,(r-1));
ADOBE FLEX 3 733
Adobe Flex 3 Developer Guide
g.endFill();
// RadioButton fill
g.beginGradientFill(GradientType.LINEAR,
upFillColors,
upFillAlphas,
[0,0xFF],
verticalGradientMatrix(1,1,w-2,h-2));
g.drawCircle(r,r,(r-1));
g.endFill();
} else if (myParent=="CheckBox") {
// CheckBox border
drawRoundRect(0,0,w,h,0,
[borderColor, 0x000000], 1,
verticalGradientMatrix(0,0,w,h),
GradientType.LINEAR,
null, {x: 1,y:1,w:w-2,h:h-2,r:0});
// CheckBox fill
drawRoundRect(1, 1, w-2, h-2, 0,
upFillColors, upFillAlphas,
verticalGradientMatrix(1,1,w-2,h-2));
}
// top highlight
drawRoundRect(1, 1, w-2,
(h-2)/2, {tl:r,tr:r,bl:0,br:0},
[0xFFFFFF, 0xFFFFFF],
highlightAlphas,
verticalGradientMatrix(0,0,w-2,(h-2)/2));
}
You should wrap this call to the getStyle() method in a check to see if the style exists. If the property was not
set, the result of the getStyle() method can be unpredictable.
The following example verifies if the property is defined before assigning it a value:
if (getStyle("lineThickness")) {
_lineThickness = getStyle("lineThickness");
}
You must define a default value for the skin’s styleable properties. You usually do this in the skin’s constructor
function. If you do not define a default value, the style property is set to NaN or undefined if the Flex application
does not define that style. This can cause a run-time error.
The following example of the MyButtonSkin programmatic skin class defines default values for the
_lineThickness and _backgroundFillColor styleable properties in the skin’s constructor. It then adds calls to
the getStyle() method in the updateDisplayList() method to make these properties styleable:
package { // Use unnamed package if this skin is not in its own package.
// skins/ButtonStylesSkin.as
// Constructor.
public function ButtonStylesSkin() {
// Set default values.
_backgroundFillColor = 0xFFFFFF;
_lineThickness=2;
}
g.moveTo(0, 0);
g.lineTo(w, h);
g.moveTo(0, h);
g.lineTo(w, 0);
}
}
} // Close unnamed package.
In your Flex application, you can set the values of styleable properties by using CSS or the setStyle() method.
The following example sets the value of styleable properties on all Button controls with a CSS:
<?xml version="1.0"?>
<!-- skins/ApplyButtonStylesSkin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600" height="600">
<mx:Style>
Button {
upSkin:ClassReference('ButtonStylesSkin');
downSkin:ClassReference('ButtonStylesSkin');
overSkin:ClassReference('ButtonStylesSkin');
disabledSkin:ClassReference('ButtonStylesSkin');
lineThickness:4;
backgroundFillColor:#CCCCCC;
}
</mx:Style>
<mx:Script><![CDATA[
public function changeLineThickness(e:Event):void {
var t:int = Number(b1.getStyle("lineThickness"));
if (t == 4) {
b1.setStyle("lineThickness",1);
} else {
b1.setStyle("lineThickness",4);
}
}
]]></mx:Script>
<mx:Button id="b1" label="Change Line Thickness" click="changeLineThickness(event)"/>
<mx:Button id="b2"/>
</mx:Application>
When using the setStyle() method to set the value of a style property in your Flex application, you can set the
value of a styleable property on a single component instance (as in the previous example) or on all instances of a
component. The following example uses the setStyle() method to set the value of a styleable property on all
instances of the control (in this case, all Button controls):
<?xml version="1.0"?>
<!-- skins/ApplyGlobalButtonStylesSkin.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600" height="600">
<mx:Style>
Button {
upSkin:ClassReference('ButtonStylesSkin');
downSkin:ClassReference('ButtonStylesSkin');
overSkin:ClassReference('ButtonStylesSkin');
disabledSkin:ClassReference('ButtonStylesSkin');
lineThickness:4;
736 CHAPTER 20
backgroundFillColor:#CCCCCC;
}
</mx:Style>
<mx:Script><![CDATA[
public function changeLineThickness(e:Event):void {
var t:int = Number(b1.getStyle("lineThickness"));
if (t == 4) {
StyleManager.getStyleDeclaration("Button").setStyle("lineThickness", 1);
} else {
StyleManager.getStyleDeclaration("Button").setStyle("lineThickness", 4);
}
}
]]></mx:Script>
</mx:Application>
If you do not set the values of these properties using either CSS or the setStyle() method, Flex uses the default
values of the properties that you set in the skin’s constructor.
To get the value of an existing style property, such as color or fontSize, you do not have to wrap the call to the
getStyle() method in a check for the property’s existence. This is because Flex creates a CSSStyleDeclaration
that defines the default values of all of a component’s styles. Preexisting style properties are never undefined. Style
properties that you add to a custom skin are not added to this CSSStyleDeclaration because the component does
not know that the property is a style property.
Custom skin properties that you define as styleable are noninheritable. So, subclasses or children of that
component do not inherit the value of that property.
741
Topics
About drag and drop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 741
Using drag-and-drop with list-based controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
Manually adding drag-and-drop support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 750
Using drag and drop with Flex applications running in AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761
Drag and drop examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763
Moving and copying data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 770
Dragging While still holding down the mouse button, the user moves the mouse around the Flex application. Flex
displays an image during the drag, called the drag proxy. A drag source object (an object of type DragSource)
contains the data being dragged.
Dropping When the user moves the drag proxy over another Flex component, that component becomes a
possible drop target. The drop target inspects the drag source object to determine whether the data is in a format
that the target accepts and, if so, allows the user to drop the data onto it. If the drop target determines that the data
is not in an acceptable format, the drop target disallows the drop.
A drag-and-drop operation either copies or moves data from the drag initiator to the drop target. Upon a
successful drop, Flex adds the data to the drop target and, optionally, deletes it from the drag initiator in the case
of a move.
The following figure shows one List control functioning as the drag initiator and a second List control functioning
as the drop target. In this example, you use drag and drop to move the ’Television’ list item from the drag initiator
to the drop target:
Television
(drag proxy)
Reading
Television Television
Movies
List control List control
(drag initiator) (drop target)
A single Flex component can function as both the drag initiator and the drop target. This lets you move the data
within the component. The following example shows a List control functioning as both the drag initiator and the
drop target:
List control
(drag initiator and drop target)
By specifying the List control as both the drag initiator and the drop target, you can use drag and drop to rearrange
the items in the control. For example, if you use a Canvas container as the drag initiator and the drop target, you
can then use drag and drop to move controls in the Canvas container to rearrange them.
ADOBE FLEX 3 743
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
<mx:HBox>
<mx:VBox>
<mx:Label text="Available Activities"/>
<mx:List id="srclist"
allowMultipleSelection="true"
dragEnabled="true"
dragMoveEnabled="true"/>
</mx:VBox>
<mx:VBox>
<mx:Label text="Activities I Like"/>
<mx:List id="destlist"
dropEnabled="true"/>
</mx:VBox>
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
By setting the dragEnabled property to true on the first List and the dropEnabled property to true on the
second List control, you enabled users to drag items from the first list to the second without worrying about any
of the underlying event processing.
For all list classes except the Tree control, the default value of the dragMoveEnabled property is false, so you
can only copy elements from one control to the other. By setting the dragMoveEnabled to true in the first List
control, you can move and copy data. For the Tree control, the default value of the dragMoveEnabled property is
true.
When the dragMoveEnabled property is set to true, the default drag-and-drop action is to move the drag data.
To perform a copy, hold down the Control key during the drag-and-drop operation.
The only requirement on the drag and drop operation is that the structure of the data providers must match for
the two controls. In this example, the data provider for srclist is an Array of Strings, and the data provider for the
destination List control is an empty Array. If the data provider for destlist is an Array of some other type of data,
destlist might not display the dragged data correctly.
You can modify the dragged data as part of a drag-and-drop operation to make the dragged data compatible with
the destination. For an example of dragging data from one control to another when the data formats do not match,
see “Example: Copying data from a List control to a DataGrid control” on page 773.
ADOBE FLEX 3 745
Adobe Flex 3 Developer Guide
You can allow two-way drag and drop by setting the dragEnabled, dropEnabled, and dragMoveEnabled
properties to true for both list-based controls, as the following example shows for two DataGrid controls. In this
example, you can drag and drop rows from either DataGrid control to the other:
<?xml version="1.0"?>
<!-- dragdrop\SimpleDGToDG.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
<mx:VBox>
<mx:Label text="Buy These Albums"/>
<mx:DataGrid id="destgrid"
allowMultipleSelection="true"
dragEnabled="true"
dropEnabled="true"
dragMoveEnabled="true">
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
746 CHAPTER 21
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
<mx:Script>
<![CDATA[
// Initialize the data provider for the Tree.
private function initApp():void {
firstList.dataProvider = treeDP;
}
]]>
</mx:Script>
<mx:XML id="treeDP">
<node label="Mail">
<node label="Inbox"/>
<node label="Personal Folder">
<node label="Demo"/>
<node label="Personal"/>
<node label="Saved Mail"/>
<node label="bar"/>
</node>
<node label="Calendar"/>
<node label="Sent"/>
<node label="Trash"/>
</node>
</mx:XML>
<mx:Tree id="firstList"
showRoot="false"
labelField="@label"
dragEnabled="true"
dropEnabled="true"
allowMultipleSelection="true"
creationComplete="initApp();"/>
</mx:Application>
ADOBE FLEX 3 747
Adobe Flex 3 Developer Guide
Property/Method Description
dropIndicatorSkin Specifies the name of the skin to use for the drop-insert indicator which shows where the dragged data will
be inserted.
dragEnabled A Boolean value that specifies whether the control is a drag initiator. The default value is false. When true,
users can drag selected items from the control. When a user drags items from the control, Flex creates a Drag-
Source object that contains the following data objects:
dropEnabled A Boolean value that specifies whether the control can be a drop target that uses default values for handling
items dropped onto it. The default value is false, which means that you must write event handlers for the
drag events. When the value is true, you can drop items onto the control by using the default drop behavior.
When you set dropEnabled to true, Flex automatically calls the showDropFeedback() and
hideDropFeedback() methods to display the drop indicator.
dragMoveEnabled If the value is true, and the dragEnabled property is true, specifies that you can move or copy items from
the drag initiator to the drop target. When you move an item, the item is deleted from the drag initiator when
you add it to the drop target.
If the value is false, you can only copy an item to the drop target. For a copy, the item in the drag initiator is
not affected by the drop.
When the dragMoveEnabled property is true, you must hold down the Control key during the drop oper-
ation to perform a copy.
The default value is false for all list controls except the Tree control, and true for the Tree control.
748 CHAPTER 21
Property/Method Description
calculateDropIndex Returns the item index in the drop target where the item will be dropped. Used by the dragDrop event
handler to add the items in the correct location.
hideDropFeedback() Hides drop target feedback and removes the focus rectangle from the target. You typically call this method
from within the handler for the dragExit and dragDrop events.
showDropFeedback() Specifies to display the focus rectangle around the target control and positions the drop indicator where the
drop operation should occur. If the control has active scroll bars, hovering the mouse pointer over the control’s
top or bottom scrolls the contents.
You typically call this method from within the handler for the dragOver event.
[RemoteClass]
public class Car extends Object
{
// Constructor.
public function Car()
{
super();
}
// Class properties.
public var numWheels:int;
public var model:String;
public var make:String;
}
}
Notice that the Car.as file includes the [RemoteClass] metadata tag. This metadata tag is required to register the
Car data type with Flex so that its type information is preserved during the copy operation. If you omit the
[RemoteClass] metadata tag, type information is lost.
You then use that class in your application, as the following example shows:
<?xml version="1.0"?>
<!-- dragdrop\DandDRemoteClassListUpdated.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" xmlns="*">
<mx:Script>
<![CDATA[
public function changeit():void
{
if (list2.dataProvider != null)
{
msg.text += list2.dataProvider[0]
if(list2.dataProvider[0] is Car)
msg.text += " Is Car\n";
else
msg.text += " Is NOT Car\n";
}
}
]]>
</mx:Script>
<mx:List id="list1"
x="10" y="45"
width="160" height="120"
dragEnabled="true"
dragMoveEnabled="true">
<mx:dataProvider>
<mx:Array>
<Car model="Camry" make="Toyota" numWheels="4"/>
<Car model="Prius" make="Toyota" numWheels="4"/>
</mx:Array>
</mx:dataProvider>
</mx:List>
<mx:List id="list2"
x="200" y="45"
width="160" height="120"
dropEnabled="true"/>
<mx:TextArea id="msg"
x="10" y="200"
width="400" height="100"/>
</mx:Application>
750 CHAPTER 21
Class Function
DragManager Manages the drag-and-drop operations; for example, its doDrag() method starts the drag operation.
DragSource Contains the data being dragged. It also provides additional drag management features, such as the ability to add
a handler that is called when data is requested.
mouseDown and The mouseDown event is dispatched when the user selects a control Yes, for nonlist No
mouseMove with the mouse and holds down the mouse button. The mouseMove controls
event is dispatched when the mouse moves.
dragStart Dispatched by a list-based component when a drag operation starts. Yes, for list Yes
This event is used internally by the list-based controls; you do not controls
handle it when implementing drag and drop.
dragComplete Dispatched when a drag operation completes, either when the drag No Yes
data drops onto a drop target, or when the drag-and-drop operation
ends without performing a drop operation.
You can use this event to perform any final cleanup of the drag-and-
drop operation. For example, if a user moves data from one compo-
nent to another, you can use this event to delete the item from the
drag initiator. For an example, see “Example: Moving and copying
data for a nonlist-based control” on page 774.
When adding drag-and-drop support to a component, you must implement an event handler for either the
mouseDown or mouseMove event, and optionally for the dragComplete event. When you set the dragEnabled
property to true for a list-based control, Flex automatically adds event handlers for the dragStart and
dragComplete events.
Note: Do not add an event handler for the dragStart event. That is an internal event handled by Flex.
752 CHAPTER 21
dragEnter Dispatched when a drag proxy moves over the drop target from Yes Yes
outside the drop target.
In the handler, you can change the appearance of the drop target to
provide visual feedback to the user that the component can accept
the drag operation. For example, you can draw a border around the
drop target, or give focus to the drop target. For an example, see
“Example: Simple drag-and-drop operation for a nonlist-based
control” on page 755.
dragOver Dispatched while the user moves the mouse over the target, after the No Yes
dragEnter event.
You can handle this event to perform additional logic before allowing
the drop operation, such as dropping data to various locations within
the drop target, reading keyboard input to determine if the drag-and-
drop operation is a move or copy of the drag data, or providing
different types of visual feedback based on the type of drag-and-drop
operation. For an example, see “Example: Handling the dragOver and
dragExit events for the drop target” on page 767.
dragDrop Dispatched when the user releases the mouse over the drop target. Yes Yes
Use this event handler to add the drag data to the drop target. For an
example, see “Example: Simple drag-and-drop operation for a
nonlist-based control” on page 755.
dragExit Dispatched when the user moves the drag proxy off of the drop No Yes
target, but does not drop the data onto the target.
You can use this event to restore the drop target to its normal appear-
ance if you modified its appearance in response to a dragEnter
event or other event. For an example, see “Example: Handling the
dragOver and dragExit events for the drop target” on page 767.
ADOBE FLEX 3 753
Adobe Flex 3 Developer Guide
When adding drag-and-drop support to a nonlist-based component, you must implement an event handler for
the dragEnter and dragDrop events, and optionally for the other events. When you set the dropEnabled
property to true for a list-based control, Flex automatically adds event handlers for all events.
The dragEnter event handler can examine the DragSource object to determine whether the data being
dragged is in an accepted format. To accept the drop, the event handler calls the
DragManager.acceptDragDrop() method. You must call the DragManager.acceptDragDrop() method
for the drop target to receive the dragOver, dragExit, and dragDrop events.
• If the drop target does not accept the drop, the drop target component’s parent chain is examined to
determine if any component in the chain accepts the drop data.
• If the drop target or a parent component accepts the drop, Flex dispatches the dragOver event as the user
moves the proxy over the target.
4 (Optional) The drop target can handle the dragOver event. For example, the drop target can use this event
handler to set the focus on itself.
5 (Optional) If the user decides not to drop the data onto the drop target and moves the drag proxy outside of
the drop target without releasing the mouse button, Flex dispatches a dragExit event for the drop target. The
drop target can optionally handle this event; for example, to undo any actions made in the dragOver event
handler.
6 If the user releases the mouse while over the drop target, Flex dispatches a dragDrop event on the drop target.
• List-based components with dropEnabled=true
Flex automatically adds the drag data to the drop target. If this is a copy operation, you have to implement
the event handler for the dragDrop event for a list-based control. For more information, see “Example:
Copying data from one List control to another List control” on page 771.
• Nonlist-based components, or list-based components with dropEnabled=false
The drop target must define an event listener for the dragDrop event handler to add the drag data to the
drop target.
7 (Optional) When the drop operation completes, Flex dispatches a dragComplete event. The drag initiator
can handle this event; for example, to delete the drag data from the drag initiator in the case of a move.
• List-based components with dragEnabled=true
If this is a move operation, Flex automatically removes the drag data from the drag initiator.
• Nonlist-based components, or list-based components with dragEnabled=false
The drag initiator completes any final processing required. If this was a move operation, the event handler
must remove the drag data from the drag initiator. For an example of writing the event handler for the
dragComplete event, see “Example: Moving and copying data for a nonlist-based control” on page 774.
ADOBE FLEX 3 755
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.core.DragSource;
import mx.managers.DragManager;
import mx.events.*;
import mx.containers.Canvas;
// Called when the user moves the drag proxy onto the drop target.
private function dragEnterHandler(event:DragEvent):void {
// Called if the target accepts the dragged object and the user
// releases the mouse button while over the Canvas container.
private function dragDropHandler(event:DragEvent):void {
<!-- A horizontal box with red and green canvases that the user can drag. -->
<mx:HBox>
<mx:Canvas
width="30" height="30"
backgroundColor="red"
borderStyle="solid"
mouseMove="mouseMoveHandler(event);"/>
<mx:Canvas
width="30" height="30"
backgroundColor="green"
borderStyle="solid"
mouseMove="mouseMoveHandler(event);"/>
</mx:HBox>
<mx:Label text="Drag a color onto the Canvas container."/>
<mx:Button id="b1"
label="Clear Canvas"
click="myCanvas.setStyle('backgroundColor', '0xFFFFFF');"
/>
</mx:Application>
The following sections describe the event handlers for the mouseDown, dragEnter, and dragDrop events.
You use the DragSource.addData() method to add the drag data and format to the DragSource object,
where the addData() method has the following signature:
addData(data:Object, format:String):void
The format argument is a text string such as "color", "list data", or "employee record". In the event
handler for the dragEnter event, the drop target examines this string to determine whether the data format
matches the type of data that the drop target accepts. If the format matches, the drop target lets users drop the
data on the target; if the format does not match, the target does not enable the drop operation.
One example of using the format string is when you have multiple components in your application that
function as drop targets. Each drop target examines the DragSource object during its dragEnter event to
determine if the drop target supports that format. For more information, see “Handling the dragEnter event”
on page 757.
Note: List controls have predefined values for the format argument. For all list controls other than the Tree
control, the format String is "items". For the Tree control, the format String is "treeItems". For more infor-
mation, see “Using drag-and-drop with list-based controls” on page 743.
If you drag large or complex data items, consider creating a handler to copy the data, and specify it by calling
the DragSource.addListener() method instead of using the DragSource.addData() method. If you do
this, the data does not get copied until the user drops it, which avoids the processing overhead of copying the
data if a user starts dragging data but never drops it. The implementation of the list-based classes use this
technique.
2 Call the DragManager.doDrag() method to start the drag-and-drop operation.
The doDrag() method has the following signature:
doDrag(dragInitiator:IUIComponent, dragSource:DragSource, mouseEvent:MouseEvent,
dragImage:IFlexDisplayObject = null, xOffset:Number = 0, yOffset:Number = 0,
imageAlpha:Number = 0.5, allowMove:Boolean = true):void
The doDrag() method requires three arguments: a reference to the component that initiates the drag
operation (identified by the event.currentTarget object); the DragSource object that you created in step
1, and the event object passed to the event handler.
Optional arguments specify the drag proxy image and the characteristics of the image. For an example that
specifies a drag proxy, see “Example: Specifying the drag proxy” on page 765.
• If the drag data is in a compatible format, the handler must call the DragManager.acceptDragDrop()
method to enable the user to drop the data on the drop target. If the event handler does not call this method, the
user cannot drop the data and the drop target will not receive the dragOver, dragExit, and dragDrop events.
• Optionally, perform any other actions necessary when the user first drags a drag proxy over a drop target.
The value of the action property of the event object for the dragEnter event is DragManager.MOVE, even if you
are doing a copy. This is because the dragEnter event occurs before the drop target recognizes that the Control
key is pressed to signal a copy.
The Flex default event handler for the dragOver event for a list-based control automatically sets the action
property. For nonlist-based controls, or if you explicitly handle the dragOver event for a list-based control, use
the DragManager.showFeedback() method to set the action property to a value that signifies the type of drag
operation: DragManager.COPY, DragManager.LINK, DragManager.MOVE, or DragManager.NONE. For more
information on the dragOver event, see “Example: Handling the dragOver and dragExit events for the drop
target” on page 767.
Define your own event handlers If you want to control the drag-and-drop operation for a list-based control, you
can explicitly handle the drag-and-drop events, just as you can for any component. In this scenario, set the
dragEnabled property to false for a drag initiator, or set the dropEnabled property to false for a drop target.
For more information on handling these events, see “Example: Simple drag-and-drop operation for a nonlist-
based control” on page 755.
Define your own event handlers and use the default event handlers You might want to add your own event
handler for a drag-and-drop event, and also use the build in drag-and-drop handlers. In this case, your event
handler executes first, then the default event handler provided by Flex executes. If, for any reason, you want to
explicitly prohibit the execution of the default event handler, call the Event.preventDefault() method from
within your event handler.
Note: If you call Event.preventDefault() in the event handler for the dragComplete or dragDrop event for a
Tree control when dragging data from one Tree control to another, it prevents the drop.
Because of the way data to a Tree control is structured, the Tree control handles drag and drop differently from
the other list-based controls. For the Tree control, the event handler for the dragDrop event only performs an
action when you move or copy data in the same Tree control, or copy data to another Tree control. If you drag data
from one Tree control and drop it onto another Tree control to move the data, the event handler for the
dragComplete event actually performs the work to add the data to the destination Tree control, rather than the
event handler for the dragDrop event, and also removes the data from the source Tree control. This is necessary
because to reparent the data being moved, Flex must remove it first from the source Tree control.
Therefore, if you call Event.preventDefault() in the event handler for the dragDrop or dragComplete events,
you implement the drop behavior yourself. For more information, see “Example: Moving and copying data for a
nonlist-based control” on page 774.
The following example modifies the example shown in the section “Example: Moving and copying data for a
nonlist-based control” on page 774 to define an event handler for the dragDrop event that accesses the data
dragged from one DataGrid control to another. This event handler is executed before the default event handler for
the dragDrop event to display in an Alert control the Artist field of each DataGrid row dragged from the drag
initiator to the drop target:
<?xml version="1.0"?>
<!-- dragdrop\SimpleDGToDGAlert.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.controls.Alert;
import mx.collections.ArrayCollection;
Alert.show(artistList);
}
]]>
</mx:Script>
<mx:HBox>
<mx:VBox>
<mx:Label text="Available Albums"/>
<mx:DataGrid id="srcgrid"
allowMultipleSelection="true"
dragEnabled="true"
dropEnabled="true"
dragMoveEnabled="true">
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
<mx:VBox>
<mx:Label text="Buy These Albums"/>
<mx:DataGrid id="destgrid"
allowMultipleSelection="true"
dragEnabled="true"
dropEnabled="true"
dragMoveEnabled="true"
dragDrop="dragDropHandler(event);">
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
ADOBE FLEX 3 761
Adobe Flex 3 Developer Guide
</mx:VBox>
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
Notice that the dataForFormat() method specifies an argument value of "items". This is because the list-based
controls have predefined values for the data format of drag data. For all list controls other than the Tree control,
the format String is "items". For the Tree control, the format String is "treeItems".
Notice also that the return value of the dataForFormat() method is an Array. The dataForFormat() method
always returns an Array for a list-based control, even if you are only dragging a single item, because list-based
controls let you select multiple items.
3 Your main application file uses the <mx:Application> tag, but loads the AIR drag-and-drop manager as
represented by the mx.managers.NativeDragManagerImpl class. In this scenario, you use the AIR drag-and-drop
manager, and can drag and drop items from outside of AIR.
For the third scenario, to use the AIR drag-and-drop manager in your Flex application, you must write your appli-
cation to link to mx.managers.NativeDragManagerImpl class, and to load it at runtime, as the following example
shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initDandD();">
<mx:Script>
<![CDATA[
// Ensure that the NativeDragManagerImpl class is linked in to your
application.
import mx.managers.NativeDragManagerImpl;
var placeholder:NativeDragManagerImpl;
...
</mx:Application>
Two drag-and-drop events work differently depending on whether your application runs in Adobe® Flash® Player
or AIR, as the following table shows:
dragEnter Triggers many times when you move the mouse Triggers once when you move the mouse pointer over any compo-
pointer over any component during a drag and drop nent during a drag and drop operation.
operation.
The default value of the DragEvent.action property is
The default value of the DragEvent.action prop- DragEvent.COPY.
erty is DragEvent.MOVE.
dragOver Triggers many times when you drag an item over a Triggers many times when you drag an item over any component,
valid drop target. even if the component is not a valid drop target.
ADOBE FLEX 3 763
Adobe Flex 3 Developer Guide
There are several other differences between the Flex and AIR drag managers, as described below:
Cursors Flex draws the drag-and-drop cursors. The operating system draws the cursors.
Drag proxy You can control the drag proxy. The operating system controls the drag proxy, but you can
still specify a drag image.
Drag image The drag image of the drag proxy can be an instance of By default, the drag image is a bitmap created from the
the DisplayObject class, including an animated SWF file, object being dragged. It does not change dynamically as the
an image, or a Flex component. user drags it.
Drop animation The DragProxy class animaties the drag image based on No custom animations can be used. The operating system
the results of the drop, such as accepted or rejected. handles the behavior of the cursor and the drag image.
Argument Description
To specify a symbol, such as a JPEG image of a product that a user wants to order, use a string that specifies the symbol’s
name, such as myImage.jpg.
To specify a component, such as a Flex container or control, create an instance of the control or container, configure and
size it, and then pass it as an argument to the doDrag() method.
xOffset Number that specifies the x offset, in pixels, for the dragImage. This argument is optional. If omitted, the drag proxy is
shown at the upper-left corner of the drag initiator. The offset is expressed in pixels from the left edge of the drag proxy
to the left edge of the drag initiator, and is usually a negative number.
yOffset Number that specifies the y offset, in pixels, for the dragImage. This argument is optional. If omitted, the drag proxy is
shown at the upper-left corner of the drag initiator. The offset is expressed in pixels from the top edge of the drag proxy
to the top edge of the drag initiator, and is usually a negative number.
imageAlpha A Number that specifies the alpha value used for the drag proxy image. If omitted, Flex uses an alpha value of 0.5. A value
of 0 corresponds to transparent and a value of 1.0 corresponds to fully opaque.
You must specify a size for the drag proxy image, otherwise it does not appear. The following example modifies
the example in “Example: Using a container as a drop target” on page 763 to use a 15 pixel by 15 pixel Image
control as the drag proxy:
<?xml version="1.0"?>
<!-- dragdrop\DandDImageProxy.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
//Import classes so you don't have to use full names.
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.events.DragEvent;
import flash.events.MouseEvent;
ds.addData(dragInitiator, "img");
Example: Handling the dragOver and dragExit events for the drop target
The dragOver event occurs when the user moves the mouse over a drag-and-drop target whose dragEnter event
handler has called the DragManager.acceptDragDrop() method. This event is dispatched continuously as the
user drags the mouse over the target. The dragOver event handler is optional; you do not have to define it to
perform a drag-and-drop operation.
The dragOver event is useful for specifying the visual feedback that the user gets when the mouse is over a drop
target. For example, you can use the DragManager.showFeedback() method to specify the drag-feedback
indicator that appears within the drag proxy image. This method uses four constant values for the argument, as
the following table shows:
DragManager.COPY A green circle with a white plus sign indicating that you can perform the drop.
DragManager.LINK A grey circle with a white arrow sign indicating that you can perform the drop.
DragManager.MOVE A plain arrow indicating that you can perform the drop.
DragManager.NONE A red circle with a white x appears indicating that a drop is prohibited. This is the same image that appears
when the user drags over an object that is not a drag target.
You typically show the feedback indicator based on the keys pressed by the user during the drag-and-drop
operation. The DragEvent object for the dragOver event contains Boolean properties that indicate whether the
Control or Shift keys are pressed at the time of the event: ctrlKey and shiftKey, respectively. No key pressed
indicates a move, the Control key indicates a copy, and the Shift key indicates a link. You then call the
showFeedback() method as appropriate for the key pressed.
Another use of the showFeedback() method is that it determines the value of the action property of the
DragEvent object for the dragDrop, dragExit, and dragComplete events. If you do not call the
showFeedback() method in the dragOver event handler, the action property of the DragEvent is always set to
DragManager.MOVE.
The dragExit event is dispatched when the user drags the drag proxy off the drop target, but does not drop the
data onto the target. You can use this event to restore any visual changes that you made to the drop target in the
dragOver event handler.
In the following example, you set the dropEnabled property of a List control to true to configure it as a drop
target and to use the default event handlers. However, you want to provide your own visual feedback, so you also
define event handlers for the dragEnter, dragExit, and dragDrop events. The dragOver event handler
completely overrides the default event handler, so you call the Event.preventDefault() method to prohibit the
default event handler from execution.
768 CHAPTER 21
The dragOver event handler determines whether the user is pressing a key while dragging the proxy over the
target, and sets the feedback appearance based on the key that is pressed. The dragOver event handler also sets
the border color of the drop target to green to indicate that it is a viable drop target, and uses the dragExit event
handler to restore the original border color.
For the dragExit and dragDrop handlers, you only want to remove any visual changes that you made in the
dragOver event handlers, but otherwise you want to rely on the default Flex event handlers. Therefore, these event
handlers do not call the Event.preventDefault() method:
<?xml version="1.0"?>
<!-- dragdrop\DandDListToListShowFeedback.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
<mx:Script>
<![CDATA[
import mx.managers.DragManager;
import mx.events.DragEvent;
import mx.collections.ArrayCollection;
private function initApp():void {
firstList.dataProvider = new ArrayCollection([
{label:"First", data:"1"},
{label:"Second", data:"2"},
{label:"Third", data:"3"},
{label:"Fourth", data:"4"}
]);
secondList.dataProvider = new ArrayCollection([]);
}
if (event.dragSource.hasFormat("items"))
{
// Set the border to green to indicate that
// this is a drop target.
// Since the dragOver event is dispatched continuosly
// as you move over the drop target, only set it once.
ADOBE FLEX 3 769
Adobe Flex 3 Developer Guide
if (borderColorSet == false) {
tempBorderColor =
event.currentTarget.getStyle('borderColor');
borderColorSet = true;
}
<mx:HBox id="myHB">
<mx:List id="firstList"
dragEnabled="true"
dragMoveEnabled="true"/>
<mx:List id="secondList"
borderThickness="2"
dropEnabled="true"
dragOver="dragOverHandler(event);"
dragDrop="dragExitHandler(event);"
dragExit="dragExitHandler(event);"/>
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
770 CHAPTER 21
Example: Copying data from one List control to another List control
The following example lets you copy items from one List control to another. In this example, even though you set
the dropEnabled property to true in the drop target, you still write an event handler for the dragDrop event. The
event handler calls Event.preventDefualt() to explicitly prohibit the default event handler from executing.
The reason to set the dropEnabled property to true in the drop target is so that Flex automatically handles all of
the other events (dragEnter, dragOver, and dragExit) on the drop target.
Note: You call Event.preventDefault() because the drop target is a List control, one of the list-based controls that
defines a default dragDrop handler. In the case of a copy, you want to explicitly handle the dragDrop event, but use
all the other default event handlers. For a nonlist-based component, you do not have to call
Event.preventDefault() because only list-based controls define default drag-and-drop event handlers.
The default value of the dragMoveEnabled property is false, so that you can only copy elements from one List
control to the other. If you modify the example to set dragMoveEnabled to true in the drag initiator, you can
move and copy elements. To copy a list element, hold down the Control key during the drag-and-drop operation:
<?xml version="1.0"?>
<!-- dragdrop\DandDListToListCopy.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.collections.IList;
import mx.collections.ArrayCollection;
<mx:HBox>
<mx:List id="firstList"
dragEnabled="true"/>
<mx:List id="secondList"
dropEnabled="true"
dragDrop="dragDropHandler(event);"/>
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
To perform the copy, the event handler creates a new Object, then copies the individual data fields of the drag data
into the new Object. Then, the event handler adds the new Object to the drop target’s data provider.
Unlike the example in the section “Example: Moving and copying data for a nonlist-based control” on page 774,
you do not have to write the dragOver or dragComplete event handlers. While Flex cannot perform the copy,
Flex does recognize when you perform a copy or a move, and automatically removes the data from the drag
initiator for you on a move.
ADOBE FLEX 3 773
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.collections.IList;
import mx.collections.ArrayCollection;
var itemsArray:Array =
event.dragSource.dataForFormat('items') as Array;
var tempItem:Object =
{ label: itemsArray[0].label,
data: itemsArray[0].data,
774 CHAPTER 21
IList(dropTarget.dataProvider).addItemAt(tempItem, dropLoc);
}
}
]]>
</mx:Script>
<mx:HBox>
<mx:List id="srcList"
dragEnabled="true"
dragMoveEnabled="true"/>
<mx:DataGrid id="destDG"
dropEnabled="true"
dragDrop="dragDropHandler(event);">
<mx:columns>
<mx:DataGridColumn dataField="label"/>
<mx:DataGridColumn dataField="data"/>
<mx:DataGridColumn dataField="date"/>
</mx:columns>
</mx:DataGrid>
</mx:HBox>
<mx:Button id="b1"
label="Reset"
click="initApp()"
/>
</mx:Application>
In the following example, you drag an Image control from one Canvas container to another. As part of the drag-
and-drop operation, you can move the Image control, or copy it by holding down the Control key. If you perform
a move, the dragComplete event handler removes the Image control from its original parent container:
<?xml version="1.0"?>
<!-- dragdrop\DandDImageCopyMove.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="horizontal">
<mx:Script>
<![CDATA[
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.events.DragEvent;
import flash.events.MouseEvent;
return;
}
else {
DragManager.showFeedback(DragManager.MOVE);
return;
}
}
DragManager.showFeedback(DragManager.NONE);
}
if (event.action == DragManager.MOVE)
dragInitCanvas.removeChild(draggedImage);
}
]]>
</mx:Script>
<!-- Canvas holding the Image control that is the drag initiator. -->
<mx:Canvas
width="250" height="500"
borderStyle="solid"
backgroundColor="#DDDDDD">
<!-- The Image control is the drag initiator and the drag proxy. -->
<mx:Image id="myimg"
source="@Embed(source='assets/globe.jpg')"
mouseMove="mouseOverHandler(event);"
dragComplete="dragCompleteHandler(event);"/>
</mx:Canvas>
ADOBE FLEX 3 777
Adobe Flex 3 Developer Guide
Topics
About item renderers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779
Creating an item renderer and item editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788
Creating drop-in item renderers and item editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797
Creating inline item renderers and editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 800
Creating item renderers and item editor components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807
Working with item renderers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813
A list control gets its data from a data provider. A data provider is a collection that contains a data object such as
an Array or XMLList object. For example, a Tree control reads data from a data provider to define the structure
of the tree and any associated data that is assigned to each tree node. Collections are objects that contain a set of
methods that let you access, sort, filter, and modify the data items in a data object. The standard collection types
are the ArrayCollection and XMLListCollection classes, for working with Array-based and XMLList-based data,
respectively.
Collections provide a level of abstraction between Flex components and the data that you use to populate them.
You can populate multiple components from the same collection, switch the collection that a component uses as
a data provider at run time, or modify a collection so that changes are reflected by all components that use it as a
data provider.
You can think of the data provider as the model, and the Flex components as the view of the model. By separating
the model from the view, you can change one without changing the other. Each list control has a default
mechanism for controlling the display of data, or view, and lets you override that default. To override the default
view, you create a custom item renderer.
In addition to controlling the display of data using an item renderer, the DataGrid, List, and Tree controls let users
edit the data. For example, you could let users update the Quantity column of a DataGrid control if you are using
it for a shopping cart. As with the display of data, the list controls have a default mechanism for letting users edit
data that you can override by creating a custom item editor.
In this example, the List control uses the default item renderer to display each of the three strings that represent
postal codes for Alaska, Alabama, and Arkansas. You use the following code to create this List control:
<?xml version="1.0"?>
ADOBE FLEX 3 781
Adobe Flex 3 Developer Guide
The following code creates the example shown in the previous image:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\DGDefaultRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted', Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners', Price:11.99}
]);
]]>
</mx:Script>
width="100%" editable="true">
<mx:columns>
<mx:DataGridColumn dataField="Artist" resizable="true"/>
<mx:DataGridColumn dataField="Album" resizable="true"/>
<mx:DataGridColumn dataField="Price" resizable="true"/>
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
An editable component lets the user modify the data in the list control, and propagates the changes in the data
back to the underlying data provider of the control. The DataGrid, List, and Tree controls have a property named
editable that, if set to true, lets you edit the contents of a cell. By default, the list controls use a TextInput control
as the item editor. That means when you select a cell in the list control, Flex opens a TextInput control that
contains the current contents of the cell and lets you edit it, as the following image shows:
In this image, you use the default item editor to edit the price of the first album in the DataGrid control.
For more information on item editors, see “Working with Item Editors” on page 821.
The following List control is a modification of the List control in the section “Default item rendering and cell
editing” on page 780. In this example, you use a custom item renderer to display the state name, capital, and a URL
to the state’s official website in each list item:
For the code for this example, see “Example: Using an item renderer with a List control” on page 816.
In the next image, you use a default item renderer for the first and third columns of the DataGrid control. You use
a custom item renderer for the second column to display the album cover along with the album title in the
DataGrid control.
For the code for this example, see “Creating a complex inline item renderer or item editor” on page 802.
784 CHAPTER 22
Just as you can define a custom item renderer to control the display of a cell, you can use a custom item editor to
edit the contents of the cell. For example, if the custom item renderer displays an image, you could define a custom
item editor that uses a ComboBox control that lets users select an image from a list of available images. Or you
could use a CheckBox control to let the user set a true or false value for a cell, as the right side of the following
example shows:
For the code for this example, see “Creating a simple item editor component” on page 810.
Using an item renderer does not imply that the control also has an item editor. Often, you do not allow your
controls to be edited; that is, they are for display only.
You can also use an item editor without a corresponding item renderer. For example, you could display infor-
mation such as a male/female or true/false as text using the default item renderer. But, you could then use a custom
item editor with a ComboBox control that provides the user only a limited set of options to enter into the cell when
changing the value.
The following image shows the relationship of a list control to an item renderer or item editor:
data property
item renderer
list control
Item editor
To pass information to an item renderer or item editor, Flex sets the data property of the item renderer or item
editor to the cell data. In the previous image, you can see the data property that is used to pass the data to the item
renderer or item editor.
By default, an item editor can pass back a single value to the list control that becomes the new value of the edited
cell. To return more than one value, you must write additional code to return the data back to the list control. For
more information, see “Example: Passing multiple values back from an item editor” on page 840.
Any Flex component that you want to use in an item renderer or item editor, and that requires access to the cell
data of the list control, must implement the IDataRenderer interface to support the data property. You can use
additional components in an item renderer that do not support the data property, if those components do not
need to access data passed from the list control.
The contents of the data property depend on the type of control, as the following table shows:
DataGrid Contains the data provider element for the entire row of the DataGrid control. That means if you use a different item
renderer for each cell of the DataGrid control, each cell in a row receives the same information in the data property.
Tree Contains the data provider element for the node of the List or Tree control.
List
786 CHAPTER 22
TileList
Menu Contains the data provider element for the menu item.
MenuBar Contains the data provider element for the menu bar item.
For more information about item editors, see “Working with Item Editors” on page 821.
The following table describes the interfaces that you use with item renderers and item editors:
Interface Use
IDataRenderer Defines the data property used to pass information to an item renderer or item editor. All item
renderers and item editors must implement this interface.
Many Flex components implement this interface, such as the chart renderer classes and many Flex
controls.
IDropInListItemRenderer Defines the listData property required by drop-in item renderers and item editors. All drop-in item
renderers and item editors must implement this interface. For more information, see “Creating drop-in
item renderers and item editors” on page 797.
The listData property is of type BaseListData, where the BaseListData class has three subclasses:
DataGridListData, ListData, TreeListData. The actual data type of the value of the listData property
depends on the control using the drop-in item renderer or item editor. For a DataGrid control, the value
is of type DataGridListData; for a List control, the value is of type ListData; and for a Tree control, the
value is of type TreeListData.
IListItemRenderer Defines the complete set of interfaces that an item renderer or item editor must implement to be used
with any Flex control other than a Chart control. A renderer for a Chart control has to implement only
the IDataRenderer interface.
The UIComponent class implements all of these interfaces, except the IDataRenderer interface. There-
fore, if you create a custom item renderer or item editor as a subclass of the UIComponent class, you
have to implement only the IDataRenderer interface. If you implement a drop-in item renderer or item
editor as a subclass of the UIComponent class, you have to implement only the IDataRenderer and
IDropInListItemRenderer interfaces.
For the HorizontalList control, Flex can use the value of the columnWidth property, if specified. For the TileList
control, Flex uses the values of the columnWidth and rowHeight properties. If you omit these properties, Flex
examines the control’s data provider to determine the default size of each cell, including an item renderer, if
specified. Otherwise, Flex sets the height and width of each cell to 50 pixels.
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{label1:"Order #2314", quant:3, Sent:true},
{label1:"Order #2315", quant:3, Sent:false}
]);
]]>
ADOBE FLEX 3 789
Adobe Flex 3 Developer Guide
</mx:Script>
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{label1:"Order #2314", quant:3, Sent:true},
{label1:"Order #2315", quant:3, Sent:false}
]);
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{label1:"Order #2314", quant:3, Sent:true},
{label1:"Order #2315", quant:3, Sent:false}
]);
]]>
</mx:Script>
However, an item renderer by default is not connected to the editing mechanism of the list control; it does not
propagate changes to the list control’s data provider, nor does it dispatch an event when the user modifies the cell.
Although the list control appears to the user to be editable, it really is not.
In another example, the user changes the value of the CheckBox control, and then sorts the DataGrid column. But
the DataGrid sorts the cell by the value in the data provider, not the value in the CheckBox control, so the user
perceives that the sort works incorrectly.
You can manage this situation in several ways, including the following:
• In your item renderer, do not use controls that let users modify them (CheckBox, ComboBox, and others).
• Create custom versions of these controls to prohibit user interaction with them.
• Use the rendererIsEditor property of the list control to specify that the item renderer is also an item editor.
For more information, see “Example: Using an item renderer as an item editor” on page 844.
• Write your own code for the item renderer and hosting control to pass data back from the item renderer when
you do let users interact with it. For more information and an example, see “Example: Passing multiple values back
from an item editor” on page 840.
<mx:Script>
<![CDATA[
import mx.core.ClassFactory;
<mx:Object label="Alaska"
data="Juneau"
webPage="http://www.state.ak.us/"/>
<mx:Object label="Alabama"
data="Montgomery"
webPage="http://www.alabama.gov/" />
<mx:Object label="Arkansas"
data="Little Rock"
webPage="http://www.state.ar.us/"/>
</mx:dataProvider>
</mx:List>
</mx:Application>
Shown below is the code for the RenderState.mxml item renderer:
<?xml version="1.0"?>
<!-- itemRenderers\list\RendererState.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
// Import Event and URLRequest classes.
import flash.events.Event;
import flash.net.URLRequest;
<mx:HBox >
<!-- Use Label controls to display state and capital names. -->
<mx:Label id="State" text="State: {data.label}"/>
<mx:Label id="Statecapital" text="Capital: {data.data}" />
</mx:HBox>
Because Flex can reuse an item renderer, ensure that you fully define its state. For example, you use a CheckBox
control in an item renderer to display a true (checked) or false (unchecked) value based on the current value of
the data property. A common mistake is to assume that the CheckBox control in the item renderer is always in
its default state of unchecked. Developers then write an item renderer to inspect the data property for a value of
true and set the CheckBox control to checked if found.
However, you must take into account that the CheckBox may already be checked. So, you must inspect the data
property for a value of false, and explicitly uncheck the control if it is checked.
Property Description
owner A reference to the list control that uses the item renderer or item editor.
rowIndex The index of the row of the DataGrid, List, or Tree control relative to the currently visible rows of the control, where
the first row is at an index of 1.
label The text representation of the item data based on the List class’s itemToLabel() method.
The BaseListData class has three subclasses: DataGridListData, ListData, TreeListData that define additional
properties. For example, the DataGridListData class adds the columnIndex and dataField properties that you
can access from an item renderer or item editor.
The data type of the value of the listData property depends on the control that uses the item renderer or item
editor. For a DataGrid control, the value is of type DataGridListData; for a List control, the value is of type
ListData; and for a Tree control, the value is of type TreeListData.
The TextArea control is one of the Flex controls that implements the IDropInListItemRenderer interface The item
renderer in the following example uses the listData property of the TextArea control to display the row and
column of each item renderer in the DataGrid control:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\myComponents\RendererDGListData.mxml -->
<mx:TextArea xmlns:mx="http://www.adobe.com/2006/mxml"
preinitialize="initTA();">
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridListData;
ADOBE FLEX 3 795
Adobe Flex 3 Developer Guide
import flash.events.Event;
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var initDG:ArrayCollection = new ArrayCollection([
{ Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', Date: '5/5/05'},
{ Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', Date: '5/6/05'}
]);
]]>
</mx:Script>
itemRenderer="myComponents.RendererDGListData"/>
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
This code produces the following image of the DataGrid control:
As you can see in this image, each cell of the DataGrid control displays its column and row index.
By inserting the [Bindable] metadata tag before the class definition, you specify that all public properties
support data binding. For more information on data binding, see “Binding Data” on page 1229 and “Metadata
Tags in Custom Components” on page 33 in Creating and Extending Adobe Flex 3 Components.
The following table lists the components that you can use as drop-in item renderers and item editors, and the
default property of the component:
CheckBox selected If used as a drop-in item renderer in a Tree control, the Tree displays only check boxes
with no text.
DateField selectedDate Requires that the data provider of the list control has a field of type Date.
Image source Set an explicit row height by using the rowHeight property, or set the
variableRowHeight property to true to size the row correctly.
Label text
NumericStepper value
Text text
TextArea text
TextInput text
In the following example, you use the NumericStepper, DateField, and CheckBox controls as the drop-in item
renderers and item editors for a DataGrid control:
<?xml version="1.0"?>
<!-- itemRenderers\inline\CBInlineCellEditor.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{label1:"Order #2314", contact:"John Doe",
quant:3, solddate:new Date(2005, 0, 1), Sent:true},
{label1:"Order #2315", contact:"Jane Doe",
quant:3, solddate:new Date(2005, 0, 5), Sent:false}
]);
]]>
</mx:Script>
<mx:DataGrid id="myDG"
dataProvider="{myDP}"
variableRowHeight="true"
width="500" height="250"
editable="true">
<mx:columns>
<mx:DataGridColumn dataField="label1"
ADOBE FLEX 3 799
Adobe Flex 3 Developer Guide
headerText="Order #"
editable="false"/>
<mx:DataGridColumn dataField="quant"
headerText="Quantity"
itemEditor="mx.controls.NumericStepper"
editorDataField="value"/>
<mx:DataGridColumn dataField="solddate"
headerText="Date"
itemRenderer="mx.controls.DateField"
rendererIsEditor="true"
editorDataField="selectedDate"/>
<mx:DataGridColumn dataField="Sent"
itemRenderer="mx.controls.CheckBox"
rendererIsEditor="true"
editorDataField="selected"/>
</mx:columns >
</mx:DataGrid>
</mx:Application>
To determine the field of the data provider used to populate the drop-in item renderer, Flex uses the value of the
dataField property for the <mx:DataGridColumn> tag. In this example, you do the following:
• You set the dataField property of the second column to quant, and define the NumericStepper control as
the item editor. Therefore, the column displays the cell value as text, and opens the NumericStepper control when
you select the cell to edit it. The NumericStepper control displays the current value of the cell, and any changes
you make to it are copied back to the data provider of the DataGrid control.
• You set the dataField property of the third column to solddate, and define the DateField control as the item
renderer and item editor by setting the rendererIsEditor property to true. The data provider defines the data
as an object of type Date, which is required to use the DateField control as the item renderer or item editor.
Therefore, the column displays the date value using the DateField control, and also uses the DateField control to
edit the cell value.
• You set the dataField property of the fourth column to Sent, and define the CheckBox control as the item
renderer and item editor. Typically, you use itemEditor property to specify a different class as the item editor,
and specify to use the same control as both the item renderer and item editor by setting the rendererIsEditor
property to true. The CheckBox control displays a check mark in the cell if the Sent field for the row is set to true,
and an empty check box if the field is set to false.
For more information on using an item renderer as an item editor, see “Creating an editable cell” on page 822.
Note: When you use a CheckBox control as a drop-in item renderer, the control appears flush against the left cell
border. To center a CheckBox control, or any drop-in item renderer, create a custom item renderer that wraps the
control in a container, such as the HBox container. However, the addition of the container can affect application
performance when you are rendering large amounts of data. For more information, see “Creating item renderers and
item editor components” on page 807.
When you use the Image control as a drop-in item renderer, you usually have to set the row height to accom-
modate the image, as the following example shows:
800 CHAPTER 22
<?xml version="1.0"?>
<!-- itemRenderers\DGDropInImageRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99, Cover:'../assets/slanted.jpg'},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99, Cover:'../assets/brighten.jpg'}
]);
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99, Cover: '../assets/slanted.jpg'},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99, Cover: '../assets/brighten.jpg'}
]);
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{label1:"Order #2314", quant:3, Sent:true},
{label1:"Order #2315", quant:3, Sent:false}
802 CHAPTER 22
]);
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
<mx:Text id="albumName"
width="100%"
selectable="false"
text="{data.Album}"/>
<mx:Image id="albumImage"
height="45"
source="{data.Cover}"/>
<mx:TextArea
text="{'Renderer localVar= ' + localVar}"/>
<mx:TextArea
text="{'Application localVar= ' + outerDocument.localVar}"/>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
One use of the outerDocument keyword is to initialize the data provider of a control in the inline item editor. For
example, you can use a web service, or other mechanism, to pass data into the application, such as the list of U.S.
states. You can then initialize all ComboBox controls that are used as item editors from a single property of the
application that contains the list of U.S. states.
806 CHAPTER 22
[Bindable]
public var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', City: 'Boston', State: 'MA'},
{Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', City: 'SanFrancisco', State: 'CA'}
]);
]]>
</mx:Script>
<mx:Component id="inlineEditor">
<mx:ComboBox>
<mx:dataProvider>
<mx:String>AL</mx:String>
<mx:String>AK</mx:String>
<mx:String>AR</mx:String>
</mx:dataProvider>
</mx:ComboBox>
</mx:Component>
<mx:DataGrid id="myGrid"
variableRowHeight="true"
dataProvider="{initDG}"
editable="true" >
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
ADOBE FLEX 3 807
Adobe Flex 3 Developer Guide
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="City"/>
<mx:DataGridColumn dataField="State"
width="150"
editorDataField="selectedItem"
itemEditor="{inlineEditor}"/>
</mx:columns>
</mx:DataGrid>
<mx:DataGrid id="myGrid2"
variableRowHeight="true"
dataProvider="{initDG}"
editable="true">
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="City"/>
<mx:DataGridColumn dataField="State"
width="150"
editorDataField="selectedItem"
itemEditor="{inlineEditor}"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
In this example, you specify the id property of the inline item editor defined by the <mx:Component> tag. You
then use data binding to specify the editor as the value of the itemEditor property for the two DataGrid controls.
The inline item editor or item renderer defined in the <mx:Component> tag appears only where you use it in the
DataGrid control; otherwise, Flex ignores it when laying out your application.
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99, Cover: '../assets/slanted.jpg'},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99, Cover: '../assets/brighten.jpg'}
]);
]]>
</mx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
variableRowHeight="true">
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
ADOBE FLEX 3 809
Adobe Flex 3 Developer Guide
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Cover"
itemRenderer="myComponents.RendererDGImage"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
The DataGrid control contains a column for the album cover that uses the itemRenderer property to specify the
name of the MXML file that contains the item renderer for that column. Now, when you run this example, the
DataGrid control uses your custom item renderer for the Cover column to display an image of the album cover.
Rather than having the album name and album image in separate cells of the DataGrid control, you can use an
item renderer to make them appear in a single cell, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\inline\myComponents\RendererDGTitleImage.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
horizontalAlign="center" height="75">
<mx:Text id="albumName"
width="100%"
selectable="false"
text="{data.Album}"/>
<mx:Image id="albumImage"
source="{data.Cover}"/>
</mx:VBox>
You save this item renderer to the RendererDGTitleImage.mxml file. The DataGrid control in the main appli-
cation references the item renderer, as the following example shows:
<?xml version="1.0"?>
<!-- itemRenderers\MainDGTitleRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99, Cover: '../assets/slanted.jpg'},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99, Cover: '../assets/brighten.jpg'}
]);
]]>
</mx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
variableRowHeight="true">
<mx:columns>
<mx:DataGridColumn dataField="Artist" />
<mx:DataGridColumn dataField="Album"
itemRenderer="myComponents.RendererDGTitleImage" />
<mx:DataGridColumn dataField="Price" />
810 CHAPTER 22
</mx:columns>
</mx:DataGrid>
</mx:Application>
In the preceding example, you define three columns in the DataGrid control, and assign your item renderer to the
second column. For an image that shows the output of this application, see “Using custom item renderers and item
editors” on page 782.
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Embed(source="saleIcon.jpg")]
[Bindable]
public var sale:Class;
[Embed(source="noSaleIcon.jpg")]
[Bindable]
public var noSale:Class;
// myComponents/CellField.as
import mx.controls.*;
import mx.core.*;
import mx.controls.dataGridClasses.DataGridListData;
if (value != null)
{
text = value[DataGridListData(listData).dataField];
if(Number(text) > 100)
{
setStyle("backgroundColor", 0xFF0000);
}
}
else
{
// If value is null, clear text.
text= "";
}
super.invalidateDisplayList();
}
}
}
In the preceding example, you create a subclass of the TextInput control as your item renderer. The class must be
public to be used as an item renderer or editor. This item renderer displays a red background if the value of the
DataGrid cell is greater than 100.
You can use this item renderer in a DataGrid control, as the following example shows:
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- itemRenderers\asRenderer\MainASItemRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
ADOBE FLEX 3 813
Adobe Flex 3 Developer Guide
width="600" height="600">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Monday: 12, Tuesday: 22, Wednesday: 452, Thursday: 90},
{Monday: 258, Tuesday: 22, Wednesday: 45, Thursday: 46},
{Monday: 4, Tuesday: 123, Wednesday: 50, Thursday: 95},
{Monday: 12, Tuesday: 52, Wednesday: 111, Thursday: 20},
{Monday: 22, Tuesday: 78, Wednesday: 4, Thursday: 51}
]);
]]>
</mx:Script>
The following image shows a HorizontalList control that is used to display a product catalog:
Each item in the HorizontalList control contains an image, a descriptive text string, and a price. The following
code shows the application that displays the catalog. The item renderer for the HorizontalList control is an MXML
component named Thumbnail.
<?xml version="1.0"?>
<!-- itemRenderers\MainTlistThumbnailRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HorizontalList id="myList"
columnWidth="125"
rowHeight="125"
columnCount="4"
dataProvider="{catalog.product}"
itemRenderer="myComponents.Thumbnail"/>
</mx:Application>
The file catalog.xml defines the data provider for the HorizontalList control:
<?xml version="1.0"?>
<catalog>
<product id="1">
<name>Nokia Model 3595</name>
<price>129.99</price>
<image>../assets/products/Nokia_3595.gif</image>
<thumbnail>../assets/products/Nokia_3595_sm.gif</thumbnail>
</product>
<product id="2">
<name>Nokia Model 3650</name>
<price>99.99</price>
<image>../assets/products/Nokia_3650.gif</image>
<thumbnail>../assets/products/Nokia_3650_sm.gif</thumbnail>
</product>
<product id="3">
<name>Nokia Model 6010</name>
<price>49.99</price>
<image>../assets/products/Nokia_6010.gif</image>
<thumbnail>../assets/products/Nokia_6010_sm.gif</thumbnail>
</product>
<product id="4">
<name>Nokia Model 6360</name>
<price>19.99</price>
<image>../assets/products/Nokia_6360.gif</image>
ADOBE FLEX 3 815
Adobe Flex 3 Developer Guide
<thumbnail>../assets/products/Nokia_6360_sm.gif</thumbnail>
</product>
<product id="5">
<name>Nokia Model 6680</name>
<price>19.99</price>
<image>../assets/products/Nokia_6680.gif</image>
<thumbnail>../assets/products/Nokia_6680_sm.gif</thumbnail>
</product>
<product id="6">
<name>Nokia Model 6820</name>
<price>49.99</price>
<image>../assets/products/Nokia_6820.gif</image>
<thumbnail>../assets/products/Nokia_6820_sm.gif</thumbnail>
</product>
</catalog>
The following example shows the Thumbnail.mxml MXML component. In this example, you define the item
renderer to contain three controls: an Image control and two Label controls. These controls examine the data
property that is passed to the item renderer to determine the content to display.
<?xml version="1.0" ?>
<!-- itemRenderers\htlist\myComponents\Thumbnail.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
horizontalAlign="center"
verticalGap="0" borderStyle="none" backgroundColor="white" >
[Embed(source="saleIcon.jpg")]
[Bindable]
public var sale:Class;
816 CHAPTER 22
]]>
</mx:Script>
</mx:HBox>
This item renderer uses a Label control to insert the text “Sale Price!” and an Image control to insert an icon in
the column header.
The following example shows the main application:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\MainDGHeaderRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99, SalePrice: true },
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99, SalePrice: false }
]);
]]>
</mx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
variableRowHeight="true">
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
<mx:DataGridColumn width="150" dataField="SalePrice"
headerRenderer="myComponents.RendererDGHeader"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
In this example, the DataGrid control displays the String true or false in the column to indicate that the price
is a sale price. You can also define an item renderer for that column to display a more compelling icon rather than
text. For an example that uses an item renderer with a DataGrid control, see “Using custom item renderers and
item editors” on page 782.
<?xml version="1.0"?>
<!-- itemRenderers\list\MainListStateRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
height="700" width="700">
<mx:List id="myList"
height="180" width="250"
variableRowHeight="true"
itemRenderer="myComponents.RendererState"
backgroundColor="white" >
<mx:dataProvider>
<mx:Object label="Alaska"
data="Juneau"
webPage="http://www.state.ak.us/"/>
<mx:Object label="Alabama"
data="Montgomery"
webPage="http://www.alabama.gov/" />
<mx:Object label="Arkansas"
data="Little Rock"
webPage="http://www.state.ar.us/"/>
</mx:dataProvider>
</mx:List>
</mx:Application>
The previous example sets the rowHeight property to 75 pixels because the item renderer displays content that
exceeds the default row height of the List control. To see an image that shows this application, see “Using custom
item renderers and item editors” on page 782.
The following item renderer, RendererState.mxml, displays the parts of each List item, and creates a LinkButton
control which lets you open the state’s website:
<?xml version="1.0"?>
<!-- itemRenderers\list\myComponents\RendererState.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
// Import Event and URLRequest classes.
import flash.events.Event;
import flash.net.URLRequest;
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(super.data)
{
if(TreeListData(super.listData).hasChildren)
ADOBE FLEX 3 819
Adobe Flex 3 Developer Guide
{
var tmp:XMLList =
new XMLList(TreeListData(super.listData).item);
var myStr:int = tmp[0].children().length();
super.label.text = TreeListData(super.listData).label +
"(" + myStr + ")";
}
}
}
}
}
For each node that has a child node, this item renderer displays the node text in red and includes the count of the
number of child nodes in parentheses. The following example uses this item renderer in an application.
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- itemRenderers\tree\MainTreeItemRenderer.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="initCollections();">
<mx:Script>
<![CDATA[
import mx.collections.*;
[Bindable]
public var xlcBalanced:XMLListCollection;
}
]]>
</mx:Script>
<mx:Text width="400"
text="The nodes with children are in bold red text, with the number of children
in parenthesis.)"/>
<mx:Tree id="compBalanced"
width="400" height="500"
dataProvider="{xlcBalanced}"
labelField="@label"
itemRenderer="myComponents.MyTreeItemRenderer"/>
</mx:Application>
821
Topics
The cell editing process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 821
Creating an editable cell. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 822
Returning data from an item editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 823
Sizing and positioning an item editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 826
Creating an item editor that responds to the Enter key. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828
Using cell editing events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829
Item editor examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836
Examples using item editors with the list-based controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 846
6 Flex dispatches the itemEditEnd event to close the item editor and update the list-based control with the new
cell data. You can use this event to modify the data returned to the cell, validate the new data, or return data in a
format other than the format returned by the item editor. For more information, see “Example: Modifying data
passed to or received from an item editor” on page 837.
7 The new data value appears in the cell.
false (default) Specifies the item renderer. Specifies the item editor.
As this table shows, the state of the rendererIsEditor property defines whether to use a custom item renderer
as the item editor, or a custom item editor. If you set the rendererIsEditor property to true, Flex uses the item
renderer as an item editor, and ignores the itemEditor property.
For an example, see “Example: Using an item renderer as an item editor” on page 844.
ADOBE FLEX 3 823
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{label1:"Order #2314", quant:3, Sent:true},
{label1:"Order #2315", quant:3, Sent:false}
]);
]]>
</mx:Script>
<mx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
public var cbSelected:Boolean;
]]>
</mx:Script>
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', Date: '5/5/05' , FollowUp: true },
{Company: 'Allied', Contact: 'Jane Smith',
ADOBE FLEX 3 825
Adobe Flex 3 Developer Guide
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true" >
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="Date"/>
<mx:DataGridColumn dataField="FollowUp"
width="150"
headerText="Follow Up?"
itemEditor="myComponents.EditorDGCheckBox"
editorDataField="cbSelected"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
Notice that the editorDataField property is set to cbSelected, the new property of the VBox container.
You also use this same mechanism with an inline item renderer that contains multiple controls. For example, you
can modify the previous DataGrid example to use an inline item editor, rather than an item editor component, as
the following code shows:
<?xml version="1.0"?>
<!-- itemRenderers\inline\InlineDGCheckBoxEditor.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', Date: '5/5/05' , FollowUp: true },
{Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', Date: '5/6/05' , FollowUp: false}
]);
]]>
</mx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true">
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="Date"/>
<mx:DataGridColumn dataField="FollowUp"
width="150"
headerText="Follow Up?"
826 CHAPTER 23
editorDataField="cbSelected">
<mx:itemEditor>
<mx:Component>
<mx:VBox backgroundColor="yellow">
<mx:Script>
<![CDATA[
// Define a property for returning
// the new value to the cell.
[Bindable]
public var cbSelected:Boolean;
]]>
</mx:Script>
<mx:CheckBox id="followUpCB"
label="Follow up needed"
height="100%" width="100%"
selected="{data.FollowUp}"
click="cbSelected=followUpCB.selected"/>
</mx:VBox>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</mx:Application>
Property Description
editorHeightOffset Specifies the height of the item editor, in pixels, relative to the size of the cell for a DataGridColumn control,
or the text field of a Tree control.
ADOBE FLEX 3 827
Adobe Flex 3 Developer Guide
Property Description
editorWidthOffset Specifies the width of the item editor, in pixels, relative to the size of the cell for a DataGridColum control,
or the text field of a Tree control.
editorXOffset Specifies the x location of the upper-left corner of the item editor, in pixels, relative to the upper-left corner
of the cell for a DataGridColumn control, or from the upper-left corner of the text field of a Tree control.
editorYOffset Specifies the y location of the upper-left corner of the item editor, in pixels, relative to the upper-left corner
of the cell for a DataGridColumn control, or from the upper-left corner of the text field of a Tree control.
The following code modifies the definition of the DataGridColumn control from the previous section to use the
editorXOffset and editorYOffset properties to move the item editor down and to the right by 15 pixels so
that it has a more prominent appearance in the DataGrid control:
<?xml version="1.0"?>
<!-- itemRenderers\inline\InlineDGCheckBoxEditorWithOffsets.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', Date: '5/5/05' , FollowUp: true },
{Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', Date: '5/6/05' , FollowUp: false}
]);
]]>
</mx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true" >
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="Date"/>
<mx:DataGridColumn dataField="FollowUp"
width="150"
headerText="Follow Up?"
editorDataField="cbSelected"
editorXOffset="15"
editorYOffset="15">
<mx:itemEditor>
<mx:Component>
<mx:VBox backgroundColor="yellow">
<mx:Script>
<![CDATA[
// Define a property for returning
828 CHAPTER 23
<mx:CheckBox id="followUpCB"
label="Follow up needed"
height="100%" width="100%"
selected="{data.FollowUp}"
click="cbSelected=followUpCB.selected"/>
</mx:VBox>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
</mx:Application>
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\myComponents\EditorDGCheckBox.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="yellow">
<mx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
public var cbSelected:Boolean;
]]>
</mx:Script>
When this item editor opens, the CheckBox control can obtain focus for editing, but pressing the Enter key does
not move focus to the next cell because the parent VBox container does not implement the IFocusManagerCom-
ponent interface. You can modify this example to implement the IFocusManagerComponent interface, as the
following code shows:
<?xml version="1.0"?>
<!-- itemRenderers\dataGrid\myComponents\EditorDGCheckBoxFocusable.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="yellow"
implements="mx.managers.IFocusManagerComponent" >
<mx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
public var cbSelected:Boolean;
However, you can replace the default event listener for the component with your own event listener. To prevent
the default event listener from executing, you call the preventDefault() method from anywhere in your event
listener.
Use the following events when you create an item editor:
1 itemEditBeginning
Dispatched when the user releases the mouse button while over a cell, tabs to a cell, or in any way attempts to
edit a cell.
The list-based controls have a default listener for the itemEditBeginning event that sets the
editedItemPosition property of the list-based control to the cell that has focus.
You typically write your own event listener for this event to prevent editing of a specific cell or cells. To prevent
editing, call the preventDefault() method from within your event listener, which stops the default event
listener from executing, and prevents any editing from occurring on the cell. For more information, see
“Example: Preventing a cell from being edited” on page 836.
2 itemEditBegin
Dispatched before an item editor opens.
The list components have a default listener for the itemEditBegin event that calls the createItemEditor()
method to perform the following actions:
• Creates an item editor object, and copies the data property from the cell to the editor. By default, the item
editor object is an instance of the TextInput control. You use the itemEditor property of the list-based
control to specify a custom item editor class.
• Sets the itemEditorInstance property of the list-based control to reference the item editor object.
You can write an event listener for this event to modify the data passed to the item editor. For example, you
might modify the data, its format, or other information used by the item editor. For more information, see
“Example: Modifying data passed to or received from an item editor” on page 837.
You can also create an event listener to determine which item editor you use to edit the cell. For example, you
might have two different item editors. Within the event listener, you can examine the data to be edited, open
the appropriate item editor by setting the itemEditor property to the appropriate editor, and then call the
createItemEditor() method. In this case, first you call preventDefault() to stop Flex from calling the
createItemEditor() method as part of the default event listener.
You can call the createItemEditor() method only from within the event listener for the itemEditBegin
event. To create an editor at other times, set the editedItemPosition property to generate the
itemEditBegin event.
ADOBE FLEX 3 831
Adobe Flex 3 Developer Guide
3 itemEditEnd
Dispatched when the cell editing session ends, typically when focus is removed from the cell.
The list components have a default listener for this event that copies the data from the item editor to the data
provider of the list-based control. The default event listener performs the following actions:
• Uses the editorDataField property of the list-based control to determine the property of the item editor
that contains the new data. The default item editor is the TextInput control, so the default value of the
editorDataField property is "text" to specify that the text property of the TextInput control contains the
new cell data.
• Depending on the reason for ending the editing session, the default event listener calls the
destroyItemEditor() method to close the item editor. For more information, see “Determining the reason
for an itemEditEnd event” on page 833.
You typically write an event listener for this event to perform the following actions:
• Modify the data returned from the item editor.
In your event listener, you can modify the data returned by the editor to the list-based control. For
example, you can reformat the data before returning it to the list-based control. By default, an item editor
can return only a single value. You must write an event listener for the itemEditEnd event if you want to
return multiple values.
• Examine the data entered into the item editor:
In your event listener, you can examine the data entered into the item editor. If the data is incorrect, you
can call the preventDefault() method to stop Flex from passing the new data back to the list-based
control and from closing the editor.
DataGrid DataGridEvent
List ListEvent
Tree ListEvent
Notice that the event class for the List and Tree controls is ListEvent.
832 CHAPTER 23
When defining the event listener for a list-based control, ensure that you specify the correct type for the event
object passed to the event listener, as the following example shows for a DataGrid control:
public function myCellEndEvent(event:DataGridEvent):void {
// Define event listener.
}
<mx:Script>
<![CDATA[
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99 }
]);
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditEnd="getCellInfo(event);" >
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
In this example, you access the item editor, and cast it to the correct editor class. The default item editor is a
TextInput control, so you cast it to TextInput. If you had defined a custom item editor, you would cast it to that
class. After you have a reference to the item editor, you can access its properties to obtain the new cell value.
To access the old value of the cell, you use the editedItemRenderer property of the DataGrid control. You then
use the dataField property of the event object to access the data property for the edited column.
Each event class for a list-based control defines the reason property, which contains a value that indicates the
reason for the event. The reason property has the following values:
Value Description
CANCELLED Specifies that the user canceled editing and that they do not want to save the edited data. Even if you call the
preventDefault() method from within your event listener for the itemEditEnd event, Flex still calls the
destroyItemEditor() method to close the editor.
NEW_COLUMN (DataGrid only) Specifies that the user moved focus to a new column in the same row. In an event listener, you can let
the focus change occur, or prevent it.
For example, your event listener might check that the user entered a valid value for the cell currently being edited. If
not, you can prevent the user from moving to a new cell by calling the preventDefault() method. In this case, the
item editor remains open, and the user continues to edit the current cell. If you call the preventDefault() method
and also call the destroyItemEditor() method, you block the move to the new cell, but the item editor closes.
NEW_ROW Specifies that the user moved focus to a new row. You handle this value for the reason property similar to the way
you handle the NEW_COLUMN value.
OTHER Specifies that the list-based control lost focus, was scrolled, or is somehow in a state where editing is not allowed.
Even if you call the preventDefault() method from within your event listener for the itemEditEnd event, Flex
still calls the destroyItemEditor() method to close the editor.
The following example uses the itemEditEnd event to ensure that the user did not enter an empty String in a cell.
If there is an empty String, the itemEditEnd event calls preventDefault() method to prohibit the user from
removing focus from the cell until the user enters a valid value. However, if the reason property for the
itemEditEnd event has the value CANCELLED, the event listener does nothing:
<?xml version="1.0"?>
<!-- itemRenderers\events\EndEditEventFormatter.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.events.DataGridEventReason;
import mx.formatters.NumberFormatter;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99 }
]);
]]>
</mx:Script>
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditEnd="formatData(event);">
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
In this example, if the user’s reason for the event is CANCELLED, the event listener does nothing.
If the reason is NEW_COLUMN, NEW_ROW, or OTHER, the event listener performs the following actions:
1 Checks if the new cell value is an empty String.
2 If it is an empty String, the event listener calls the preventDefault() method to prevent Flex from closing
the editor and from updating the cell with the empty String.
3 Writes a message to the errorString property of the TextInput control. This message causes a red box to
appear around the TextInput control, and the message appears as a tooltip when the user moves the mouse over
the cell.
836 CHAPTER 23
<mx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99}
]);
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditBeginning="disableEditing(event);" >
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
ADOBE FLEX 3 837
Adobe Flex 3 Developer Guide
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
Although the preceding example uses the column index, you could inspect any property of the DataGrid, or of the
cell being edited, to make your decision about allowing the user to edit the cell.
<mx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.controls.NumericStepper;
import mx.collections.ArrayCollection;
import mx.controls.listClasses.IDropInListItemRenderer;
[Bindable]
private var myDP:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted', Price:11.99},
{Artist:'Pavement', Album:'Crooked Rain, Crooked Rain', Price:10.99},
{Artist:'Pavement', Album:'Wowee Zowee', Price:12.99},
{Artist:'Pavement', Album:'Brighten the Corners', Price:11.99},
{Artist:'Pavement', Album:'Terror Twilight', Price:11.99}
]);
if(colName=="Price")
{
// Handle the event here.
event.preventDefault();
import mx.controls.TextInput;
import mx.events.DataGridEvent;
import mx.events.DataGridEventReason;
import mx.formatters.NumberFormatter;
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{Artist:'Pavement', Album:'Slanted and Enchanted',
Price:11.99},
{Artist:'Pavement', Album:'Brighten the Corners',
Price:11.99 }
ADOBE FLEX 3 839
Adobe Flex 3 Developer Guide
]);
<mx:DataGrid id="myGrid"
dataProvider="{initDG}"
editable="true"
itemEditEnd="formatData(event);" >
<mx:columns>
<mx:DataGridColumn dataField="Artist"/>
<mx:DataGridColumn dataField="Album"/>
<mx:DataGridColumn dataField="Price"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
840 CHAPTER 23
<mx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.events.DataGridEventReason;
import mx.collections.ArrayCollection;
import myComponents.CityStateEditor;
[Bindable]
ADOBE FLEX 3 841
Adobe Flex 3 Developer Guide
<mx:DataGrid id="myGrid"
rowHeight="75"
dataProvider="{initDG}"
editable="true"
itemEditEnd="processData(event);">
<mx:columns>
<mx:DataGridColumn dataField="Company" editable="false"/>
<mx:DataGridColumn dataField="Contact"/>
<mx:DataGridColumn dataField="Phone"/>
<mx:DataGridColumn dataField="City and State" width="150"
itemEditor="myComponents.CityStateEditor">
<mx:itemRenderer>
<mx:Component>
<mx:Text selectable="false" width="100%"
text="{data.City}, {data.State}"/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
842 CHAPTER 23
</mx:Application>
Notice that the preceding example uses an inline item renderer to display the city and state in a single column of
the DataGrid control.
The event listener for the itemEditEnd event determines if the column being edited is the city and state column.
If so, the event listener performs the following actions:
1 Calls the preventDefault() method to prevent Flex from returning a String value.
2 Obtains the new city and state values from the item editor using the itemEditorInstance property of the
list-based control.
3 Calls the destroyItemEditor() method to close the item editor.
4 Calls the itemUpdated() method to cause the list-based control to update its display based on the new data
passed to it. If you do not call this method, the new data does not appear until the next time the list-based control
updates its appearance.
For examples of using the List and Tree controls, see “Using Item Renderers and Item Editors” on page 779.
The following example performs the same action, but uses an inline item editor, rather than a component:
<?xml version="1.0"?>
<!-- itemRenderers\events\InlineDGEditorReturnObject.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="700">
<mx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.collections.ArrayCollection;
import mx.controls.TextInput;
[Bindable]
public var initDG:ArrayCollection = new ArrayCollection([
{Company: 'Acme', Contact: 'Bob Jones',
Phone: '413-555-1212', City: 'Boston', State: 'MA'},
{Company: 'Allied', Contact: 'Jane Smith',
Phone: '617-555-3434', City: 'SanFrancisco', State: 'CA'}
]);
myGrid.editedItemRenderer.data.City=
myEditor(myGrid.itemEditorInstance).setCity.text;
myGrid.editedItemRenderer.data.State=
myEditor(myGrid.itemEditorInstance).pickState.selectedItem;
ADOBE FLEX 3 843
Adobe Flex 3 Developer Guide
myGrid.destroyItemEditor();
<mx:itemEditor>
<mx:Component className="myEditor">
<mx:VBox backgroundColor="yellow">
<mx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
[Bindable]
public var newContact:String;
]]>
</mx:Script>
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{label1: "Order #2314", Contact: "John Doe",
Confirmed: false, Photo: "john_doe.jpg", Sent: false},
{label1: "Order #2315", Contact: "Jane Doe",
Confirmed: true, Photo: "jane_doe.jpg", Sent: false}
]);
]]>
</mx:Script>
<mx:DataGrid id="myDG"
width="500" height="250"
dataProvider="{initDG}"
variableRowHeight="true"
editable="true">
<mx:columns>
<mx:DataGridColumn dataField="Photo"
ADOBE FLEX 3 845
Adobe Flex 3 Developer Guide
editable="false"/>
<mx:DataGridColumn dataField="Contact"
width="200"
editable="true"
rendererIsEditor="true"
itemRenderer="myComponents.MyContactEditable"
editorDataField="newContact"/>
<mx:DataGridColumn dataField="Confirmed"
editable="true"
rendererIsEditor="true"
itemRenderer="mx.controls.CheckBox"
editorDataField="selected"/>
<mx:DataGridColumn dataField="Sent"
editable="true"
rendererIsEditor="false"
itemEditor="mx.controls.CheckBox"
editorDataField="selected"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
In the previous example, you use the item renderer as the item editor by setting the rendererIsEditor property
to true in the second and third columns of the DataGrid control.
<mx:Script>
<![CDATA[
// Define a property for returning the new value to the cell.
[Bindable]
public var returnPN:String;
]]>
</mx:Script>
<mx:PhoneNumberValidator id="pnV"
source="{newPN}"
property="text"
trigger="{newPN}"
triggerEvent="change"
required="true"/>
<mx:TextInput id="newPN"
text="{data.phone}"
846 CHAPTER 23
updateComplete="returnPN=newPN.text;"
change="returnPN=newPN.text;"/>
</mx:VBox>
If the user enters an incorrect phone number, the PhoneNumberValidator draws a red box around the editor and
shows a validation error message when the user moves the mouse over it.
The following example shows the code for the application that uses this item editor:
<?xml version="1.0" ?>
<!-- itemRenderers\validator\MainDGValidatorEditor.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var initDG:ArrayCollection = new ArrayCollection([
{name: 'Bob Jones', phone: '413-555-1212',
email: '[email protected]'},
{name: 'Sally Smith', phone: '617-555-5833',
email: '[email protected]'},
]);
]]>
</mx:Script>
<mx:DataGrid id="dg"
width="500" height="200"
editable="true"
dataProvider="{initDG}">
<mx:columns>
<mx:DataGridColumn dataField="name"
headerText="Name" />
<mx:DataGridColumn dataField="phone"
headerText="Phone"
itemEditor="myComponents.EditorPhoneValidator"
editorDataField="returnPN"/>
<mx:DataGridColumn dataField="email" headerText="Email" />
</mx:columns>
</mx:DataGrid>
</mx:Application>
<mx:Script>
<![CDATA[
import mx.events.ListEvent;
import myComponents.EditorStateInfo;
<mx:List id="myList"
height="180" width="250"
848 CHAPTER 23
editable="true"
itemRenderer="myComponents.RendererState"
itemEditor="myComponents.EditorStateInfo"
variableRowHeight="true"
backgroundColor="white"
itemEditEnd="processData(event);">
<mx:dataProvider>
<mx:Object label="Alaska"
data="Juneau"
webPage="http://www.state.ak.us/"/>
<mx:Object label="Alabama"
data="Montgomery"
webPage="http://www.alabama.gov/" />
<mx:Object label="Arkansas"
data="Little Rock"
webPage="http://www.state.ar.us/"/>
</mx:dataProvider>
</mx:List>
</mx:Application>
This example uses the RendererState.mxml renderer. You can see that renderer in the section “Example: Using an
item renderer with a List control” on page 816.
<mx:Script>
<![CDATA[
import mx.collections.*;
import mx.controls.DateField;
import mx.collections.ArrayCollection;
[Bindable]
private var catalog:ArrayCollection = new ArrayCollection([
{confirmed: new Date(), Location: "Spain"},
{confirmed: new Date(2006,0,15), Location: "Italy"},
{confirmed: new Date(2004,9,24), Location: "Bora Bora"},
{confirmed: new Date(), Location: "Vietnam"}
]);
]]>
</mx:Script>
<mx:List id="myList"
width="300" height="300"
rowHeight="50"
dataProvider="{catalog}"
editable="true"
labelField="confirmed"
ADOBE FLEX 3 849
Adobe Flex 3 Developer Guide
itemEditor="mx.controls.DateField"
editorDataField="selectedDate"/>
</mx:Application>
In this example, you specify "confirmed" as the value of the labelField property to specify that the DateField
control modifies that field of the data provider.
if(event.rowIndex==0) {
event.preventDefault();
}
}
<mx:Tree id="myTree"
width="400" height="400"
editable="true"
itemEditor="myComponents.TreeEditor"
editorHeightOffset="75" editorWidthOffset="-100"
editorXOffset="40" editorYOffset="30"
creationComplete="initCatalog(contacts1);"
itemEditBeginning="disableEditing(event);"
itemEditEnd="processData(event);"/>
</mx:Application>
You specify the custom item editor using the itemEditor property of a tree control. You also use the
editorHeightOffset, editorWidthOffset , editorXOffset, and editorYOffset properties to position the
item editor.
The following item editor, defined in the file TreeEditor.mxml, lets you edit the data associated with each item in
a Tree control:
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- itemRenderers/tree/myComponents/TreeEditor.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
]]>
</mx:Script>
<!-- Display the text 'Phone:' and let the user edit it.-->
<mx:HBox>
<mx:Text text="Phone:"/>
<mx:TextInput id="contactPhone"
width="150"
text="{data.phone}"
change="newPhone=contactPhone.text;"/>
</mx:HBox>
Topics
About view states . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 853
Create and apply view states . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
Defining view state overrides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 867
Defining view states in custom components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880
Using view states with a custom item renderer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 881
Using view states with history management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884
Creating your own override classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 886
At its simplest, a view state defines a particular view of a component. For example, a product thumbnail could have
two view states; a base state with minimal information, and a “rich” state with links for more information or to
add the item to a shopping cart, as the following figure shows:
To create a view state, you define a base state, and then define a set of changes, or overrides, that modify the base
state to define the new view state. Each additional view state can modify the base state by adding or removing child
components, by setting style and property values, or by defining state-specific event handlers.
A view state does not have to modify the base state. A view state can specify modifications to any other view state.
This lets you create a set of view states that share common functionality while adding the overrides specific to each
view state. For more information, see “Basing a view state on another view state” on page 863.
A. LinkButton control
ADOBE FLEX 3 855
Adobe Flex 3 Developer Guide
If the user selects the Need to Register link, the form changes view state to display registration information, as the
following image shows:
A. Modified title of Panel container B. New form item C. Modified label of Button control D. New LinkButton control
Notice the following changes to the base view state to create this new view state:
• The title of the Panel container is set to Register
• The Form container has a new TextInput control for confirming the password
• The label of the Button control is set to Register
• The LinkButton control has been replaced with a new LinkButton control that lets the user change state back
to the base view state
When the user clicks the Return to Login link, the view state changes back to base view state to display the Login
form, reversing all of the changes made when changing to the register view state.
The following table shows the classes that you use to define view states:
Class Description
AddChild and RemoveChild Adds or removes a child component as part of a change of view state. For more information, see
“Adding and removing components by using overrides” on page 870.
SetEventHandler Adds an event handler as part of a change of view state. For more information, see “Setting over-
rides on event handlers” on page 877.
SetProperty Sets a component property as part of a change of view state. For more information, see “Setting
overrides on component properties” on page 868.
SetStyle Sets a style property on a component as part of a change of view state. For more information, see
“Setting overrides on component styles” on page 869.
856 CHAPTER 24
name="title" value="Register"/>
<mx:SetProperty target="{loginButton}"
name="label" value="Register"/>
<mx:Panel id="loginPanel"
title="Login"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Form id="loginForm">
<mx:FormItem label="Username:">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="Password:">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:ControlBar>
<!-- Use the LinkButton to change to the Register view state.-->
<mx:LinkButton id="registerLink"
label="Need to Register?"
click="currentState='Register'"/>
<mx:Spacer width="100%" id="spacer1"/>
<mx:Button label="Login" id="loginButton"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
858 CHAPTER 24
To change view state, click on the Panel container that you want to display in the expanded size. For a version of
this example that adds a transition to animate the view state change, see “Defining transitions” on page 892.
<?xml version="1.0"?>
<!-- states/ThreePanel.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="400">
<!-- Define the two view states, in addition to the base state.-->
<mx:states>
<mx:State name="One">
<mx:SetProperty target="{p1}" name="x" value="110"/>
<mx:SetProperty target="{p1}" name="y" value="0"/>
<mx:SetProperty target="{p1}" name="width" value="200"/>
<mx:SetProperty target="{p1}" name="height" value="210"/>
<mx:SetProperty target="{p2}" name="x" value="0"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="100"/>
<mx:SetProperty target="{p2}" name="height" value="100"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
<mx:State name="Two">
<mx:SetProperty target="{p2}" name="x" value="110"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="200"/>
<mx:SetProperty target="{p2}" name="height" value="210"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
</mx:states>
ADOBE FLEX 3 859
Adobe Flex 3 Developer Guide
<!-- Define the Canvas container holding the three Panel containers.-->
<mx:Canvas id="pm" width="100%" height="100%">
<mx:Panel id="p1" title="One"
x="0" y="0" width="100" height="100"
click="currentState='One'">
<mx:Label fontSize="24" text="One"/>
</mx:Panel>
<mx:State name="State1">
<mx:AddChild/>
.
<mx:SetStyle/>
.
<mx:SetProperty/>
.
<mx:SetEventHandler/>
.
</mx:State>
<mx:State name="State2">
.
.
</mx:State>
.
.
</mx:states>
<!-- Application definition that defines the base view state. -->
.
.
</mx:Application>
<mx:states>
<!-- Define the new view state. -->
<mx:State name="NewButton">
<mx:VBox id="v1">
<mx:Button id="b1" label="Click Me"/>
<mx:states>
<mx:State name="NewButton">
<mx:AddChild relativeTo="{v1}">
<mx:Button id="b3" label="New Button"/>
</mx:AddChild>
<mx:VBox id="v1">
<mx:Button id="b1" label="Click Me"/>
<mx:Button id="b2" label="Click Me" enabled="false"/>
To define the view state relative to another view state rather than to the base view state, use the State.basedOn
property. When Flex changes to the new view state, it restores the base state, applies any changes from the state
determined by the basedOn property, and then applies the changes defined in the new state.
In the following example, you define a NewButton view state that adds a Button control to the application, and a
NewButton2 view state based on the NewButton state that adds another Button control:
<?xml version="1.0"?>
<!-- states\StatesSimpleBasedOn.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:states>
<mx:State name="NewButton">
<mx:AddChild relativeTo="{v1}">
<mx:Button id="b2" label="New Button B2"/>
</mx:AddChild>
<mx:SetProperty target="{b1}"
name="enabled" value="false"/>
</mx:State>
<mx:VBox id="v1">
<mx:Button id="b1" label="Initial Button"/>
The component on which you modify the currentState property to cause the state change dispatches the
following events:
currentStateChanging Dispatched when the view state is about to change. It is dispatched by a component after
its currentState property changes, but before the view state changes. You can use this event to request any data
from the server required by the new view state.
currentStateChange Dispatched after the view state has completed changing. It is dispatched by a component
after its currentState property changes. You can use this event to send data back to a server indicating the user’s
current view state.
<mx:Script>
<![CDATA[
866 CHAPTER 24
import mx.states.*;
import mx.controls.Button;
// Initialization method to
// create a view state in ActionScript.
private function createState():void {
newState.overrides.push(newFormItem);
newState.overrides.push(changePropPanel);
newState.overrides.push(changePropButton);
newState.overrides.push(oldLinkButton);
newState.overrides.push(newLinkButton);
<mx:Panel id="loginPanel"
title="Login"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Form id="loginForm">
<mx:FormItem label="Username:">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="Password:">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:ControlBar>
<!-- Use the LinkButton to change to the Register view state.-->
<mx:LinkButton id="registerLink"
label="Need to Register?"
click="currentState='Register'"/>
<mx:Spacer width="100%" id="spacer1"/>
<mx:Button label="Login" id="loginButton"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
<mx:states>
<mx:State name="Register">
<mx:SetProperty
target="{loginPanel}"
name="title" value="Register"/>
<mx:SetProperty
target="{loginButton}"
name="label" value="Register"/>
</mx:State>
</mx:states>
<mx:Panel id="loginPanel"
title="Login"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Form id="loginForm">
<mx:Button label="Login" id="loginButton"/>
</mx:Form>
<mx:ControlBar width="100%">
<mx:Button label="Change State"
click="currentState =
currentState=='Register' ? '':'Register';"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
You can use data binding to specify information to the value property, as the following example shows:
<?xml version="1.0"?>
<!-- states\StatesSetProp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
// Define a variable in ActionScript.
[Bindable]
ADOBE FLEX 3 869
Adobe Flex 3 Developer Guide
<mx:states>
<mx:State name="Register">
<mx:SetProperty
target="{loginPanel}"
name="title" value="{registerValue}"/>
<mx:SetProperty
target="{loginButton}"
name="label" value="{registerValue}"/>
</mx:State>
</mx:states>
<mx:Panel id="loginPanel"
title="Login"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Form id="loginForm">
<mx:Button label="Login" id="loginButton"/>
</mx:Form>
<mx:ControlBar width="100%">
<mx:Button label="Change State"
click="currentState =
currentState=='Register' ? '':'Register';"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
When you switch to the Register state, the value property of the SetProperty class is determined by the current
value of the registerValue variable. However, this binding occurs only when you switch to the Register view state;
if you modify the value of the registerValue variable after switching to the Register view state, the title property
of the target component is not updated.
<mx:states>
<mx:State name="Register">
<mx:SetProperty
target="{loginPanel}"
name="title" value="Register"/>
<mx:SetStyle
target="{loginPanel}"
870 CHAPTER 24
name="backgroundColor" value="0x00FFFF"/>
<mx:SetProperty
target="{loginButton}"
name="label" value="Register"/>
<mx:SetStyle
target="{loginButton}"
name="color" value="0xFFFF00"/>
</mx:State>
</mx:states>
<mx:Panel id="loginPanel"
title="Login"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Form id="loginForm">
<mx:Button label="Login" id="loginButton"/>
</mx:Form>
<mx:ControlBar width="100%">
<mx:Button label="Change State"
click="currentState =
currentState=='Register' ? '':'Register';"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
<mx:states>
<mx:State name="NewButton">
<mx:AddChild relativeTo="{h1}" position="firstChild">
<mx:Button id="buttonNew" label="New Button"/>
</mx:AddChild>
</mx:State>
</mx:states>
<mx:HBox id="h1">
<mx:Button label="Change State"
click=
"currentState = currentState=='NewButton' ? '':'NewButton';"/>
</mx:HBox>
</mx:Application>
You can add multiple child components, or a container that contains multiple child components, as the following
example shows:
<?xml version="1.0"?>
<!-- states\StatesAddRelativeMultiple.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:states>
<mx:State name="NewVBox">
<mx:AddChild relativeTo="{v1}">
<mx:VBox id="v2">
<mx:Button id="buttonNew1" label="New Button"/>
<mx:Button id="buttonNew2" label="New Button"/>
<mx:Button id="buttonNew3" label="New Button"/>
</mx:VBox>
872 CHAPTER 24
</mx:AddChild>
</mx:State>
</mx:states>
<mx:VBox id="v1">
<mx:Button label="Change State"
click=
"currentState = currentState=='NewVBox' ? '':'NewVBox';"/>
</mx:VBox>
</mx:Application>
In the previous example, you use a single <mx:AddChild> tag to add the VBox container and its children. The
following example performs the same action, but uses multiple <mx:AddChild> tags:
<?xml version="1.0"?>
<!-- states\StatesAddRelativeMultipleAlt.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:states>
<mx:State name="NewVBox">
<mx:AddChild relativeTo="{v1}">
<mx:VBox id="v2"/>
</mx:AddChild>
<mx:AddChild relativeTo="{v2}">
<mx:Button id="buttonNew1" label="New Button"/>
</mx:AddChild>
<mx:AddChild relativeTo="{v2}">
<mx:Button id="buttonNew2" label="New Button"/>
</mx:AddChild>
<mx:AddChild relativeTo="{v2}">
<mx:Button id="buttonNew3" label="New Button"/>
</mx:AddChild>
</mx:State>
</mx:states>
<mx:VBox id="v1">
<mx:Button label="Change State"
click=
"currentState = currentState=='NewVBox' ? '':'NewVBox';"/>
</mx:VBox>
</mx:Application>
The specification of when the child is created is called its creation policy. For more general information on creation
policies and controlling how children are created, see “Improving Startup Performance” on page 91 in Building
and Deploying Adobe Flex 3 Applications.
The AddChild class has two mutually exclusive properties that you use to specify the child to add and the child’s
creation policy:
target Always creates the child when the applications starts. You cannot change the creation policy when using
this property. When you use this property, you can access the component before the first change to the view state
that defines it.
targetFactory Lets you control the creation policy of the child.
<mx:states>
<mx:State name="NewParent">
<mx:RemoveChild target="{button1}"/>
<mx:AddChild target="{button1}" relativeTo="{v2}"/>
</mx:State>
</mx:states>
</mx:VBox>
</mx:Application>
<mx:Script>
<![CDATA[
<mx:states>
<!-- Create the Button control at application startup. -->
<mx:State name="cpAll">
<mx:AddChild relativeTo="{myPanel}" creationPolicy="all">
<mx:Button id="newButton"/>
</mx:AddChild>
</mx:State>
<!-- Create the Button control when you want to create it. -->
<mx:State name="cpNone">
<mx:AddChild id="noCP"
relativeTo="{myPanel}" creationPolicy="none">
<mx:Button label="cpNone button"/>
</mx:AddChild>
</mx:State>
</mx:states>
<mx:Panel id="myPanel"
title="Static and dynamic states"
width="300" height="150">
<!-- Create the Button control for the noCP state that
uses creationPolicy=none.
If you do not click this button before changing to the
cpNone view state, the view state does nothing
because the Button control does not exist. -->
<mx:Button label="Explicitly create a button control"
click="noCP.createInstance();"/>
876 CHAPTER 24
</mx:Panel>
</mx:Application>
<mx:Script>
<![CDATA[
import mx.core.*;
import mx.states.*;
[Bindable]
public var defInst:DeferredInstanceFromFunction =
new DeferredInstanceFromFunction(createMyButton);
<mx:states>
<mx:State name="deferredButton">
<mx:AddChild relativeTo="{myPanel}" targetFactory="{defInst}"/>
</mx:State>
</mx:states>
<mx:Panel id="myPanel"
title="Static and dynamic states"
width="300" height="150">
<mx:Button id="myButton2"
label="Toggle Deferred Button"
click="currentState =
currentState == 'deferredButton' ? '' : 'deferredButton';"/>
</mx:Panel>
</mx:Application>
ADOBE FLEX 3 877
Adobe Flex 3 Developer Guide
• You can specify ActionScript code directly in the <mx:SetEventHandler> tag, without having to define a
separate function for the event handler. This technique is useful for very simple event handlers, such as when you
want to pop up an Alert dialog box.
• The event handler can take multiple arguments, of any type. If you use the handlerFunction property, the
handler function can take only an Event object as an argument.
You can use the handler event in MXML only.
You use the SetEventHandler.name property to specify the event name for the associated event handler. The
following example shows how to use the handler property to specify the event handler code directly in the
<mx:SetEventHandler> tag for the click event of a Button control:
<mx:SetEventHandler target="{myButton1}"
name="click" handler="Alert.show(’Hello World.’)"/>
The following example shows how you specify a handler function that takes two arguments; the Event object and
a user ID String variable:
<mx:SetEventHandler target="{myButton1}"
name="click" handler="myAlert(event, userID)"/>
The function myAlert must have the following declaration:
private function myAlert(eventObj:Event, idString:String):void
{
...
}
<mx:Script>
<![CDATA[
import flash.events.Event;
<mx:states>
<mx:State name="State1">
<mx:SetEventHandler target="{b1}"
name="click"
handlerFunction="handlerState1"/>
<mx:SetProperty target="{b1}"
name="label" value="Click Me: State 1"/>
</mx:State>
<mx:State name="State2">
<mx:SetEventHandler target="{b1}"
name="click"
handler="ta1.text='Specify an inline event listener';"/>
<mx:SetProperty target="{b1}"
name="label" value="Click Me: State 2"/>
</mx:State>
<mx:State name="State3">
<mx:SetEventHandler target="{b1}"
name="click"
handler="handlerState3('Event listener arg');"/>
<mx:SetProperty target="{b1}"
name="label" value="Click Me: State 3"/>
</mx:State>
</mx:states>
<mx:Button id="b1"
label="Click Me: Base State"
click="handlerBase();"/>
<mx:Script>
<![CDATA[
[Embed(source="closeButtonDownSkin.jpg")]
[Bindable]
public var closeBDown:Class;
[Embed(source="closeButtonOverSkin.jpg")]
[Bindable]
public var closeBOver:Class;
name="closeButtonUpSkin"
value="{closeBUp}"/>
<mx:SetStyle
name="closeButtonDownSkin"
value="{closeBDown}"/>
<mx:SetStyle
name="closeButtonOverSkin"
value="{closeBOver}"/>
</mx:State>
</mx:states>
</mx:TitleWindow>
This example replaces the default close icon for a TitleWindow when the component is in the collapsed state.
You can then use this component in an application, as the following example shows:
<?xml version="1.0"?>
<!-- states\StatesTitleWindowMain.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
<mx:ControlBar width="100%">
<mx:Label text="Quantity"/>
<mx:NumericStepper/>
<!-- Use Spacer to push Button control to the right. -->
<mx:Spacer width="100%"/>
<mx:Button label="Add to Cart"/>
</mx:ControlBar>
</MyComp:StateTitleWindow>
</mx:Application>
When the user rolls the mouse over the item, the view state changes: the thumbnail no longer has the availability
and rating information, but now has buttons that let the user get more information or add the item to the wish list
or cart. In the new state, the cell also has a border and a drop shadow, as the following image shows:
In this example, the application item renderer’s two view states have different child components and have different
component styles. The summary state, for example, includes an availability label and a star rating image, and has
no border. The rolled-over state replaces the label and rating components with three buttons, and has an outset
border.
For information on item renderers, see “Using Item Renderers and Item Editors” on page 779.
<mx:TileList id="myList"
dataProvider="{catArray}"
columnWidth="150"
rowHeight="150"
width="310"
height="310"
itemRenderer="myComponents.ImageComp"/>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
horizontalAlign="center"
verticalAlign="top"
mouseOver="currentState='showdesc'"
mouseOut="currentState=''">
<!-- In the base state, display the image and the label. -->
<mx:Image id="img1"
source="{data.image}"
width="75"
height="75"/>
<mx:Label text="{data.name}"/>
<mx:states>
<mx:State name="showdesc">
<!-- In the showdesc state, add the price, make the image bigger,
and put the description in the parent application's TextArea.-->
<mx:AddChild>
<mx:Text text="{data.price}"/>
884 CHAPTER 24
</mx:AddChild>
<mx:SetProperty target="{img1}" name="width" value="85"/>
<mx:SetProperty target="{img1}" name="height" value="85"/>
<mx:SetProperty target="{parentApplication.t1}" name="text"
value="{data.description}"/>
</mx:State>
</mx:states>
</mx:VBox>
<mx:Script>
<![CDATA[
import mx.managers.HistoryManager;
/////////////////////////
// IHistoryState methods
/////////////////////////
// Restore the state and searchString value.
public function loadState(state:Object):void {
if (state) {
currentState = state.currentState;
searchString = searchInput.text = state.searchString;
}
else {
currentState = '';
}
}
ADOBE FLEX 3 885
Adobe Flex 3 Developer Guide
/////////////////////////
// App-specific scripts
/////////////////////////
// The search string value.
[Bindable]
public var searchString:String;
<mx:states>
<!-- The state for displaying the search results -->
<mx:State name="results">
<mx:SetProperty target="{p}" name="width" value="100%" />
<mx:SetProperty target="{p}" name="height" value="100%" />
<mx:SetProperty target="{p}" name="title" value="Results" />
<mx:AddChild relativeTo="{searchFields}">
<mx:Button label="Reset" click="reset()" />
</mx:AddChild>
<mx:AddChild relativeTo="{p}">
<mx:Label text="Search results for {searchString}" />
</mx:AddChild>
</mx:State>
</mx:states>
Method Description
The following example shows an AddBlur override class that applies the Flash BlurFilter class to blur the target
component.
package myOverrides
{
import flash.display.*;
import flash.filters.*;
import mx.core.*;
import mx.states.*;
filters.push(new BlurFilter());
obj.filters = filters;
}
filters.pop();
obj.filters = filters;
}
}
}
You can then use your custom override class in an application, as the following example shows:
<?xml version="1.0"?>
<!-- states\AddBlurApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:myOverride="myOverrides.*">
<mx:states>
<mx:State name="State1">
<myOverride:AddBlur target="{b1}"/>
</mx:State>
</mx:states>
<mx:Button id="b1"
label="Click Me: Base State"/>
<mx:Button
label="Set State 1"
click="currentState='State1';"/>
<mx:Button
label="Set Base State"
click="currentState='';"/>
</mx:Application>
888 CHAPTER 24
889
Topics
About transitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 889
Defining transitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892
Handling events when using transitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898
Using action effects in a transition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899
Filtering effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 902
Transition tips and troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913
About transitions
View states let you vary the content and appearance of an application, typically in response to a user action. To use
view states, you define the base view state of an application, and one or more additional view states.
When you change view states, Adobe® Flex® performs all the visual changes to the application at the same time.
That means when you resize, move, or in some other way alter the appearance of the application, the application
appears to jump from one view state to the next.
Instead, you might want to define a smooth visual change from one view state to the next, in which the change
occurs over a period of time. A transition is one or more effects grouped together to play when a view state change
occurs.
For example, your application defines a form that in its base view state shows only a few fields, but in an expanded
view state shows additional fields. Rather than jumping from the base version of the form to the expanded version,
you define a Flex transition that uses the Resize effect to expand the form, and then uses the Fade effect to slowly
make the new form elements appear on the screen.
When a user changes back to the base version of the form, your transition uses a Fade effect to make the fields of
the expanded form disappear, and then uses the Resize effect to slowly shrink the form back to its original size.
890 CHAPTER 25
By using a transition, you can apply one or more effects to the form, to the fields added to the form, and to fields
removed from the form. You can apply the same effects to each form field, or apply different effects. You can also
define one set of effects to play when you change state to the expanded form, and a different set of effects to play
when changing from the expanded state back to the base state.
<mx:Script>
<![CDATA[
// Import easing classes if you use them only in MXML.
import mx.effects.easing.Bounce;
]]>
</mx:Script>
<!-- Define the transition to animate the change of view state. -->
<mx:transitions>
<mx:Transition>
<mx:Parallel
targets="{[loginPanel, registerLink, loginButton, confirm]}">
<mx:Resize duration="500" easingFunction="Bounce.easeOut"/>
<mx:Sequence target="{confirm}">
<mx:Blur duration="200" blurYFrom="1.0" blurYTo="20.0"/>
<mx:Blur duration="200" blurYFrom="20.0" blurYTo="1"/>
</mx:Sequence>
</mx:Parallel>
</mx:Transition>
</mx:transitions>
<mx:states>
<mx:State name="Register">
<mx:AddChild relativeTo="{loginForm}"
position="lastChild">
<mx:FormItem id="confirm" label="Confirm:">
<mx:TextInput/>
</mx:FormItem>
</mx:AddChild>
<mx:SetProperty target="{loginPanel}"
name="title" value="Register"/>
<mx:SetProperty target="{loginButton}"
name="label" value="Register"/>
<mx:RemoveChild target="{registerLink}"/>
<mx:AddChild relativeTo="{spacer1}" position="before">
<mx:LinkButton label="Return to Login"
click="currentState=''"/>
ADOBE FLEX 3 891
Adobe Flex 3 Developer Guide
</mx:AddChild>
</mx:State>
</mx:states>
<mx:Panel
title="Login" id="loginPanel"
horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:Form id="loginForm">
<mx:FormItem label="Username:">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="Password:">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:ControlBar>
<mx:LinkButton id="registerLink"
label="Need to Register?"
click="currentState='Register'"/>
<mx:Spacer width="100%" id="spacer1"/>
<mx:Button label="Login" id="loginButton"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
Defining transitions
You use the Transition class to create a transition. The following table defines the properties of the Transition class:
Property Definition
fromState A String that specifies the view state that you are changing from when you apply the transition. The default value is an
asterisk, "*", which means any view state.
toState A String that specifies the view state that you are changing to when you apply the transition. The default value is an
asterisk, "*", which means any view state.
effect The Effect object to play when you apply the transition. Typically, this is a composite effect, such as the Parallel or
Sequence effect, that contains multiple effects.
You can define multiple Transition objects in an application. The UIComponent class includes a transitions
property that you set to an Array of Transition objects. For example, you define an application with three Panel
containers and three view states, as the following example shows:
You define the transitions for this example in MXML using the <mx:transitions> tag, as the following example
shows:
<?xml version="1.0" ?>
<!-- transitions/DefiningTrans.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="400" >
<!-- Define the two view states, in addition to the base state.-->
<mx:states>
<mx:State name="One">
<mx:SetProperty target="{p1}" name="x" value="110"/>
<mx:SetProperty target="{p1}" name="y" value="0"/>
<mx:SetProperty target="{p1}" name="width" value="200"/>
<mx:SetProperty target="{p1}" name="height" value="210"/>
<mx:SetProperty target="{p2}" name="x" value="0"/>
ADOBE FLEX 3 893
Adobe Flex 3 Developer Guide
<!-- Define the Canvas container holding the three Panel containers.-->
<mx:Canvas id="pm" width="100%" height="100%" >
<mx:Panel id="p1" title="One"
x="0" y="0" width="100" height="100"
click="currentState='One'" >
<mx:Label fontSize="24" text="One"/>
</mx:Panel>
In this example:
1 You use the click event of each Panel container to change the view state.
2 When the application changes view state, Flex searches for a Transition object that matches the current and
destination view state. In this example, you set the fromState and toState properties to "*". Therefore, Flex
applies myTransition to all state changes. For more information on setting the fromState and toState
properties, see “Defining multiple transitions” on page 894.
3 After Flex determines the transition that matches the change of view state, Flex applies the Move and Resize
effects defined by the transition to the effect targets. In this example, you use the specification of the top-level
Parallel effect in the transition to specify the targets as the three Panel containers. For more information on setting
the effect targets, see “Defining effect targets” on page 895.
The Move and Resize effects play in parallel on all effect targets, so the three Panel containers move to a new
position and change size simultaneously. You can also define the top-level effect as a Sequence effect to make the
Move and Resize effects occur sequentially, rather than in parallel.
Flex determines the start and end property values of the Move and Resize effect by using information from any
properties that you specified to the effect, the current view state, and the destination view state. In this example,
you omit any property specifications in the effect definitions, so Flex uses the current size and position of each
Panel container to determine the values of the Move.xFrom, Move.yFrom, Resize.widthFrom, and
Resize.heightFrom properties. Flex uses the destination view state to determine the values of the Move.xTo,
Move.yTo, Resize.widthTo, and Resize.heightTo properties. For more information, see “Defining the effect
start and end values” on page 896.
<!-- Play for a change to the login view state from the details view state. -->
ADOBE FLEX 3 895
Adobe Flex 3 Developer Guide
<!-- Play for a change from any view state to any other view state. -->
<mx:Transition id="toAnyFromAny" fromState="*" toState="*">
...
</mx:Transition>
</mx:transitions>
<!-- Go to the login view state, transition toLoginFromDetails plays because you
transitioned from the details to the login view state. -->
<mx:Button click="currentState="login";/>
</mx:Parallel>
In this example, the Resize effect plays on all three panels, while the Move effect plays only on the first two panels.
You could also write this example as the following code shows:
<mx:Parallel id="t1" targets="{[p1,p2]}">
<mx:Move duration="400"/>
<mx:Resize targets="{[p1,p2,p3]}" duration="400"/>
</mx:Parallel>
4 If there are no explicit values, and Flex cannot determine values from the current or destination view states,
the effect uses its default property values.
The following example modifies the three-panel example shown in “Defining transitions” on page 892 by adding
Blur effects to the transition, where the Blur effect explicitly defines the values of the blurXFrom, blurXTo,
blurYFrom, and blurYTo properties:
<?xml version="1.0" ?>
<!-- transitions\DefiningTransWithBlurs.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="400" >
<!-- Define the two view states, in addition to the base state.-->
<mx:states>
<mx:State name="One">
<mx:SetProperty target="{p1}" name="x" value="110"/>
<mx:SetProperty target="{p1}" name="y" value="0"/>
<mx:SetProperty target="{p1}" name="width" value="200"/>
<mx:SetProperty target="{p1}" name="height" value="210"/>
<mx:SetProperty target="{p2}" name="x" value="0"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="100"/>
<mx:SetProperty target="{p2}" name="height" value="100"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
<mx:State name="Two">
<mx:SetProperty target="{p2}" name="x" value="110"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="200"/>
<mx:SetProperty target="{p2}" name="height" value="210"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
</mx:states>
<!-- Define the single transition for all view state changes.-->
<mx:transitions>
<mx:Transition fromState="*" toState="*">
<mx:Sequence id="t1" targets="{[p1,p2,p3]}">
<mx:Blur duration="100" blurXFrom="0.0" blurXTo="10.0"
blurYFrom="0.0" blurYTo="10.0"/>
<mx:Parallel>
<mx:Move duration="400"/>
<mx:Resize duration="400"/>
</mx:Parallel>
<mx:Blur duration="100" blurXFrom="10.0" blurXTo="0.0"
blurYFrom="10.0" blurYTo="0.0"/>
</mx:Sequence>
</mx:Transition>
</mx:transitions>
<!-- Define the Canvas container holding the three Panel containers.-->
898 CHAPTER 25
To move from the base view state to the OneOnly view state, you create the following view state definition:
<mx:states>
<mx:State name="OneOnly">
<mx:SetProperty target="{p2}" name="visible" value="false"/>
<mx:SetProperty target="{p2}" name="includeInLayout" value="false"/>
</mx:State>
</mx:states>
You set the value of the visible and includeInLayout properties to false so that Flex makes the second Panel
container invisible and ignores it when laying out the application. If the visible property is false, and the
includeInLayout property is true, the container is invisible, but Flex lays out the application as if the
component were visible.
A view state defines how to change states, and the transition defines the order in which the visual changes occur.
In the example shown in the previous image, you play an Iris effect on the second panel when it disappears, and
when it reappears on a transition back to the base state.
For the change from the base state to the OneOnly state, you define the toOneOnly transition which uses the Iris
effect to make the second panel disappear, and then sets the panel’s visible and includeInLayout properties
to false. For a transition back to the base state, you define the toAnyFromAny transition that makes the second
panel visible by setting its visible and includeInLayout properties to true, and then uses the Iris effect to
make the panel appear, as the following example shows:
900 CHAPTER 25
<mx:transitions>
<mx:Transition id="toOneOnly" fromState="*" toState="OneOnly">
<mx:Sequence id="t1" targets="{[p2]}">
<mx:Iris showTarget="false" duration="350"/>
<mx:SetPropertyAction name="visible"/>
<mx:SetPropertyAction target="{p2}" name="includeInLayout"/>
</mx:Sequence>
</mx:Transition>
When you create a view state, you use the SetProperty, SetStyle, AddChild, and RemoveChild classes to define the
view state. To control when a change defined by the view state property occurs in a transition, you use the corre-
sponding action effect. The action effects give you control over the order of the state change.
In the previous example, you used the following statement to define an action effect to occur when the value of
the visible property of a component changes:
<mx:SetPropertyAction name="visible"/>
ADOBE FLEX 3 901
Adobe Flex 3 Developer Guide
This action effect plays when the value of the visible property changes to either true or false. You can further
control the effect using the value property of the <mx:SetPropertyAction> tag, as the following example
shows:
<mx:SetPropertyAction name="visible" value="true"/>
In this example, you specify to play the effect only when the value of the visible property changes to true.
Adding this type of information to the action effect can be useful if you want to use filters with your transitions.
For more information, see “Filtering effects” on page 902.
The action effects do not support a duration property; they only perform the specified action.
Filtering effects
By default, Flex applies all of the effects defined in a transition to all of the target components of the transition.
Therefore, in the following example, Flex applies the Move and Resize effects to all three targets:
<mx:Transition fromState="*" toState="*">
<!-- Define a Parallel effect as the top most effect.-->
<mx:Parallel id="t1" targets="{[p1,p2,p3]}">
<!-- Define a Move and Resize effect.-->
<mx:Move duration="400"/>
<mx:Resize duration="400"/>
</mx:Parallel>
</mx:Transition>
However, you might want to conditionalize an effect so that it does not apply to all target components, but only
to a subset of the components. For example, you define an application with three view states, as the following
image shows:
Each change of view state removes the top panel, moves the bottom panel to the top, and adds the next panel to
the bottom of the screen. In this example, the third panel is invisible in the base view state.
For this example, you define a single transition that applies a WipeUp effect to the top panel as it is removed,
applies a Move effect to the bottom panel as it moves to the top position, and applies another WipeUp effect to the
panel being added to the bottom, as the following example shows:
<mx:transitions>
<mx:Transition fromState="*" toState="*">
<mx:Sequence targets="{[p1,p2,p3]}">
<mx:Sequence id="sequence1" filter="hide">
<mx:WipeUp/>
<mx:SetPropertyAction name="visible" value="false"/>
</mx:Sequence>
<mx:Move filter="move"/>
<mx:Sequence id="sequence2" filter="show">
<mx:SetPropertyAction name="visible" value="true"/>
<mx:WipeUp/>
</mx:Sequence>
</mx:Sequence>
</mx:Transition>
</mx:transitions>
The sequence1 Sequence effect uses the filter property to specify the change that a component must go through
in order for the effect to play on it. In this example, the sequence1 effect specifies a value of "hide" for the filter
property. Therefore, the WipeUp and SetPropertyAction effects only play on those components that change from
visible to invisible by setting their visible property to false.
In the sequence2 Sequence effect, you set the filter property to show. Therefore, the WipeUp and SetProperty-
Action effects only play on those components whose state changes from invisible to visible by setting their
visible property to true.
The Move effect also specifies a filter property with a value of move. Therefore, it applies to all target compo-
nents that are changing position.
The following table describes the possible values of the filter property:
Value Description
add Specifies to play the effect on all children added during the change of view state.
hide Specifies to play the effect on all children whose visible property changes from true to false during the change of view
state.
move Specifies to play the effect on all children whose x or y properties change during the change of view state.
904 CHAPTER 25
Value Description
remove Specifies to play the effect on all children removed during the change of view state.
resize Specifies to play the effect on all children whose width or height properties change during the change of view state.
show Specifies to play the effect on all children whose visible property changes from false to true during the change of view
state.
</mx:transitions>
Property Description
filterProperties An Array of Strings specifying component properties. If any of the properties in the Array have changed on the
target component, play the effect on the target.
filterStyles An Array of Strings specifying style properties. If any of the style properties in the Array have changed on the
target component, play the effect on the target.
filterFunction A property containing a reference to a callback function that defines custom filter logic. Flex calls this method
on every target of the effect. If the function returns true, the effect plays on the target; if it returns false, the
target is skipped by that effect.
requiredSemantics A collection of properties and associated values which must be associated with a target for the effect to be
played.
The callback function specified by the filterFunction property has the following signature:
filterFunc(propChanges:Array, instanceTarget:Object):Boolean {
// Return true to play the effect on instanceTarget,
// or false to not play the effect.
}
906 CHAPTER 25
<mx:states>
<mx:State name="One">
<mx:SetProperty target="{p1}" name="x" value="110"/>
<mx:SetProperty target="{p1}" name="y" value="0"/>
<mx:SetProperty target="{p1}" name="width" value="500"/>
<mx:SetProperty target="{p1}" name="height" value="210"/>
<mx:SetProperty target="{p2}" name="x" value="0"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="100"/>
<mx:SetProperty target="{p2}" name="height" value="100"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
<mx:State name="Two">
<mx:SetProperty target="{p2}" name="x" value="110"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="500"/>
<mx:SetProperty target="{p2}" name="height" value="210"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
</mx:states>
<mx:transitions>
<mx:Transition fromState="*" toState="*">
<mx:Sequence id="t1" targets="{[p1,p2,p3]}">
<mx:Blur id="myBlur" duration="100" blurXFrom="0.0"
blurXTo="10.0" blurYFrom="0.0" blurYTo="10.0">
<!-- Define the custom filter. -->
<mx:customFilter>
<mx:EffectTargetFilter
filterProperties="['width','x']"/>
</mx:customFilter>
</mx:Blur>
<mx:Parallel>
<mx:Move duration="400"/>
ADOBE FLEX 3 907
Adobe Flex 3 Developer Guide
<mx:Resize duration="400"/>
</mx:Parallel>
<mx:Blur id="myUnBlur" duration="100" blurXFrom="10.0"
blurXTo="0.0" blurYFrom="10.0" blurYTo="0.0">
<!-- Define the custom filter. -->
<mx:customFilter>
<mx:EffectTargetFilter
filterProperties="['width','x']"/>
</mx:customFilter>
</mx:Blur>
</mx:Sequence>
</mx:Transition>
</mx:transitions>
<mx:Script>
<![CDATA[
import mx.effects.EffectTargetFilter;
// Define the EffectTargetFilter object.
private var myBlurFilter:EffectTargetFilter;
myBlurFilter.filterProperties=['x', 'width'];
myBlur.customFilter=myBlurFilter;
myUnBlur.customFilter=myBlurFilter;
}
]]>
</mx:Script>
<mx:transitions>
<mx:Transition fromState="*" toState="*">
<mx:Sequence id="t1" targets="{[p1,p2,p3]}">
<mx:Blur id="myBlur"/>
<mx:Parallel>
<mx:Moveduration="400"/>
<mx:Resize duration="400"/>
</mx:Parallel>
<mx:Blur id="myUnBlur"/>
</mx:Sequence>
</mx:Transition>
</mx:transitions>
...
</mx:Application>
import mx.effects.EffectTargetFilter;
import flash.events.Event;
myBlurFilter.filterFunction=filterFunc;
myBlur.customFilter=myBlurFilter;
ADOBE FLEX 3 909
Adobe Flex 3 Developer Guide
myUnBlur.customFilter=myBlurFilter;
}
]]>
</mx:Script>
<mx:transitions>
<mx:Transition fromState="*" toState="*">
<mx:Sequence id="t1" targets="{[p1,p2,p3]}">
<mx:Blur id="myBlur"/>
<mx:Parallel>
<mx:Moveduration="400"/>
<mx:Resize duration="400"/>
</mx:Parallel>
<mx:Blur id="myUnBlur"/>
</mx:Sequence>
</mx:Transition>
</mx:transitions>
...
</mx:Application>
The propChanges argument passed to the filter function contains an Array of PropertyChanges objects, one
object per target component of the effect. The following table describes the properties of the PropertyChanges
class:
Property Description
target A target component of the effect. The end and start properties of the PropertyChanges class define how the target
component is modified by the change to the view state.
start An Object that contains the starting properties of the target component, as defined by the current view state. For
example, for a target component that is both moved and resized by a change to the view state, the start property
contains the starting position and size of the component, as the following example shows:
end An Object that contains the ending properties of the target component, as defined by the destination view state. For
example, for a target component that is both moved and resized by a change to the view state, the end property
contains the ending position and size of the component, as the following example shows:
Within the custom filter function, you first search the propChanges Array for the PropertyChanges object that
matches the instanceTarget argument by comparing the instanceTarget argument to the
propChanges.target property.
The following filter function examines the propChanges Array to determine if it should play the effect on the
instanceTarget. In this example, the filter function returns true only for those components being moved to a
position where the x property equals 110, as the following example shows:
910 CHAPTER 25
<mx:Script>
<![CDATA[
import mx.effects.EffectTargetFilter;
import flash.events.Event;
return false;
}
myBlur.customFilter=myBlurFilter;
myUnBlur.customFilter=myBlurFilter;
}
]]>
</mx:Script>
<mx:states>
<mx:State name="One">
<mx:SetProperty target="{p1}" name="x" value="110"/>
<mx:SetProperty target="{p1}" name="y" value="0"/>
<mx:SetProperty target="{p1}" name="width" value="500"/>
<mx:SetProperty target="{p1}" name="height" value="210"/>
<mx:SetProperty target="{p2}" name="x" value="0"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="100"/>
<mx:SetProperty target="{p2}" name="height" value="100"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
<mx:State name="Two">
<mx:SetProperty target="{p2}" name="x" value="110"/>
<mx:SetProperty target="{p2}" name="y" value="0"/>
<mx:SetProperty target="{p2}" name="width" value="500"/>
<mx:SetProperty target="{p2}" name="height" value="210"/>
<mx:SetProperty target="{p3}" name="x" value="0"/>
<mx:SetProperty target="{p3}" name="y" value="110"/>
<mx:SetProperty target="{p3}" name="width" value="100"/>
<mx:SetProperty target="{p3}" name="height" value="100"/>
</mx:State>
</mx:states>
<mx:transitions>
<mx:Transition fromState="*" toState="*">
<mx:Sequence id="t1" targets="{[p1,p2,p3]}">
<mx:Blur id="myBlur" duration="100" blurXFrom="0.0"
blurXTo="10.0" blurYFrom="0.0" blurYTo="10.0"/>
<mx:Parallel>
<mx:Move duration="400"/>
912 CHAPTER 25
<mx:Resize duration="400"/>
</mx:Parallel>
<mx:Blur id="myUnBlur" duration="100" blurXFrom="10.0"
blurXTo="0.0" blurYFrom="10.0" blurYTo="0.0"/>
</mx:Sequence>
</mx:Transition>
</mx:transitions>
For more information on data effects, see “Using data effects” on page 581.
Troubleshooting
Troubleshooting a transition effect that does not play:
• Is the effect target being hidden or removed? If so, make sure you add an <mx:RemoveChild> property to the
view state definition, or an <mx:SetPropertyAction name="visible"> tag in the transition definition.
• Does the change to the view state define settings that pertain to the transition effect? For example, if you have
a Resize effect, you must change the width or height property of the target when the view state changes to trigger
the effect.
• Check that you specified the correct targets to the transition.
• Check that your filter settings on the effect and on any parent effect are not excluding the target.
Troubleshooting an effect playing on too many targets:
914 CHAPTER 25
• Add a filter for a dynamic transition, or change the targets for an explicit transition.
Troubleshooting wrong effect parameters:
• Did you specify explicit parameters on the effect? Are they correct?
• Ensure that you correctly set the showTarget property for mask effects such as the Iris effect, and the wipe
effects.
Troubleshooting a flickering or flashing target:
• Ensure that you correctly set the showTarget property for mask effects such as the Iris effect, and the wipe
effects.
• Is the effect target being hidden or removed? If so, make sure you add an <mx:RemoveChild> property to the
view state definition to remove the target, or an <mx:SetPropertyAction name="visible"> tag in the
transition definition to hide the target.
Troubleshooting when an application does not look correct after a transition:
• Some effects leave the target with changed properties. For example, a Fade effect leaves the alpha property of
the target at the alphaTo value specified to the effect. If you use the Fade effect on a target that sets alpha property
to zero, you must set the alpha property to a nonzero value before the object appears again.
• Try removing one effect at a time from the transition until it no longer leaves your application with the
incorrect appearance.
915
Topics
About ToolTips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915
Creating ToolTips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 916
Using the ToolTip Manager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 922
Creating custom ToolTips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 926
Using error tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 932
Reskinning ToolTips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935
About ToolTips
ToolTips are a standard feature of many desktop applications. They make the application easier to use by
displaying messages when the user moves the mouse pointer over an onscreen element, such as a Button control.
The following image shows ToolTip text that appears when the user hovers the mouse pointer over a button:
When the user moves the mouse pointer away from the component or clicks the mouse button, the ToolTip disap-
pears. If the mouse pointer remains over the component, the ToolTip eventually disappears. The default behavior
is to display only one ToolTip at a time.
You can set the time it takes for the ToolTip to appear when a user moves the mouse pointer over the component.
You can also set the amount of time it takes for the ToolTip to disappear.
If you define a ToolTip on a container, the ToolTipManager displays the parent’s ToolTip for the children if the
child does not have one.
916 CHAPTER 26
Flex ToolTips support style sheets and the dynamic loading of ToolTip text. ToolTip text does not support
embedded HTML. For more information on using style sheets and dynamic loading of text, see “Setting styles in
ToolTips” on page 918 and “Using dynamic ToolTip text” on page 925.
Some Flex components have their own ToolTip-like “data tips.” These components include the List control, most
chart controls, and DataGrid control. For more information, see that component’s documentation.
ToolTips are the basis for the accessibility implementation within Flex. All controls that support accessibility do
so by making their ToolTip text readable by screen readers such as JAWS. For more information on accessibility,
see “Creating Accessible Applications” on page 1143.
Creating ToolTips
Every visual Flex component that extends the UIComponent class (which implements the IToolTipManager-
Client interface) supports a toolTip property. This property is inherited from the UIComponent class. You set
the value of the toolTip property to a text string, and when the mouse pointer hovers over that component, the
text string appears. The following example sets the toolTip property text for a Button control:
<?xml version="1.0"?>
<!-- tooltips/BasicToolTip.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
</mx:Application>
To set the value of a ToolTip in ActionScript, use the toolTip property of the component. The following example
creates a new Button and sets the toolTip property of a Button control:
<?xml version="1.0"?>
<!-- tooltips/BasicToolTipActionScript.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
public function createNewButton(event:MouseEvent):void {
var myButton:Button = new Button();
myButton.label = "Create Another Button";
myButton.toolTip = "Click this new button to create another button.";
myButton.addEventListener(MouseEvent.CLICK, createNewButton);
addChild(myButton);
}
]]></mx:Script>
<mx:Button id="b1" label="Create Another Button" click="createNewButton(event);"/>
</mx:Application>
ADOBE FLEX 3 917
Adobe Flex 3 Developer Guide
If you do not define a ToolTip on the child of a container, the ToolTipManager displays the parent’s ToolTip. For
example, if you add a Button control to a Panel container that has a ToolTip, the user sees the Panel container’s
ToolTip text when the user moves the mouse pointer over the Panel. When the user moves the mouse pointer over
the Button control, the Panel’s ToolTip continues to be displayed. You can override the container’s ToolTip text by
setting the value of the child’s toolTip property.
The following example shows the inheritance of ToolTip text:
<?xml version="1.0"?>
<!-- tooltips/ToolTipInheritance.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:VBox toolTip="VBOX">
<mx:Button id="b1" label="Button 1" toolTip="BUTTON"/>
<mx:Button id="b2" label="Button 2"/>
</mx:VBox>
</mx:Application>
When the mouse pointer is over button b1, the ToolTip displays BUTTON. When the mouse pointer is over
button b2 or anywhere in the VBox container except over button b1, the ToolTip displays VBOX.
The TabNavigator container uses the ToolTips that are on its children. If you add a ToolTip to a child view of a
TabNavigator container, the ToolTip appears when the mouse is over the tab for that view, but not when the mouse
is over the view itself. If you add a ToolTip to the TabNavigator container, the ToolTip appears when the mouse is
over either the tab or the view, unless the ToolTip is overridden by the tab or the view. ToolTips in the following
controls also behave this way:
• Accordion
• ButtonBar
• LinkBar
• TabBar
• ToggleButtonBar
There is no limit to the size of the ToolTip text, although long messages can be difficult to read. When the ToolTip
text reaches the width of the ToolTip box, the text wraps to the next line. You can add line breaks in ToolTip text.
In ActionScript, you use the \n escaped newline character. In MXML tags, you use the XML entity.
The following examples show using the \n escaped newline character and the entity:
<?xml version="1.0"?>
<!-- tooltips/ToolTipNewlines.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="doSomething(event)">
<mx:Script><![CDATA[
public function doSomething(event:Event):void {
// Use the \n to force a line break in ActionScript.
b1.toolTip = "Click this button \n to clear the form.";
}
918 CHAPTER 26
]]></mx:Script>
<mx:Button id="b1" label="Clear" width="100"/>
<!-- Use to force a line break in MXML tags. -->
<mx:Button id="b2" label="Submit" width="100" toolTip="Click this button to submit
the form."/>
</mx:Application>
You also have some flexibility in formatting the text of the ToolTip. You can apply styles and change other settings
for all ToolTips in your application by using the ToolTip Cascading Style Sheets (CSS) type selector. The following
sections describe how to set styles on the ToolTip text and box.
<mx:Style>
ToolTip {
fontFamily: "Arial";
fontSize: 19;
fontStyle: "italic";
color: #FF6699;
backgroundColor: #33CC99;
}
</mx:Style>
</mx:Application>
To use the StyleManager class to set ToolTip styles, apply a style to the ToolTip type selector with the setStyle()
method, as the following example shows:
<?xml version="1.0"?>
<!-- tooltips/ToolTipStyleManager.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="setToolTipStyle()">
<mx:Script><![CDATA[
import mx.styles.StyleManager;
private function setToolTipStyle():void {
StyleManager.getStyleDeclaration("ToolTip").setStyle("fontStyle","italic");
StyleManager.getStyleDeclaration("ToolTip").setStyle("fontSize","19");
StyleManager.getStyleDeclaration("ToolTip").setStyle("fontFamily","Arial");
StyleManager.getStyleDeclaration("ToolTip").setStyle("color","#FF6699");
StyleManager.getStyleDeclaration("ToolTip").setStyle("backgroundColor","#33CC99");
ADOBE FLEX 3 919
Adobe Flex 3 Developer Guide
}
]]></mx:Script>
</mx:Application>
ToolTips use inheritable styles that you set globally. For example, you can set the fontWeight of ToolTips with
the StyleManager by setting it on the global selector, as the following example shows:
<?xml version="1.0"?>
<!-- tooltips/ToolTipGlobalStyles.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="setToolTipStyle()">
<mx:Script><![CDATA[
import mx.styles.StyleManager;
private function setToolTipStyle():void {
StyleManager.getStyleDeclaration("global").setStyle("fontWeight","bold");
}
]]></mx:Script>
</mx:Application>
Styles set on the Application object typically apply to all UI objects. However, ToolTips do not inherit styles set on
the Application object.
If you set the fontWeight property on the global selector, your change affects the text of many controls in addition
to ToolTips, so be careful when using the global selector.
For a complete list of styles supported by ToolTips, see the Adobe Flex Language Reference. For more information
on using styles, see “Using Styles and Themes” on page 589.
You can reskin ToolTip controls to give them an entirely new appearance. You can do this by using the ToolTip-
Border programmatic skin or reskin them graphically. For an example of programmatically reskinning a ToolTip
control, see “Reskinning ToolTips” on page 935.
import mx.controls.ToolTip;
[Embed(source="../assets/sound1.mp3")]
private var beepSound:Class;
private var myClip:Sound;
}
private function init():void {
myLabel.addEventListener(ToolTipEvent.TOOL_TIP_SHOW, myListener);
myClip = new beepSound();
}
]]></mx:Script>
<mx:Label id="myLabel" toolTip="ToolTip" text="Mouse Over Me"/>
</mx:Application>
<!-- Define the ViewStack and the three child containers. -->
<mx:ViewStack id="vs1" borderStyle="solid" width="100%" height="150">
<mx:Canvas id="search" label="Search" toolTip="Search Screen">
<mx:Label text="Search Screen"/>
</mx:Canvas>
<mx:Canvas id="custInfo" label="Customer"
toolTip="Customer Info Screen">
<mx:Label text="Customer Info"/>
</mx:Canvas>
<mx:Canvas id="accountInfo" label="Account"
toolTip="Account Info Screen">
<mx:Label text="Account Info"/>
</mx:Canvas>
</mx:ViewStack>
</mx:VBox>
</mx:Application>
You can also set the value of the NavBar’s toolTipField property to point to the field in the data provider that
provides a ToolTip. The data provider in the following example defines ToolTips in the myToolTip field:
<?xml version="1.0"?>
922 CHAPTER 26
<mx:Script><![CDATA[
import mx.managers.ToolTipManager;
</mx:Application>
ADOBE FLEX 3 923
Adobe Flex 3 Developer Guide
Property Description
showDelay The length of time, in milliseconds, that Flex waits before displaying the ToolTip box when a user moves the mouse
pointer over a component that has a ToolTip.
hideDelay The length of time, in milliseconds, that Flex waits to hide the ToolTip box after it appears. This amount of time only
applies if the mouse pointer is over the target component. Otherwise the ToolTip disappears immediately when you
move the mouse pointer away from the target component. After Flex hides a ToolTip box, the user must move the mouse
pointer off the component and back onto it to see the ToolTip box again.
If you set the hideDelay property to 0, Flex does not display the ToolTip. Adobe recommends that you use the default
value of 10,000 milliseconds, or 10 seconds.
If you set the hideDelay property to Infinity, Flex does not hide the ToolTip until the user triggers an event (such as
moving the mouse pointer off the component). The following example sets the hideDelay property to Infinity :
ToolTipManager.hideDelay = Infinity;
scrubDelay The length of time, in milliseconds, that a user can take when moving the mouse between controls before Flex again
waits for the duration of showDelay to display a ToolTip box.
This setting is useful if the user moves quickly from one control to another; after displaying the first ToolTip, Flex displays
the others immediately rather than waiting for the duration of the showDelay setting. The shorter the setting for
scrubDelay, the more likely that the user must wait for an amount of time specified by the showDelay property in
order to see the next ToolTip.
A good use of this property is if you have several buttons on a toolbar, and the user will quickly scan across them to see
brief descriptions of their functionality.
The following example uses the Application control’s initialize event to set the starting values for the ToolT-
ipManager:
<?xml version="1.0"?>
924 CHAPTER 26
</mx:Application>
<mx:Script><![CDATA[
import mx.managers.ToolTipManager;
public function app_init():void {
ToolTipManager.showEffect = fadeIn;
}
]]></mx:Script>
</mx:Application>
In this example, if the user enters [email protected] in the TextInput box, and then moves the mouse pointer over
the button, Flex displays the message “Send e-mail to [email protected]” in the ToolTip box.
Another approach to creating dynamic text for ToolTips is to intercept the ToolTip in its toolTipShow event
handler and change the value of its text property. The following example registers the myToolTipChanger()
method as a listener for the Button control’s toolTipShow event. The code in that method changes the value of
the ToolTipManager.currentToolTip.text property to a value that is not known until run time.
<?xml version="1.0"?>
<!-- tooltips/DynamicToolTipText.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="initApp()">
<mx:Script><![CDATA[
import mx.managers.ToolTipManager;
import mx.controls.ToolTip;
import mx.events.ToolTipEvent;
public function initApp():void {
b1.addEventListener(ToolTipEvent.TOOL_TIP_SHOW, myToolTipChanger)
}
For information about using the Application.application.parameters object, see “Passing request data with
flashVars properties” on page 1043.
Flex displays the ToolTip until you destroy it. In general, you should not display more than one ToolTip box at a
time, because it is confusing to the user.
You can use the destroyToolTip() method to destroy the specified ToolTip object. The destroyToolTip()
method has the following signature:
destroyToolTip(toolTip:IToolTip):void
The toolTip parameter is the ToolTip object that you want to destroy. This is the object returned by the
createToolTip() method.
The following example creates a custom ToolTip when you move the mouse over a Panel container that contains
three Button controls. Each Button control has its own ToolTip that appears when you mouse over that particular
control. The big ToolTip disappears only when you move the mouse away from the Panel container.
<?xml version="1.0"?>
<!-- tooltips/CreatingToolTips.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.managers.ToolTipManager;
import mx.controls.ToolTip;
<mx:Style>
Panel {
paddingLeft: 5;
paddingRight: 5;
paddingTop: 5;
paddingBottom: 5;
}
</mx:Style>
You can also create a custom ToolTip by extending an existing control, such as a Panel or VBox container, and
implementing the IToolTip interface. The following example uses a Panel container as the base for a new imple-
mentation of the IToolTip interface:
<?xml version="1.0"?>
<!-- tooltips/ToolTipComponents/PanelToolTip.mxml -->
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml"
implements="mx.core.IToolTip"
width="200"
alpha=".8"
borderThickness="2"
backgroundColor="0xCCCCCC"
dropShadowEnabled="true"
borderColor="black"
borderStyle="solid"
title="feh"
>
<mx:Script><![CDATA[
[Bindable]
public var bodyText:String = "";
</mx:Panel>
In your application, you can create a custom ToolTip by intercepting the toolTipCreate event handler of the
target component. In the event handler, you instantiate the new ToolTip and set its properties. You then point the
toolTip property of the ToolTipEvent object to the new ToolTip.
In the following example, the first two buttons in the application use the custom PanelToolTip in the Custom-
ToolTips package. The third button uses a default ToolTip to show you how the two are different. To run this
example, store the PanelToolTip.mxml file in a subdirectory named CustomToolTips.
<?xml version="1.0"?>
<!-- tooltips/MainCustomApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import ToolTipComponents.PanelToolTip;
import mx.events.ToolTipEvent;
ptt.bodyText = body;
event.toolTip = ptt;
}
]]></mx:Script>
<mx:Button id="b1"
label="Delete"
toolTip=" "
toolTipCreate="createCustomTip('DELETE','Click this button to delete the report.',
event)"
/>
<mx:Button id="b2"
label="Generate"
toolTip=" "
toolTipCreate="createCustomTip('GENERATE','Click this button to generate the
report.', event)"
/>
<mx:Button id="b3"
label="Stop"
toolTip="Click this button to stop the creation of the report. This button uses a
standard ToolTip style."
/>
</mx:Application>
You also set the value of the ToolTip’s y position to be the same as the target component’s y position to line the
ToolTip and the component up horizontally.
930 CHAPTER 26
One way to get the values you need to calculate the x position of the ToolTip is to use an event handler. Event
objects passed to an event handler can give you the x position and the width of the target component.
The following example gets the value of the current target’s x, y, and width properties in the focusIn event handler,
and uses them to position the ToolTip. In this case, the current target is the TextInput control, and the ToolTip
appears to its right with a 10-pixel offset.
<?xml version="1.0"?>
<!-- tooltips/PlacingToolTips.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalAlign="middle"
horizontalAlign="center" height="100" width="300">
<mx:Script>
<![CDATA[
import mx.controls.ToolTip;
import mx.managers.ToolTipManager;
<mx:TextInput id="b"
width="100"
focusIn="showTip(event)"
focusOut="destroyTip(event)"
/>
</mx:Application>
ADOBE FLEX 3 931
Adobe Flex 3 Developer Guide
The previous example creates a ToolTip on a target component that is not inside any containers. However, in many
cases, your components will be inside layout containers such as a VBox or an HBox. Under these circumstances,
the coordinates you access in the event handler will be relative to the container and not the main application. But
the ToolTipManager expects global coordinates when positioning the ToolTip. This will position ToolTips in
unexpected locations.
To avoid this, you can use the contentToGlobal() method to convert the coordinates in the event handler from
local to global. All components that subclass UIComponent have this method. It takes a single Point that is relative
to the target’s enclosing container as an argument and returns a Point that is relative to the Stage.
The following example calls the TextInput control’s contentToGlobal() method to convert the control’s coordi-
nates from those that are relative to the VBox container to global coordinates.
<?xml version="1.0"?>
<!-- tooltips/PlacingToolTipsInContainers.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalAlign="middle"
horizontalAlign="center" height="250" width="400">
<mx:Script>
<![CDATA[
import mx.controls.ToolTip;
import mx.managers.ToolTipManager;
tip = ToolTipManager.createToolTip(s,
pt.x + event.currentTarget.width + 10,
pt.y
) as ToolTip;
}
</mx:Script>
<mx:VBox >
<!-- A ToolTip inside a container. -->
<!-- The event handler for this ToolTip accounts for the control
being inside a container and positions the ToolTip using the
contentToGlobal() method. -->
<mx:TextInput id="b"
text="Good ToolTip placement"
width="175"
focusIn="showTipB(event)"
focusOut="destroyTip(event)"
/>
<mx:TextInput id="c"
text="Bad ToolTip placement"
width="175"
focusIn="showTipA(event)"
focusOut="destroyTip(event)"
/>
</mx:VBox>
</mx:Application>
.errorTip {
color: #FFFFFF;
fontSize: 9;
fontWeight: "bold";
shadowColor: #000000;
borderColor: #CE2929;
borderStyle: "errorTipRight";
paddingBottom: 4;
paddingLeft: 4;
paddingRight: 4;
paddingTop: 4;
}
You can customize the appearance of error tips by creating a new theme that overrides these styles, or by
overriding the style properties in your application. For more information on creating themes, see “About themes”
on page 645.
You can create ToolTips that look like validation error tips by applying the errorTip style to the ToolTip. The
following example does not contain any validation logic, but shows you how to use the errorTip style to create
ToolTips that look like validation error tips. When you run the example, press the Enter key after entering text
into the TextInput controls.
<?xml version="1.0"?>
<!-- tooltips/ErrorTipStyle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="20">
<mx:Script><![CDATA[
import mx.controls.ToolTip;
import mx.managers.ToolTipManager;
errorTip = ToolTipManager.createToolTip(
myError, event.currentTarget.x + event.currentTarget.width,
event.currentTarget.y) as ToolTip;
934 CHAPTER 26
</mx:Application>
Another way to use error tips is to set the value of the errorString property of the component. This causes the
ToolTipManager to create an instance of a ToolTip and apply the errorTip style to that ToolTip without requiring
any coding on your part.
The following example shows how to set the value of the errorString property to create an error tip:
<?xml version="1.0"?>
<!-- tooltips/ErrorString.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="20">
<mx:Script><![CDATA[
import mx.controls.ToolTip;
import mx.managers.ToolTipManager;
event.currentTarget.errorString = myError;
}
]]></mx:Script>
<?xml version="1.0"?>
<!-- tooltips/CreatingErrorTips.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.managers.ToolTipManager;
import mx.controls.ToolTip;
public var myTip:ToolTip;
]]></mx:Script>
<mx:Style>
Panel {
paddingLeft: 5;
paddingRight: 5;
paddingTop: 5;
paddingBottom: 5;
}
</mx:Style>
Reskinning ToolTips
You can apply a programmatic skin to ToolTip controls.
ToolTip skins are defined by the ToolTipBorder programmatic skin. This file is located in the mx.skins.halo
package.
936 CHAPTER 26
To reskin ToolTips, you edit the ToolTipBorder class file, and then apply the new skin to the ToolTip by using CSS.
For more information on skinning, see “Creating Skins” on page 689.
Topics
About the Cursor Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
Creating and removing a cursor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
Using a busy cursor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 942
You create a new cursor, and set an optional priority for the cursor, by using the static setCursor() method of
the CursorManager class. This method adds the new cursor to the cursor list. If the new cursor has the highest
priority, it is displayed immediately. If the priority is lower than a cursor already in the list, it is not displayed until
the cursor with the higher priority is removed.
To remove a cursor from the list, you use the static removeCursor() method. If the cursor is the currently
displayed cursor, the Cursor Manager displays the next cursor in the list, if one exists. If the list ever becomes
empty, the Cursor Manager displays the default system cursor.
The setCursor() method has the following signature:
public static setCursor(cursorClass:Class, priority:int = 2, xOffset:Number = 0,
yOffset:Number = 0, setter:IUIComponent = null):int
The following table describes the arguments for the setCursor() method:
priority The priority level of the cursor. Valid values are CursorManagerPriority.HIGH, Optional
CursorManagerPriority.MEDIUM, and CursorManagerPriority.LOW. The default value is 2, corre-
sponding to CursorManagerPriority.MEDIUM.
xOffset The x offset of the cursor relative to the mouse pointer. The default value is 0. Optional
yOffset The y offset of the cursor relative to the mouse pointer. The default value is 0. Optional
setter The IUIComponent that set the cursor. Necessary (in multi-window environments) to know which window Optional
needs to display the cursor.
This method returns the ID of the new cursor. You pass the ID to the removeCursor() method to delete the
cursor. This method has the following signature:
static removeCursor(cursorID:int):void
Note: In AIR, each mx.core.Window instance uses its own instance of the CursorManager class. In an AIR appli-
cation, instead of directly referencing the static methods and properties of the CursorManager class, use the
Window.cursorManager property to reference the CursorManager instance for the Window instance.
The following example changes the cursor to a custom wait or busy cursor while a large image file loads. After the
load completes, the application removes the busy cursor and returns the cursor to the system cursor.
Note: The Flex framework includes a default busy cursor. For information on using this cursor, see “Using a busy
cursor” on page 942.
<?xml version="1.0"?>
<!-- cursors\CursorManagerApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
ADOBE FLEX 3 941
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
import mx.managers.CursorManager;
import flash.events.*;
<mx:VBox>
<!-- Image control to load the image. -->
<mx:Image id="image1"
height="50"
width="100"
scaleContent="true"
complete="loadComplete(event);"/>
Method Description
removeBusyCursor() Removes the busy cursor from the cursor list. If other busy cursor requests are still active in the cursor list,
which means that you called the setBusyCursor() method more than once, a busy cursor does not disap-
pear until you remove all busy cursors from the list.
You can modify the example in “Creating and removing a cursor” on page 939 to use the default busy cursor, as
the following example shows:
<?xml version="1.0"?>
<!-- cursors\DefBusyCursorApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.managers.CursorManager;
import flash.events.*;
<mx:VBox>
<!-- Image control to load the image. -->
ADOBE FLEX 3 943
Adobe Flex 3 Developer Guide
<mx:Image id="image1"
height="50"
width="100"
scaleContent="true"
complete="loadComplete(event);"/>
<mx:Script>
<![CDATA[
import mx.managers.CursorManager;
import mx.managers.CursorManagerPriority;
import flash.events.*;
}
]]>
</mx:Script>
<mx:VBox>
<!-- Image control to load the image. -->
<mx:Image id="image1"
height="50"
width="100"
scaleContent="true"
complete="loadComplete(event);"/>
<mx:VBox>
<!-- Image control to load the image. -->
<mx:Image id="image1"
height="50"
width="100"
scaleContent="true"
showBusyCursor="true"/>
</mx:VBox>
</mx:Application>
946 CHAPTER 27
947
Topics
About Repeater components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
Using the Repeater component. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948
Considerations when using a Repeater component. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 965
The TileList control is a list control that displays data in a tile layout, much like the Tile container. The TileList
control provides a direction property that determines if the next item is down or to the right. For more infor-
mation, see “TileList control” on page 385.
The List control displays data in a single vertical column. For more information, see “List control” on page 373.
Property Description
dataProvider An implementation of the ICollectionView interface, IList interface, or Array class, such as an ArrayCollection
object.
You must specify a dataProvider value or the Repeater component will not execute.
Generally, you specify the value of the dataProvider property as a binding expression because the value is not
known until run time.
startingIndex Number that specifies the element in the data provider at which the repetition starts. The data provider array is
zero-based, so to start at the second element of the array, specify a starting index of one. If the startingIndex
is not within the range of the dataProvider property, no repetition occurs.
count Number that specifies how many repetitions occur. If the dataProvider property has fewer items than the
number in the count property, the repetition stops with the last item.
ADOBE FLEX 3 949
Adobe Flex 3 Developer Guide
Property Description
currentIndex Number that specifies the element of the dataProvider item currently being processed. The data provider array
is zero-based, so when the third element is being processed, the current index is two. This property changes as the
Repeater component executes, and is -1 after the execution is complete. It is a read-only property that you cannot
set in the <mx:Repeater> tag.
currentItem Reference to the item that is being processed in the dataProvider property. This property changes as the
Repeater component executes, and is null after the execution is complete. It is a read-only property that you
cannot set in the <mx:Repeater> tag.
After a Repeater component finishes repeating, you do not use the currentItem property to get the current
item. Instead, you call the getRepeaterItem() method of the repeated component itself. For more information,
see “Event handlers in Repeater components” on page 957.
recycleChildren Boolean value that, when set to true, binds new data items into existing Repeater children, incrementally creates
new children if there are more data items, and destroys extra children that are no longer required. For more infor-
mation, see “Recreating children in a Repeater component” on page 965.
Event Description
repeat Dispatched each time an item is processed and currentIndex and currentItem are updated.
repeatStart Dispatched when Flex begins processing the dataProvider property and begins creating the specified subcom-
ponents.
In actuality, the counter is not the data within the array, but the position within the array. As long as the array
contains four elements, you can provide any data within the array itself, and the Repeater component still executes
four times. The following example illustrates this principle:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var myArray:Array=[10,20,30,40];
]]>
</mx:Script>
You can also use the startingIndex and count properties to adjust the starting point and total number of execu-
tions. The count property sets a maximum on the number of times the Repeater component executes. The count
property is often—but not always—an exact measure of the number of times that the content within the Repeater
component will execute. This number is because the Repeater component stops after the last element of the data
provider is reached, regardless of the value of the count property.
The following example shows how the count and startingIndex properties affect a Repeater component:
<?xml version="1.0"?>
<!-- repeater\StartingIndexCount.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
ADOBE FLEX 3 951
Adobe Flex 3 Developer Guide
<![CDATA[
[Bindable]
public var myArray:Array=[100,200,300,400,500,600];
]]>
</mx:Script>
<mx:HRule/>
<mx:HRule/>
The first Repeater component loops through each element of the data provider, starting with the first and stopping
after the last. The second Repeater component starts at the second element of the data provider and iterates four
times, ending at the fifth element. The third Repeater component starts with the fourth element and continues
until the end of the data provider array, and then stops. Only three iterations occur despite the fact that the count
property is set to 6.
You can still use the count property to restrict the number of iterations performed. You can use the
startingIndex property to skip entries at the beginning of the data provider.
954 CHAPTER 28
In the preceding example, the first product entry in the XML file contains metadata that other applications use to
create column headers. Because it doesn’t make sense to include that entry in the radio buttons, start the Repeater
component at the second element of the data provider, as in the following code example:
<?xml version="1.0"?>
<!-- repeater\StartSecondElement.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="catalogService.send();">
<mx:XMLListCollection id="myXC"
source="{catalogService.lastResult.product}"/>
<mx:Script>
<![CDATA[
<mx:Script>
<![CDATA[
<mx:Script>
<![CDATA[
<mx:Model id="data">
<color>
<colorName>Red</colorName>
<colorName>Yellow</colorName>
<colorName>Blue</colorName>
</color>
</mx:Model>
<mx:Model id="catalog" source="../assets/repeater/catalog.xml"/>
<mx:ArrayCollection id="myAC1" source="{catalog.product}"/>
<mx:ArrayCollection id="myAC2" source="{data.colorName}"/>
This application places the full list of products with color and price into the system log when you click the Button
control (provided you have defined the log file in the mm.cfg file) and yields the following on screen:
In the previous example, the instances of the Label control are multiply indexed because they are inside multiple
Repeater components. For example, the index nameLabel[1][2] contains a reference to the Label control
produced by the second iteration of r and the third iteration of r2.
Note: After a Repeater component finishes repeating, you do not use the Repeater.currentItem property to get the
current item. Instead, you call the getRepeaterItem() method of the repeated component itself.
The following example illustrates the getRepeaterItem() method. When the user clicks each repeated Button
control, the corresponding colorName value from the data model appears in the Button control label.
<?xml version="1.0"?>
<!-- repeater\GetItem.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function clicker(cName:String):void {
foolabel.text=cName;
}
]]>
</mx:Script>
<mx:Model id="data">
<color>
<colorName>Red</colorName>
<colorName>Yellow</colorName>
<colorName>Blue</colorName>
</color>
</mx:Model>
<mx:ArrayCollection id="myAC" source="{data.colorName}"/>
The code in the following example uses the getRepeaterItem() method to display a specific URL for each
Button control that the user clicks. The Button controls must share a common data-driven click handler, because
you cannot use binding expressions inside event handlers. However, the getRepeaterItem() method lets you
change the functionality for each Button control.
<?xml version="1.0"?>
<!-- repeater\DisplayURL.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var dp:Array = [ { label: "Flex",
url: "http://www.adobe.com/flex" },
{ label: "Flash", url: "http://www.adobe.com/flash" } ];
]]>
</mx:Script>
Property Description
instanceIndices Array that contains the indices required to reference the component from its document. This Array is empty unless
the component is in one or more Repeater components. The first element corresponds to the outermost Repeater
component. For example, if the id is b and instanceIndices is [2,4], you would reference it on the document
as b[2][4].
repeaters Array that contains references to the Repeater components that produced the component. The Array is empty
unless the component is in one or more Repeater components. The first element corresponds to the outermost
Repeater component.
repeaterIndices Array that contains the indices of the items in the dataProvider properties of the Repeater components that
produced the component. The Array is empty unless the component is within one or more Repeater components.
The first element corresponds to the outermost Repeater component. For example, if repeaterIndices is
[2,4], the outer Repeater component used its dataProvider[2] data item and the inner Repeater component
used its dataProvider[4] data item.
This property differs from instanceIndices if the startingIndex of any of the Repeater components is not
0. For example, even if a Repeater component starts at dataProvider item 4, the document reference of the first
repeated component is b[0], not b[4].
The following example application uses the repeaters property to display the id value of the Repeater compo-
nents in an Alert control when the user clicks one of the Button controls labelled by the index value of the outer
Repeater component and inner Repeater component, respectively. It uses the repeaters property to get the id
value of the inner Repeater component:
<?xml version="1.0"?>
<!-- repeater\RepeatersProp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
[Bindable]
public var myArray:Array=[1,2];
]]>
</mx:Script>
click="Alert.show(event.target.repeaters[1].id);"/>
</mx:Repeater>
</mx:Repeater>
</mx:Application>
The previous example produces the following results when the user clicks the third button:
The following example application uses the instanceIndices property to set the text property of a TextInput
control when the user clicks the corresponding Button control in the set of repeated Button and TextInput
controls. You need to use the instanceIndices property because you must get the correct object dynamically;
you cannot get it by its id value.
The following example shows how to use the instanceIndices property to set the text property of a TextInput
control when the user clicks a Button control. The argument event.target.instanceIndices gets the index of
the corresponding TextInput control.
<?xml version="1.0"?>
<!-- repeater\InstanceIndicesProp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var myArray:Array=[1,2,3,4,5,6,7,8];
]]>
</mx:Script>
This example yields the following results when the user clicks the second and fourth buttons:
The following code shows how to use the repeaterIndices property instead of the instanceIndices property
to set the text property of a TextInput control when the user clicks a Button control. The value of
event.target.repeaterIndices is based on the current index of the Repeater component. Because the
startingIndex property of the Repeater component is set to 2, it does not match the
event.target.instanceIndices value, which always starts at 0.
<?xml version="1.0"?>
<!-- repeater\RepeaterIndicesProp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var myArray:Array = [1,2,3,4,5,6,7,8];
]]>
</mx:Script>
Either version yields the following results when the user clicks the second and fourth buttons:
<mx:Script>
<![CDATA[
[Bindable]
public var dp:Array=[1,2,3,4];
]]>
</mx:Script>
<mx:Script>
<![CDATA[
964 CHAPTER 28
import mx.controls.Alert;
public function getLabelRep():void {
Alert.show(comp.repbutton[1].label);
}
]]>
</mx:Script>
<MyComp:CustButton id="comp"/>
The Repeater component re-executes whenever its dataProvider, startingIndex, or count properties are set
or modified either explicitly in ActionScript, or implicitly by data binding. If the dataProvider property is bound
to a web service result, the Repeater component re-executes when the web service operation returns the result. A
Repeater component also re-executes in response to paging through the dataProvider property by incremen-
tally increasing the startingIndex value, as the following example shows:
r.startingIndex += r.count;
When a Repeater component re-executes, it destroys any children that it previously created (assuming the
recycleChildren property is set to false), and then reinstantiates its children based on the current
dataProvider property. The number of children in the container might change, and the container layout changes
to accommodate any changes to the number of children.
• Forgetting curly braces ({ }) in a dataProvider property is a common mistake when using a Repeater
component. If the Repeater component doesn’t execute, make sure that the binding is correct.
• If repeated objects are displayed out of order and you are using adjacent or nested Repeater components, you
might need to place a dummy UIComponent immediately after the Repeater that is displaying objects incorrectly.
The code in the following example contains adjacent <mx:Repeater> tags and uses an <mx:Spacer> tag to
create a dummy UIComponent:
<mx:VBox>
<mx:Repeater id="r1">
...
</mx:Repeater>
<mx:Repeater id="r2">
...
</mx:Repeater>
<mx:Spacer height="0" id="dummy"/>
</mx:VBox>
The code in the following example contains nested <mx:Repeater> tags and uses an <mx:Spacer> tag to
create a dummy UIComponent:
<mx:VBox>
<mx:Repeater id="outer">
<mx:Repeater id="inner">
...
</mx:Repeater>
<mx:Spacer id="dummy" height="0">
</mx:Repeater>
</mx:VBox>
967
Topics
About embedding assets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 969
Syntax for embedding assets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 972
Embedding asset types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976
<mx:Script>
<![CDATA[
[Embed(source="logo.gif")]
[Bindable]
public var imgCls:Class;
]]>
</mx:Script>
<mx:Style>
.myCustomButton {
overSkin:Embed(source="overIconImage.gif");
upSkin:Embed(source="upIconImage.gif");
downSkin:Embed(source="downIconImage.gif");
}
</mx:Style>
Assets loaded at run time exist as separate, independent files on your web server (or elsewhere) and are not
compiled into your Flex applications. The referenced assets add no overhead to an application’s initial load time.
However, you might experience a delay when you use the asset and load it in Adobe® Flash® Player or Adobe®
AIR™. These assets are independent of your Flex application, so you can change them without causing a recompile
operation, as long as the names of the modified assets remain the same.
For examples that load an asset at run time, see “Image control” on page 278 and “SWFLoader control” on
page 274.
For security, by default Flash Player does not allow an application to access some types of remote data (such as
SWF files) at run time from a domain other than the domain from which the application was served. Therefore,
a server that hosts data must be in the same domain as the server hosting your application, or the server must
define a crossdomain.xml file. A crossdomain.xml file is an XML file that provides a way for a server to indicate
that its data and documents are available to SWF files served from specific domains, or from all domains. For
more information on application security, see “Applying Flex Security” on page 29 in Building and Deploying
Adobe Flex 3 Applications.
PNG image/png
image/svg-xml
Symbols stored in a
SWF file
Embed parameters
Each form of the embed syntax takes one or more optional parameters. The exact syntax that you use to embed
assets depends on where they are embedded. Some of these parameters are available regardless of what type of
asset you are embedding, and others are specific to a particular type of media. For example, you can use the
source and mimeType parameters with any type of media, but the scaleGridRight parameter applies only to
images.
ADOBE FLEX 3 973
Adobe Flex 3 Developer Guide
The following table describes the parameters that are available for any type of embedded asset. For more infor-
mation, see “About the source parameter” on page 973 and “About the MIME type” on page 974.
Parameter Description
source Specifies the name and path of the asset to embed; either an absolute path or a path relative to the file containing
the embed statement. The embedded asset must be a locally stored asset. Therefore you cannot specify a URL for
an asset to embed.
For more information on setting the path, see “About setting the path to the embedded asset” on page 974.
The following table describes the parameters that are specific for images and Sprite objects. For more information,
see “Using 9-slice scaling with embedded images” on page 981.
Parameter Description
scaleGridTop Specifies the distance in pixels of the upper dividing line from the top of the image in a 9-slice scaling formatting
system. The distance is relative to the original, unscaled size of the image.
scaleGridBottom Specifies the distance in pixels of the lower dividing line from the top of the image in a 9-slice scaling formatting
system. The distance is relative to the original, unscaled size of the image.
scaleGridLeft Specifies the distance in pixels of the left dividing line from the left side of the image in a 9-slice scaling formatting
system. The distance is relative to the original, unscaled size of the image.
scaleGridRight Specifies the distance in pixels of the right dividing line from the left side of the image in a 9-slice scaling format-
ting system. The distance is relative to the original, unscaled size of the image.
The following table describes the parameter that is specific to SWF files. For more information, see “Embedding
SWF files” on page 979.
Parameter Description
symbol Specifies the symbol in a SWF file to embed, for use with Adobe Flash Player 8 and earlier.
overSkin:Embed("overIconImage.gif");
upSkin:Embed(source="upIconImage.gif");
downSkin:Embed(source="downIconImage.gif");
}
</mx:Style>
• application/x-font-truetype
• application/x-shockwave-flash
• audio/mpeg
• image/gif
• image/jpeg
• image/png
• image/svg
• image/svg-xml
<mx:Script>
<![CDATA[
[Embed(source="logo.gif")]
[Bindable]
public var imgCls:Class;
]]>
</mx:Script>
<mx:Image source="{imgCls}"/>
</mx:Application>
Notice that Flex uses data binding to tie the imgCls variable to the source property. If you omit the [Bindable]
metadata tag preceding the imgCls variable definition, Flex can perform the data binding operation only once, at
application startup. When you include the [Bindable] metadata tag, Flex recognizes any changes to the imgCls
variable and updates any components that use that variable when a change to it occurs.
Generally, this method of embedding assets provides more flexibility than other methods because you can import
an asset once and then use it in multiple places in your application, and because you can update the asset and have
the data binding mechanism propagate that update throughout your application.
976 CHAPTER 29
</mx:Application>
You might want to manipulate an embedded image at run time. To manipulate it, you determine the data type of
the object representing the image and then use the appropriate ActionScript methods and properties of the object.
For example, you use the [Embed] metadata tag in ActionScript to embed a GIF image, as the following code
shows:
[Embed(source="logo.gif")]
[Bindable]
public var imgCls:Class;
In this example, you define a class named imgCls that represents the embedded image. When embedding JPEG,
GIF, and PNG files, Flex defines imgCls as a reference to a subclass of the mx.core.BitmapAsset class, which is a
subclass of the flash.display.Bitmap class.
In ActionScript, you can create and manipulate an object that represents the embedded image before passing it to
a control. To do so, you create an object with the type of the embedded class, manipulate it, and then pass the
object to the control, as the following example shows:
<?xml version="1.0"?>
<!-- embed/EmbedAccessClassObject.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.core.BitmapAsset;
[Embed(source="logo.gif")]
[Bindable]
public var imgCls:Class;
<mx:HBox>
<mx:Image id="myImageRaw" source="{imgCls}"/>
<mx:Image id="myImage" creationComplete="modImage();"/>
</mx:HBox>
</mx:Application>
978 CHAPTER 29
In this example, the first Image control displays the unaltered image and the second Image control displays the
modified image. You use the bitmapData property of the mx.core.BitmapAsset class to modify the object. The
bitmapData property is of type flash.display.BitmapData; therefore you can use all of the methods and properties
of the BitmapData class to manipulate the object.
Embedding sounds
Flex supports embedding MP3 sound files for later playback. The following example creates a simple media player
with Play and Stop buttons:
<?xml version="1.0"?>
<!-- embed/EmbedSound.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import flash.media.*;
[Embed(source="sample.mp3")]
[Bindable]
public var sndCls:Class;
<mx:HBox>
<mx:Button label="play" click="playSound();"/>
<mx:Button label="stop" click="stopSound();"/>
</mx:HBox>
</mx:Application>
In this example, you define a class named sndCls that represents the embedded MP3 file. When embedding MP3
files, Flex defines sndCls as a reference to a subclass of the mx.core.SoundAsset, which is a subclass of the
flash.media.Sound class.
Flex can handle any legal filename, including filenames that contain spaces and punctuation marks. If the MP3
filename includes regular quotation marks, be sure to use single quotation marks around the filename.
You do not have to embed the sound file to use it with Flex. You can also use the Sound class to load a sound file
at run time. For more information, see the Sound class in the Adobe Flex Language Reference.
In this example, you define a class named imgCls that represents the embedded SWF file. Flex defines imgCls as
a reference to a subclass of the mx.core.MovieClipLoaderAsset class, which is a subclass of the
flash.display.MovieClip class. Therefore you can manipulate the image by using the methods and properties of the
MovieClipLoaderAsset class.
In this example, you define a class named imgCls that represents the embedded symbol. Internally, Flex defines
imgCls as a reference to a subclass of either one of the following classes:
SpriteAsset For single-frame SWF files
MovieClipLoaderAsset For multiframe SWF files
The following example show an image, and the same image with the regions defined by the 9-slice scaling borders:
When you scale an embedded image that uses 9-slice scaling, all text and gradients are scaled normally. However,
for other types of objects the following rules apply:
• Content in the center region is scaled normally.
• Content in the corners is not scaled.
• Content in the top and bottom regions is scaled only horizontally. Content in the left and right regions is
scaled only vertically.
• All fills (including bitmaps, video, and gradients) are stretched to fit their shapes.
If you rotate the image, all subsequent scaling is normal, as if you did not define any 9-slice scaling.
To use 9-slice scaling, define the following four parameters in your embed statement: scaleGridTop,
scaleGridBottom, scaleGridLeft , and scaleGridRight. For more information on these parameters, see
“Embed parameters” on page 972.
An embedded SWF file may already contain 9-slice scaling information specified by using Adobe Flash Profes-
sional. In that case, the SWF file ignores any 9-slice scaling parameters that you specify in the embed statement.
The following example uses 9-slice scaling to maintain a set border, regardless of how the image itself is resized.
<?xml version="1.0"?>
<!-- embed\Embed9slice.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="1200" height="600">
<mx:Script>
<![CDATA[
[Embed(source="slice_9_grid.gif",
scaleGridTop="25", scaleGridBottom="125",
scaleGridLeft="25", scaleGridRight="125")]
[Bindable]
public var imgCls:Class;
]]>
</mx:Script>
<mx:HBox>
ADOBE FLEX 3 983
Adobe Flex 3 Developer Guide
<mx:Image source="{imgCls}"/>
<mx:Image source="{imgCls}" width="300" height="300"/>
<mx:Image source="{imgCls}" width="450" height="450"/>
</mx:HBox>
</mx:Application>
The original image is 30 by 30 pixels. The preceding code produces a resizable image that maintains a 5-pixel
border:
If you had omitted the 9-slice scaling, the scaled image would have appeared exactly like the unscaled image, as
the following image shows:
984 CHAPTER 29
In this example, you define a class named imgCls that represents the embedded image. If the image is a SWF file
that uses 9-slice scaling, Flex defines imgCls as a subclass of the mx.core.SpriteAsset class, which is a subclass of
the flash.display.Sprite class. Therefore you can use all of the methods and properties of the SpriteAsset class to
manipulate the object.
<mx:Script>
<![CDATA[
import mx.core.UIComponent;
import mx.core.BitmapAsset;
[Embed(source="logo.bmp",mimeType="application/octet-stream")]
private var FileClass : Class;
<mx:Button
id="showProperties"
label="Show Properties"
click="captureEmbeddedImage();"/>
<mx:TextArea id="myTA"
width="75%"
height="100"/>
</mx:Application>
985
Topics
Modular applications overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 985
Writing modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 989
Compiling modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 991
Loading and unloading modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993
Using ModuleLoader events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 999
Passing data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1006
Benefits of modules
A module is a special type of dynamically loadable SWF that contains an IFlexModuleFactory class factory. This
allows an application to load code at run time and create class instances without requiring that the class imple-
mentations be linked into the main application.
Modules are similar to Runtime Shared Libraries (RSLs) in that they separate code from an application into
separately loaded SWF files. Modules are much more flexible than RSLs because modules can be loaded and
unloaded at run time and compiled without the application.
Two common scenarios in which using modules is beneficial are a large application with different user paths and
a portal application.
An example of the first common scenario is an enormous insurance application that includes thousands of
screens, for life insurance, car insurance, health insurance, dental insurance, travel insurance, and veterinary pet
insurance.
By using a traditional approach to rich Internet application (RIA) design, you might build a monolithic appli-
cation with a hierarchical tree of MXML classes. Memory use and start-up time for the application would be
significant, and the SWF file size would grow with each new set of functionality.
When using this application, however, any user accesses only a subset of the screens. By refactoring the screens
into small groups of modules that are loaded on demand, you can improve the perceived performance of the main
application and reduce the memory use. Also, when the application is separated into modules, developers’
productivity may increase due to better encapsulation of design. When rebuilding the application, the developers
also have to recompile only the single module instead of the entire application.
An example of the second common scenario is a system with a main portal application, written in ActionScript
3.0, that provides services for numerous portlets. Portlets are configured based on data that is downloaded on a
per-user basis. By using the traditional approach, you might build an application that compiles in all known
portlets. This is inefficient, both for deployment and development.
By using modules, you can establish an interface that contains portal services, and a generic portlet interface. You
can use XML data to determine which modules to load for a given session. When the module is loaded, you obtain
a handle to a class factory inside the module, and from that you create an instance of a class that implements the
portlet interface. In this scenario, full recompilation is necessary only if the interfaces change.
By using shared interface definitions, these shared interfaces reduce hard dependencies between the shell and the
module. This provides type-safe communication and enforces an abstraction layer without adding significantly to
the SWF file size.
The following image shows the relationship between the shell and the module’s interfaces:
Application
ConcreteShell
Manager AbstractClient
Module
AbstractFactory AbstractProduct
ConcreteFactory ConcreteProduct
The ModuleManager manages the set of loaded modules, which are treated as a map of Singletons that are indexed
by the module URL. Loading a module triggers a series of events that let clients monitor the status of the module.
Modules are only ever loaded once, but subsequent reloads also dispatch events so that client code can be
simplified and rely on using the READY event to know that the module’s class factory is available for use.
The ModuleLoader class is a thin layer on top of the ModuleManager API that is intended to act similarly to the
mx.controls.SWFLoader class for modules that only define a single visual UIComponent. The ModuleLoader
class is the easiest class to use when implementing a module-based architecture, but the ModuleManager provides
greater control over the modules.
Module domains
By default, a module is loaded into a child domain of the current application domain. You can specify a different
application domain by using the applicationDomain property of the ModuleLoader class.
Because a module is loaded into a child domain, it owns class definitions that are not in the main application’s
domain. For example, the first module to load the PopUpManager class becomes the owner of the PopUpManager
class for the entire application because it registers the manager with the SingletonManager. If another module later
tries to use the PopUpManager, Adobe ® Flash® Player throws an exception.
988 CHAPTER 30
The solution is to ensure that managers such as PopUpManager and DragManager and any other shared services
are defined by the main application (or loaded late into the shell’s application domain). When you promote one
of those classes to the shell, the class can then be used by all modules. Typically, this is done by adding the
following to a script block:
import mx.managers.PopUpManager;
import mx.managers.DragManager;
private var popUpManager:PopUpManager;
private var dragManager:DragManager;
This technique also applies to components. The module that first uses the component owns that component’s class
definition in its domain. As a result, if another module tries to use a component that has already been used by
another module, its definition will not match the existing definition. To avoid a mismatch of component defini-
tions, create an instance of the component in the main application. The result is that the definition of the
component is owned by the main application and can be used by modules in any child domain.
Because a Flex module must be in the same security domain as the application (SWF) that loads it, when you’re
using modules in an AIR application any module SWF must be located in the same directory as the main appli-
cation SWF or one of its subdirectories, which ensures that like the main application SWF, the module SWF is in
the AIR application security sandbox. One way to verify this is to ensure that a relative URL for the module’s
location doesn’t require "../" ("up one level") notation to navigate outside the application directory or one of its
subdirectories.
For more information about application domains, see “Using the ApplicationDomain class” on page 550 in
Programming ActionScript 3.0.
Module applications
To create a modular application, you create separate classes for each module, and an application that loads the
modules. Adobe® Flex® Builder™ provides some mechanisms for making module use easier.
Writing modules
Modules are classes just like application files. You can create them either in ActionScript or by extending a Flex
class by using MXML tags. You can create modules in MXML and in ActionScript.
After you compile a module, you can load it into an application or another module. Typically, you use one of the
following techniques to load MXML-based modules:
• ModuleLoader — The ModuleLoader class provides the highest-level API for handling modules. For more
information, see “Using the ModuleLoader class to load modules” on page 993.
• ModuleManager — The ModuleManager class provides a lower-level API for handling modules than the
ModuleLoader class does. For more information, see “Using the ModuleManager class to load modules” on
page 995.
To call the computeAnswer() method on the ActionScript module, you can use one of the techniques shown in
“Accessing modules from the parent application” on page 1007.
Compiling modules
The way you compile modules is similar to the way you compile Flex applications. On the command line, you use
the mxmlc command-line compiler; for example:
mxmlc MyModule.mxml
The result of compiling a module is a SWF file that you load into your application. You cannot run the module-
based SWF file as a stand-alone application or load it into a browser window. It must be loaded by an application
as a module. Modules should not be requested by the Adobe® Flash® Player or Adobe® AIR,™ or through a browser
directly.
When you compile your module, you should try to remove redundancies between the module and the application
that uses it. To do this, you create a link report for the application, and then externalize any assets in the module
that appear in that report. Flex Builder can do this for you automatically. For more information, see “Reducing
module size” on page 991.
The default output location of the linker report is the same directory as the compiler. In this case, it would be
in the bin directory.
2 Compile the module and pass the linker report to the load-externs option:
mxmlc -load-externs=report.xml MyModule.mxml
Recompiling modules
If you change a module, you do not have to recompile the application that uses the module if that module is in the
same project. This is because the application loads the module at run time and does not check against it at compile
time. Similarly, if you make changes to the application, you do not have to recompile the module. Just as the appli-
cation does not check against the module at compile time, the module does not check against the application until
run time.
If the module is in a separate project than the application that loads it, you must recompile the module separately.
However, if you make changes that might affect the linker report or common code, you should recompile both the
application and the modules.
Note: If you externalize the module’s dependencies by using the load-externs or optimize option, your module
might not be compatible with future versions of Adobe Flex. You might be required to recompile the module. To ensure
that a future Flex application can use a module, compile that module with all the classes it requires. This also applies
to applications that you load inside other applications.
Debugging modules
To debug an application that uses modules, you set the debug compiler option to true for the modules when you
compile them. Otherwise, you will not be able to set breakpoints in the modules or gather other debugging infor-
mation from them. In Flex Builder, debugging is enabled by default. On the command line, debugging is disabled
by default. You must also set the debug option to true when you compile the application that loads the modules
that you want to debug.
A common issue that occurs when using multiple modules is that modules sometimes own the class definitions
that the other modules want to use. Because they are in sibling application domains, the module that loaded the
class definition first owns the definition for that class, but other modules will experience errors when they try to
use that class. The solution is to promote the class definition to the main application domain so that all modules
can use the class. For more information, see “Module domains” on page 987.
ADOBE FLEX 3 993
Adobe Flex 3 Developer Guide
>
<mx:TabNavigator id="tn"
width="100%"
height="100%"
creationPolicy="auto"
>
<mx:VBox id="vb1" label="Column Chart Module">
<mx:Label id="l1" text="ColumnChartModule.swf"/>
<mx:ModuleLoader url="ColumnChartModule.swf"/>
</mx:VBox>
</mx:TabNavigator>
</mx:Panel>
</mx:Application>
You can also use the ModuleLoader API to load and unload modules with the loadModule() and
unloadModule() methods. These methods take no parameters; the ModuleLoader loads or unloads the module
that matches the value of the current url property.
The following example loads and unloads the module when you click the button:
<?xml version="1.0"?>
<!-- modules/ASModuleLoaderApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.modules.*;
paddingBottom="10"
>
<mx:TabNavigator id="tn"
width="100%"
height="100%"
creationPolicy="auto"
>
<mx:VBox id="vb1" label="Column Chart Module">
<mx:Button
label="Load"
click="createModule(chartModuleLoader, l1.text)"
/>
<mx:Button
label="Unload"
click="removeModule(chartModuleLoader)"
/>
<mx:Label id="l1" text="ColumnChartModule.swf"/>
<mx:ModuleLoader id="chartModuleLoader"/>
</mx:VBox>
To use the ModuleManager to load a module in ActionScript, you first get a reference to the module’s IModuleInfo
interface by using the ModuleManager getModule() method. You then call the interface’s load() method.
Finally, you use the factory property of the interface to call the create() method and cast the return value as
the module’s class.
The IModuleInfo class’s load() method optionally takes an ApplicationDomain and a SecurityDomain as
arguments. If you do not specify either of these, then the module is loaded into a new child domain.
The following example shell application loads the ColumnChartModule.swf file and then adds it to the display list
so that it appears when the application starts:
<?xml version="1.0"?>
<!-- modules/ModuleLoaderApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
import mx.modules.IModuleInfo;
<mx:VBox id="vb1"/>
</mx:Application>
MXML-based modules can load other modules. Those modules can load other modules, and so on.
Be sure to define the module instance outside of a function, so that it is not in the function’s local scope.
Otherwise, the object might be garbage collected and the associated event listeners might never be invoked.
ADOBE FLEX 3 997
Adobe Flex 3 Developer Guide
Preloading modules
When you first start an application that uses modules, the application’s file size should be smaller than a similar
application that does not use modules. As a result, there should be a reduction in wait time because the application
can be loaded into memory and run in the Flash Player or AIR before the modules’ SWF files are even transferred
across the network. However, there will be a delay when the user navigates to a part in the application that uses
the module. This is because the modules are not by default preloaded, but rather loaded when they are first
requested.
When a module is loaded by the Flex application for the first time, the module’s SWF file is transferred across the
network and stored in the browser’s cache. If the Flex application unloads that module, but then later reloads it,
there should be less wait time because Flash Player loads the module from the cache rather than across the
network.
Module SWF files, like all SWF files, reside in the browser’s cache unless and until a user clears them. As a result,
modules can be loaded by the main application across several sessions, reducing load time; but this depends on
how frequently the browser’s cache is flushed.
You can preload modules at any time so that you can have the modules’ SWF files in memory even if the module
is not currently being used.
To preload modules on application startup, use the IModuleInfo class load() method. This loads the module into
memory but does not create an instance of the module.
The following example loads the BarChartModule.swf module when the application starts up, even though it will
not be displayed until the user navigates to the second pane of the TabNavigator. Without preloading, the user
would wait for the SWF file to be transferred across the network when they navigated to the second pane of the
TabNavigator.
<?xml version="1.0"?>
<!-- modules/PreloadModulesApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="preloadModules()">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
import mx.modules.IModuleInfo;
<mx:Panel
title="Module Example"
height="90%"
width="90%"
paddingTop="10"
paddingLeft="10"
paddingRight="10"
paddingBottom="10"
>
<mx:TabNavigator id="tn"
width="100%"
height="100%"
creationPolicy="auto"
>
<mx:VBox id="vb1" label="Column Chart Module">
<mx:Label id="l1" text="ColumnChartModule.swf"/>
<mx:ModuleLoader url="ColumnChartModule.swf"/>
</mx:VBox>
<mx:VBox id="vb2" label="Bar Chart Module">
<mx:Label id="l2" text="BarChartModule.swf"/>
<mx:ModuleLoader url="BarChartModule.swf"/>
</mx:VBox>
</mx:TabNavigator>
</mx:Panel>
</mx:Application>
progress.indeterminate=true;
unload.enabled=false;
reload.enabled=false;
}
public function onProgress(event:Event):void {
progress.label="Loaded %1 of %2 bytes...";
progress.indeterminate=false;
unload.enabled=true;
reload.enabled=false;
}
if (contains(standin))
removeChild(standin);
}
Main application:
<?xml version="1.0"?>
<!-- modules/EventApp.mxml -->
<mx:Application xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var selectedItem:Object;
]]>
</mx:Script>
<mx:ComboBox
1002 CHAPTER 30
width="215"
labelField="label"
close="selectedItem=ComboBox(event.target).selectedItem"
>
<mx:dataProvider>
<mx:Object label="Select Coverage"/>
<mx:Object
label="Life Insurance"
module="insurancemodules/LifeInsurance.swf"
/>
<mx:Object
label="Auto Insurance"
module="insurancemodules/AutoInsurance.swf"
/>
<mx:Object
label="Home Insurance"
module="insurancemodules/HomeInsurance.swf"
/>
</mx:dataProvider>
</mx:ComboBox>
]]>
</mx:Script>
paddingBottom="10"
>
<mx:HBox>
<mx:Label text="URL:"/>
<mx:TextInput width="200" id="ti1" text="ColumnChartModule.swf"/>
<mx:Button label="Load" click="createModule()"/>
<mx:Button label="Unload" click="removeModule()"/>
</mx:HBox>
<mx:ModuleLoader id="chartModuleLoader" error="errorHandler(event)"/>
</mx:Panel>
</mx:Application>
[Bindable]
public var progBar:String = "";
[Bindable]
public var progMessage:String = "";
</mx:Script>
<mx:ModuleLoader
id="chartModuleLoader"
url="ColumnChartModule.swf"
progress="progressEventHandler(event)"
/>
</mx:Panel>
</mx:Application>
You can also connect a module loader to a ProgressBar control. The following example creates a custom
component for the ModuleLoader that includes a ProgressBar control. The ProgressBar control displays the
progress of the module loading.
<?xml version="1.0"?>
<!-- modules/MySimpleModuleLoader.mxml -->
<mx:ModuleLoader xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function clickHandler():void {
if (!url) {
url="ColumnChartModule.swf";
}
loadModule();
}
]]>
</mx:Script>
<mx:ProgressBar
id="progress"
width="100%"
source="{this}"
/>
<mx:HBox width="100%">
<mx:Button
id="load"
label="Load"
click="clickHandler()"
/>
<mx:Button
id="unload"
1006 CHAPTER 30
label="Unload"
click="unloadModule()"
/>
<mx:Button
id="reload"
label="Reload"
click="unloadModule();loadModule();"
/>
</mx:HBox>
</mx:ModuleLoader>
You can use this module in a simple application, as the following example shows:
<?xml version="1.0"?>
<!-- modules/ComplexProgressEventHandler.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*">
Passing data
Communication between modules and the parent application, and among modules, is possible. You can use the
following approaches to facilitate inter-module, application-to-module, and module-to-application communi-
cation:
• ModuleLoader child, ModuleManager factory, and Application parentApplication properties — You
can use these properties to access modules and applications. However, by using these properties, you might create
a tightly-coupled design that prevents code reuse. In addition, you might also create dependencies among
modules and applications that cause class sizes to be bigger. For more information, see “Accessing modules from
the parent application” on page 1007, “Accessing the parent application from the modules” on page 1009, and
“Accessing modules from other modules” on page 1011.
ADOBE FLEX 3 1007
Adobe Flex 3 Developer Guide
• Query string parameters — Modules are loaded with a URL; you can pass parameters on this URL and then
parse those parameters in the module. For more information, see “Passing data with the query string” on
page 1012.
• Interfaces — You can create ActionScript interfaces that define the methods and properties that modules and
applications can access. This gives you greater control over module and application interaction. It also prevents
you from creating dependencies between modules and applications. For more information, see “Using interfaces
for module communication” on page 1014.
The following techniques for accessing methods and properties apply to parent applications as well as modules.
Modules can load other modules, which makes the loading module similar to the parent application in the simpler
examples.
}
]]></mx:Script>
</mx:Module>
This approach creates a tight coupling between the application and the module, and does not easily let you use the
same code when loading multiple modules. Another technique is to use an interface to define the methods and
properties on the module (or group of modules) that the application can call. For more information, see “Using
interfaces for module communication” on page 1014.
If you load the module that you want to call by using the ModuleManager API, there is some additional coding in
the shell application. You use the ModuleManager factory property to get an instance of the module’s class. You
can then call the module’s method on that instance.
The following module example defines a single method, computeAnswer():
<?xml version="1.0"?>
<!-- modules/mxmlmodules/SimpleModule.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function computeAnswer(a:Number, b:Number):Number {
return a + b;
}
]]>
</mx:Script>
</mx:Module>
The following example gets an instance of the SimpleModule class by using the factory property to call the
create() method. It then calls the computeAnswer() method on that instance:
<?xml version="1.0"?>
<!-- modules/mxmlmodules/SimpleMXMLApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.modules.IModuleInfo;
import mx.modules.ModuleManager;
public var assetModule:IModuleInfo;
public var sm:Object;
[Bindable]
public var answer:Number = 0;
<mx:Form>
<mx:FormHeading label="Enter values to sum."/>
<mx:FormItem label="First Number">
<mx:TextInput id="ti1" width="50"/>
</mx:FormItem>
<mx:FormItem label="Second Number">
<mx:TextInput id="ti2" width="50"/>
</mx:FormItem>
<mx:FormItem label="Result">
<mx:Label id="ti3" width="100" text="{answer}"/>
</mx:FormItem>
<mx:Button id="b1" label="Compute" click="addNumbers()"/>
</mx:Form>
</mx:Application>
In this example, you should actually create a module that extends the ModuleBase class in ActionScript rather
than an MXML-based module that extends the Module class. This is because this example does not have any
visual elements and contains only a single method that computes and returns a value. A module that extends the
ModuleBase class would be more lightweight than a class that extends Module. For more information on writing
ActionScript-based modules that extend the ModuleBase class, see “Creating ActionScript-based modules” on
page 990.
[Bindable]
private var expenses:ArrayCollection;
1010 CHAPTER 30
[Bindable]
public var expenses:ArrayCollection = new ArrayCollection([
{Month:"Jan", Profit:2000, Expenses:1500},
{Month:"Feb", Profit:1000, Expenses:200},
{Month:"Mar", Profit:1500, Expenses:500}
]);
]]></mx:Script>
<mx:ModuleLoader url="ChartChildModule.swf" id="m1"/>
ADOBE FLEX 3 1011
Adobe Flex 3 Developer Guide
</mx:Application>
You can also call methods and access properties on other modules. For more information, see “Accessing modules
from other modules” on page 1011.
The drawback to this approach is that it can create dependencies on the parent application inside the module. In
addition, the modules are no longer portable across multiple applications unless you ensure that you replicate the
behavior of the applications.
To avoid these drawbacks, you should use interfaces that secure a contract between the application and its
modules. This contract defines the methods and properties that you can access. Having an interface lets you reuse
the application and modules as long as you keep the interface updated. For more information, see “Using inter-
faces for module communication” on page 1014.
]]></mx:Script>
<mx:HBox>
<mx:Label id="l1" text="Title: "/>
<mx:Label id="myTitle" text="{title}"/>
</mx:HBox>
<mx:Button id="b1" label="Change Title" click="changeTitle()"/>
</mx:Module>
The application in this example lets the two modules communicate with each other. You could, however, define
methods and properties on the application that the modules could access. For more information, see “Accessing
the parent application from the modules” on page 1009.
As with accessing the parent application’s properties and methods directly, using the technique described in this
section can make your modules difficult to reuse and also can create dependencies that can cause the module to
be larger than necessary. Instead, you should use interfaces to define the contract between modules. For more
information, see “Using interfaces for module communication” on page 1014.
]]></mx:Script>
<mx:Form>
<mx:FormItem id="fi1" label="First Name:">
<mx:TextInput id="ti1"/>
</mx:FormItem>
<mx:FormItem id="fi2" label="Last Name:">
<mx:TextInput id="ti2"/>
</mx:FormItem>
</mx:Form>
<mx:ModuleLoader id="m1"/>
<mx:Button id="b1" label="Submit" click="initModule()"/>
</mx:Application>
The following example module parses the query string that was used to load it. If the firstName and lastName
parameters are set, the module prints the results in a TextArea. The module also traces some additional infor-
mation available through the LoaderInfo object:
<?xml version="1.0"?>
<!-- modules/QueryStringModule.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="parseString()">
<mx:Script>
<![CDATA[
import mx.utils.*;
[Bindable]
private var salutation:String;
The following example application lets you customize the appearance of the module that it loads by calling
methods on the custom IModuleInterface interface. The application also calls the getModuleName() method.
This method returns a value from the module and sets a local property to that value.
<?xml version="1.0"?>
<!-- modules/interfaceexample/MainModuleApp.mxml -->
<mx:Application xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
[Bindable]
public var selectedItem:Object;
[Bindable]
public var currentModuleName:String;
<mx:Form>
<mx:FormItem label="Current Module:">
<mx:Label id="l1" text="{currentModuleName}"/>
</mx:FormItem>
<mx:FormItem label="Adjuster ID:">
<mx:TextInput id="myId" text="Enter your ID"/>
</mx:FormItem>
<mx:FormItem label="Background Color:">
<mx:ColorPicker id="myColor"
selectedColor="0xFFFFFF"
change="reloadModule()"
/>
</mx:FormItem>
1016 CHAPTER 30
</mx:Form>
function getModuleName():String;
function setAdjusterID(s:String):void;
function setBackgroundColor(n:Number):void;
}
}
The following example defines the module that is loaded by the previous example. It implements the custom
IModuleInterface interface.
<?xml version="1.0"?>
<!-- modules/interfaceexample/AutoInsurance2.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
implements="IModuleInterface">
<mx:Panel id="p1"
title="Auto Insurance"
width="100%"
height="100%"
backgroundColor="{bgcolor}"
>
<mx:Label id="myLabel" text="ID: {adjuster}"/>
</mx:Panel>
<mx:Script>
ADOBE FLEX 3 1017
Adobe Flex 3 Developer Guide
<![CDATA[
[Bindable]
private var adjuster:String;
[Bindable]
private var bgcolor:Number;
Topics
About printing by using Flex classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1019
Using the FlexPrintJob class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1020
Using a print-specific output format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1024
Printing multipage output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1028
Users can print to PostScript and non-PostScript printers, including the Adobe® PDF® and Adobe® FlashPaper™
from Adobe® printer drivers.
Note: Because you are spooling a print job to the user’s operating system between your calls to the start() and
send() methods, you should limit the code between these calls to print-specific activities. For example, the content
should not interact with the user between the start() and send() methods.
The following sections detail the procedures to use in these steps.
Constant Action
MATCH_WIDTH (Default) Scales the object to fill the available page width. If the resulting object height exceeds the page height, the
output spans multiple pages.
MATCH_HEIGHT Scales the object to fill the available page height. If the resulting object width exceeds the page width, the output spans
multiple pages.
1022 CHAPTER 31
Constant Action
SHOW_ALL Scales the object to fit on a single page, filling one dimension; that is, it selects the smaller of the MATCH_WIDTH or
MATCH_HEIGHT scale types.
FILL_PAGE Scales the object to fill at least one page completely; that is, it selects the larger of the MATCH_WIDTH or
MATCH_HEIGHT scale types.
NONE Does not scale the output. The printed page has the same dimensions as the object on the screen. If the object height,
width, or both dimensions exceed the page width or height, the output spans multiple pages.
If an object requires multiple pages, the output splits at the page boundaries. This can result in unreadable text or
inappropriately split graphics. For information on how to format your print job to avoid these problems, see
“Printing multipage output” on page 1028.
The FlexPrintJob class includes two properties that can help your application determine how to scale the print job.
These properties are read-only and are initially 0. When the application calls the start() method and the user
selects the Print option in the operating system Print dialog box, Flash Player or AIR retrieves the print settings
from the operating system. The start() method populates the following properties:
pageHeight Number Points Height of the printable area on the page; does not include any user-set margins.
pageWidth Number Points Width of the printable area on the page; does not include any user-set margins.
Note: A point is a print unit of measurement that is 1/72 of an inch. Flex automatically maps 72 pixels to one inch
(72 points) of printed output, based on the printer settings.
<mx:Script>
<![CDATA[
ADOBE FLEX 3 1023
Adobe Flex 3 Developer Guide
import mx.printing.*;
The following image shows how the output looks when the user clicks the Print button to print the data:
In this example, the MXML application file displays the screen and controls the printing. A separate custom
MXML component defines the appearance of the printed output.
When the user clicks the Print button, the application’s doPrint() method does the following things:
1 Creates and starts the print job to display the operating system’s Print dialog box.
2 After the user starts the print operation in the Print dialog box, creates a child control using the myPrintView
component.
1026 CHAPTER 31
<mx:Script>
<![CDATA[
import mx.printing.FlexPrintJob;
import myComponents.MyPrintView;
]]>
</mx:Script>
<mx:columns>
<mx:DataGridColumn dataField="Product"/>
<mx:DataGridColumn dataField="Code"/>
</mx:columns>
</mx:PrintDataGrid>
</mx:VBox>
You can solve these problems by using the following features of the PrintDataGrid control. These features let you
correctly print grids that contain multiple pages of data without splitting rows across pages:
sizeToPage property Makes the printed data grid contain only full rows.
nextPage() method Gets the next printable page of data.
validNextPage property Is true if printing the data requires an additional page.
Property Description
currentPageHeight Contains the height of the grid, in pixels, that results if the sizeToPage property is true. If the sizeToPage
property is true, the currentPageHeight property equals the height property.
originalHeight Contains the grid height that results if the sizeToPage property is false. If the sizeToPage property is
false, the originalHeight property equals the height property.
In most applications, you leave the sizeToPage attribute at its default value (true), and use the height property
to determine the grid height.
The sizeToPage property does not affect the way the page breaks when a single PrintDataGrid control page is
longer than a print page. To print multipage data grids without splitting rows, you must divide the grid items into
multiple views by using the nextPage() method, as described in “Using the nextPage() method and validNex-
tPage property to print multiple pages” on page 1029.
Using the nextPage() method and validNextPage property to print multiple pages
The validNextPage property is true if the PrintDataGrid control has data beyond the rows that fit on the
current print page. You use it to determine whether you need to format and print an additional page.
1030 CHAPTER 31
The nextPage() method lets you page through the data provider contents by setting the first row of the PrintDa-
taGrid control to be the data provider row that follows the last row of the previous PrintDataGrid page. In other
words, the nextPage() method increases the grid’s verticalScrollPosition property by the value of the grid’s
rowCount property.
The following code shows a loop that prints a grid using multiple pages, without having rows that span pages:
// Queue the first page.
printJob.addObject(thePrintView);
// While there are more pages, print them.
while (thePrintView.myDataGrid.validNextPage) {
//Put the next page of data in the view.
thePrintView.myDataGrid.nextPage();
//Queue the additional page.
printJob.addObject(thePrintView);
}
The section “Example: Printing with multipage PrintDataGrid controls” on page 1030 shows how to use the
nextPage() method to print a report with a multipage data grid.
• The print output template includes the PrintDataGrid control and uses two MXML components to format
the header and footer contents.
• The showPage() function determines which sections of the template to include in a particular page of the
output, based on the page type: first, middle, last, or single. On the first page of multipage output, the
showPage() function hides the footer; on the middle and last pages, it hides the header. On a single page, it
shows both header and footer.
• The FormPrintHeader.mxml and formPrintFooter.mxml files specify the contents of the start and the end of
the output. To keep the application simple, the header has a single, static Label control. The footer displays a total
of the numbers in the Quantity column. In a more complete application, the header page could have, for example,
a shipping address, and the footer page could show more detail about the shipment totals.
The files include detailed comments explaining the purpose of the code.
thePrintView.myDataGrid.nextPage();
</mx:Form>
</mx:Application>
page has only as many grid rows as are needed for the data. -->
<mx:PrintDataGrid id="myDataGrid" width="60%" height="100%">
<!-- Specify the columns to ensure that their order is correct. -->
<mx:columns>
<mx:DataGridColumn dataField="Index" />
<mx:DataGridColumn dataField="Qty" />
</mx:columns>
</mx:PrintDataGrid>
<?xml version="1.0"?>
<!-- printing\ADGPrint.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.printing.*;
import mx.collections.ArrayCollection;
import mx.printing.PrintAdvancedDataGrid;
include "SimpleHierarchicalData.as";
<mx:VBox id="myVBox"
width="100%" height="100%">
<mx:AdvancedDataGrid id="adg"
width="100%" height="100%">
<mx:dataProvider>
<mx:HierarchicalData source="{dpHierarchy}"/>
</mx:dataProvider>
<mx:columns>
<mx:AdvancedDataGridColumn dataField="Region"/>
<mx:AdvancedDataGridColumn dataField="Territory_Rep"
headerText="Territory Rep"/>
ADOBE FLEX 3 1037
Adobe Flex 3 Developer Guide
<mx:AdvancedDataGridColumn dataField="Actual"/>
<mx:AdvancedDataGridColumn dataField="Estimate"/>
</mx:columns>
</mx:AdvancedDataGrid>
<mx:Button id="myButton"
label="Print"
click="doPrint();"/>
</mx:VBox>
</mx:Application>
This example uses the PrintAdvancedDataGrid.source property to initialize the PrintAdvancedDataGrid
control from the AdvancedDataGrid control.
To support the AdvancedDataGrid control, the PrintAdvancedDataGrid control adds the following properties not
available in the PrintDataGrid control:
Property Description
allowInteractions If true, allow some interactions with the control, such as column resizing, column reordering, and expanding
or collapsing nodes. The default value is false.
displayIcons If true, display the folder and leaf icons in the navigation tree. The default value is true.
source Initialize the PrintAdvancedDataGrid control and all of its properties from the specified AdvancedDataGrid
control.
validPreviousPage Indicates that the data provider contains data rows that precede the rows that the PrintAdvancedDataGrid
control currently displays.
1038 CHAPTER 31
1039
Topics
About exchanging data with Flex applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1039
Passing request data with flashVars properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1043
Accessing JavaScript functions from Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1047
Accessing Flex from JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1056
About ExternalInterface API security in Flex. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1061
Use the methods of the ExternalInterface API to call the methods of your Flex applications and vice versa. The
addCallback() method exposes methods of your Flex application to the wrapper. The call() method invokes
a method within the wrapper and returns any results. If the wrapper is HTML, the addCallback() and call()
methods enable method invocation between your Flex application and the hosted JavaScript running within the
browser. For more information, see “About the ExternalInterface API” on page 1041.
In some situations, you want to open a new browser window or navigate to a new location. You can do this with
the navigateToURL() global function. Although it is not part of the ExternalInterface API, this method is flexible
enough to let you write JavaScript inside it, and invoke JavaScript functions on the resulting HTML page. The
navigateToURL() method is a global function in the flash.net package.
[Bindable]
public var g_HostString:String;
[Bindable]
public var g_ContextRoot:String;
[Bindable]
public var g_BaseURL:String;
<mx:Form>
<mx:FormItem label="Base URL:">
<mx:Label text="{g_BaseURL}"/>
</mx:FormItem>
<mx:FormItem label="Host Name:">
<mx:Label text="{g_HostString}"/>
</mx:FormItem>
<mx:FormItem label="Context Root:">
ADOBE FLEX 3 1041
Adobe Flex 3 Developer Guide
<mx:Label text="@ContextRoot()"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
You can also use the flash.system.Capabilities class to access information about the client, such as Operating
System, Player version, and language. For more information, see Using Flash ActionScript.
You can access more information about the browser and the application’s environment using the Exter-
nalInterface. For more information, see “About the ExternalInterface API” on page 1041.
]]></mx:Script>
</mx:Application>
For examples of using the ExternalInterface API with Flex applications, see “Using the ExternalInterface API to
access JavaScript from Flex” on page 1047 and “Accessing Flex from JavaScript” on page 1056.
In addition to requiring that browsers meet certain version requirements, the ExternalInterface API requires that
JavaScript is enabled in the browser. You can use the <noscript> tag in the HTML page to handle a browser with
disabled JavaScript. For more information, see “Handling browsers that disable JavaScript” on page 1060.
The available property determines only if the browser can support the ExternalInterface API, based on its
version and manufacturer. If JavaScript is disabled in the browser, the available property still returns true.
The ExternalInterface API is restricted by the security sandbox in which the SWF file is running. Its use relies on
the domain-based security restrictions that the allowScriptAccess and allowNetworking parameters define.
You set the values of the allowScriptAccess and allowNetworking parameters in the SWF file’s wrapper.
For more information on these parameters, see “Creating a Wrapper” on page 311 in Building and Deploying
Adobe Flex 3 Applications.
For more information on security restrictions, see “About ExternalInterface API security in Flex” on page 1061;
also see “Applying Flex Security” on page 29 in Building and Deploying Adobe Flex 3 Applications.
ADOBE FLEX 3 1043
Adobe Flex 3 Developer Guide
</td></tr></table>
</body>
</html>
1044 CHAPTER 32
If you are using the wrapper that is generated by the web-tier compiler or Adobe® Flex® Builder™, or one of the
wrappers that are included in the /templates directory, your wrapper will probably be very different from the
previous example. These wrappers call functions in the AC_OETags.js file to build the <object> and <embed>
tag structure in the HTML page. As a result, you pass the flashVars as parameters to the AC_FL_RunContent()
function in the wrapper. For a function call that already has a flashVars parameter, you can append your
flashVars to the end, as the following example shows:
"FlashVars","MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+
MMdoctitle+'&myName=Danger&myHometown=Los%20Angeles'+"",
If the function parameters do not already include the flashVars variable, then you can insert it in the list, as the
following example shows:
AC_FL_RunContent(
"src", "TestApp",
"flashVars", "myName=Danger&myHometown=Los%20Angeles",
"width", "100%",
"height", "100%",
"align", "middle",
"id", "TestApp",
"quality", "high",
"name", "TestApp",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer"
);
The value of the flashVars properties do not have to be static. If you use JSP to return the wrapper, for example,
you can use any JSP expression for the value of the flashVars properties that can be evaluated to a String.
The following example uses the values stored in the HttpServletRequest object (in this case, you can use form or
query string parameters):
<html>
<head>
<title>/flex2/code/wrapper/DynamicFlashVarTestWrapper.jsp</title>
<style>
body { margin: 0px;
overflow:hidden }
</style>
</head>
<%
String fName = (String) request.getParameter("firstname");
String mName = (String) request.getParameter("middlename");
String lName = (String) request.getParameter("lastname");
%>
<body scroll='no'>
<table width='100%' height='100%' cellspacing='0' cellpadding='0'><tr><td valign='top'>
<script>
<h1>Dynamic FlashVarTest Wrapper</h1>
</script>
ADOBE FLEX 3 1045
Adobe Flex 3 Developer Guide
</td></tr></table>
</body>
</html>
If your user requests the SWF file directly in the browser, without a wrapper, you can access variables on the query
string without providing additional code. The following URL passes the name Nick and the hometown San
Francisco to the Flex application:
http://localhost:8100/flex/myApp.swf?myName=Nick&myHometown=San%20Francisco
For more information about the HTML wrapper, see “About the wrapper” on page 311 in Building and Deploying
Adobe Flex 3 Applications.
Variables you define in this manner are accessible in the same way as flashVars properties. For more infor-
mation, see “Accessing the flashVars properties” on page 1046.
<mx:VBox>
<mx:HBox>
<mx:Label text="Name: "/>
<mx:Label text="{myName}" fontWeight="bold"/>
</mx:HBox>
<mx:HBox>
<mx:Label text="Hometown: "/>
<mx:Label text="{myHometown}" fontWeight="bold"/>
</mx:HBox>
</mx:VBox>
</mx:Application>
When a user requests this application with the myName and myHometown parameters defined as flashVars
properties, Flex displays their values in the Label controls.
To view all the flashVars properties, you can iterate over the parameters object, as the following example shows:
<?xml version="1.0"?>
<!-- wrapper/IterateOverApplicationParameters.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
ADOBE FLEX 3 1047
Adobe Flex 3 Developer Guide
<mx:Script><![CDATA[
private function init():void {
for (var i:String in Application.application.parameters) {
ta1.text += i + ":" + Application.application.parameters[i] + "\n";
}
}
]]></mx:Script>
</mx:Application>
To use the ExternalInterface, you must make the id and name properties in the HTML page callable. For more
information, see “Editing the Flex application’s id and name properties” on page 1059.
<mx:Form>
<mx:FormItem label="New Title:">
<mx:TextInput id="ti1"/>
</mx:FormItem>
</mx:Form>
<SCRIPT LANGUAGE="JavaScript">
function changeDocumentTitle(a) {
ADOBE FLEX 3 1049
Adobe Flex 3 Developer Guide
window.document.title=a;
alert(a);
return "successful";
}
</SCRIPT>
</mx:Application>
1050 CHAPTER 32
Flex only serializes public, nonstatic variables and read-write properties of ActionScript objects. You can pass
numbers and strings as properties on objects, simple objects such as primitive types and arrays, or arrays of simple
objects.
The JavaScript code can then access properties of the object, as the following example shows:
<html><head>
<title>wrapper/DataTypeWrapper.html</title>
</head>
<body scroll='no'>
<SCRIPT LANGUAGE="JavaScript">
function receiveComplexDataTypes(o) {
alert("Welcome " + o.fname + " " + o.lname + "!");
return "successful";
}
</SCRIPT>
</body></html>
You can also embed objects within objects, such as an Array within an Object, as the following example shows.
Add the following code in your Flex application’s <mx:Script> block:
<?xml version="1.0"?>
<!-- wrapper/ComplexDataTypeSender.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import flash.external.*;
</mx:Application>
The code triggers the JavaScript function in the following wrapper:
<html><head>
<title>wrapper/ComplexDataTypeWrapper.html</title>
</head>
<body scroll='no'>
<SCRIPT LANGUAGE="JavaScript">
function receiveComplexDataTypes(o) {
// Get value of fname and lname properties.
var s = ("Welcome " + o.fname + " " + o.lname + "!\n");
// Iterate over embedded object's properties.
for (i=0; i<o.b.length; i++) {
s += o.b[i] + "\n";
}
alert(s);
}
</SCRIPT>
</body></html>
Flex and Flash Player have strict security in place to prevent cross-site scripting. By default, you cannot call script
on an HTML page if the HTML page is not in the same domain as the Flex application. However, you can expand
the sources from which scripts can be called. For more information, see “About ExternalInterface API security in
Flex” on page 1061.
You cannot pass objects or arrays that contain circular references. For example, you cannot pass the following
object:
1052 CHAPTER 32
Value Description
_blank Specifies a new window. This new window acts as a pop-up window in the client’s browser, so you must be aware that
a pop-up blocker could prevent it from loading.
ADOBE FLEX 3 1053
Adobe Flex 3 Developer Guide
Value Description
You pass a URLRequest object to the navigateToURL() method. This object defines the URL target, variables,
method (POST or GET), window, and headers for the request. The following example defines a simple URL to
navigate to:
<?xml version="1.0"?>
<!-- wrapper/SimplestNavigateToURL.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import flash.net.*;
public function openNewWindow(event:MouseEvent):void {
var u:URLRequest = new URLRequest("http://www.adobe.com/flex");
navigateToURL(u,"_blank");
}
]]></mx:Script>
<mx:Button label="Open New Window" click="openNewWindow(event)"/>
</mx:Application>
The navigateToURL() method URL encodes the value of the url argument.
To send data with a URLRequest object, you can append variables to the request string. The following example
launches a new window and passes a search term to the URL:
<?xml version="1.0"?>
<!-- wrapper/SimpleNavigateToURL.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import flash.net.*;
public function executeSearch(event:MouseEvent):void {
var u:URLRequest = new URLRequest("http://www.google.com/search?hl=en&q=" +
ta1.text);
navigateToURL(u,"_blank");
}
]]></mx:Script>
<mx:TextArea id="ta1"/>
<mx:Button label="Search" click="executeSearch(event)"/>
</mx:Application>
In addition to appending strings, you can also use the data property of the URLRequest to add URL variables to
a GET or POST request. The query string parameters are of type URLVariables. Flex adds ampersand delimiters
for you in the URL request string. The following example adds name=fred to the URLRequest:
<?xml version="1.0"?>
<!-- wrapper/NavigateWithGetMethod.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import flash.net.*;
public function openNewWindow(event:MouseEvent):void {
var url:URLRequest = new URLRequest("http://mysite.com/index.jsp");
var uv:URLVariables = new URLVariables();
1054 CHAPTER 32
url.method = "GET";
uv.name = "fred";
url.data = uv;
navigateToURL(url,"_blank");
}
]]></mx:Script>
<mx:Button label="Open New Window" click="openNewWindow(event)"/>
</mx:Application>
To use POST data with the URLRequest object, set the value of the URLRequest object’s method property to POST.
• Executes the JavaScript URLs asynchronously. This means that it is possible to have multiple calls to the
navigateToURL() method that is trying to execute JavaScript methods, and have only the last one occur. Each one
overwrites the next.
• Stops all other navigation, such as loading of images and IFRAMEs when you call a JavaScript URL.
• Displays a security warning dialog box if the URL contains ampersand (&) or question mark (?) characters.
</mx:Application>
The enclosing HTML wrapper includes the JavaScript to process this call, as the following example shows:
<html><head>
<title>wrapper/NavigateToURLWrapper.html</title>
</head>
<body scroll='no'>
<SCRIPT LANGUAGE="JavaScript">
function catchClick(name, type) {
alert(name + " triggered the " + type + " event.");
}
</SCRIPT>
</body></html>
You can also use the navigateToURL() method with basic JavaScript functions in the URLRequest itself. For
example, you can launch the default e-mail client with a single line of code:
<?xml version="1.0"?>
<!-- wrapper/EmailWithNavigateToURL.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
import flash.net.*;
public function sendMail(e:Event):void {
var u:URLRequest = new URLRequest("mailto:" + ti1.text);
navigateToURL(u,"_self");
}
</mx:Script>
<mx:Button id="b1" click="sendMail(event)" label="Send Mail"/>
<mx:Form>
<mx:FormItem>
<mx:Label text="Email Address: "/>
</mx:FormItem>
<mx:FormItem>
<mx:TextInput id="ti1"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
Not all browsers support invoking the javascript protocol with the navigateToURL() method. If possible, you
should use the call() method of the ExternalInterface API to invoke JavaScript methods in the enclosing HTML
page. For more information, see “Using the ExternalInterface API to access JavaScript from Flex” on page 1047.
addCallback(function_name:String, closure:Function):void
The function_name parameter is the name by which you call the Flex function from your HTML page’s scripts.
The closure parameter is the local name of the function that you want to call. This parameter can be a method
on the application or an object instance.
The following example declares the myFunc() function to be callable by the wrapper:
<?xml version="1.0"?>
<!-- wrapper/AddCallbackExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
import flash.external.*;
</mx:Script>
<mx:Label id="l1"/>
</mx:Application>
To call the Flex function from the HTML page, you get a reference to the movie object. This is the same value as
the id and name properties of the <object> and <embed> tags. In this case, it is mySwf. You then call the method
on that object, passing whatever parameters you want, as the following example shows:
<html><head>
<title>wrapper/AddCallbackWrapper.html</title>
</head>
<body scroll='no'>
<SCRIPT LANGUAGE="JavaScript">
function callApp() {
window.document.title = document.getElementById("newTitle").value;
mySwf.myFlexFunction(window.document.title);
}
</SCRIPT>
<h1>AddCallback Wrapper</h1>
<form id="f1">
Enter a new title: <input type="text" size="30" id="newTitle" onchange="callApp()">
</form>
</body></html>
The default value of the id and name properties in the wrapper is mxml_filename.mxml.swf. The name that you
use to access the Flex application in your HTML page’s script cannot contain any periods, so you must change the
default values in the wrapper. For more information, see “Editing the Flex application’s id and name properties”
on page 1059.
If you do not know which browser your users will be using when they request your Flex application, you should
make your wrapper’s script browser independent. For more information, see “Handling multiple browser types”
on page 1058.
If there is no function with the appropriate name in the Flex application or that function hasn’t been made callable,
the browser throws a JavaScript error.
Flex and Flash Player have strict security in place to prevent cross-site scripting. By default, Flex functions are not
callable by HTML scripts. You must explicitly identify them as callable. You also cannot call a Flex function from
an HTML page if the HTML page is not in the same domain as the application. However, it is possible to expand
the sources from which Flex functions are called. For more information, see “About the addCallback() method”
on page 1061.
<SCRIPT LANGUAGE="JavaScript">
// Internet Explorer and Mozilla-based browsers refer to the Flash application
// object differently.
// This function returns the appropriate reference, depending on the browser.
function getMyApp(appName) {
if (navigator.appName.indexOf ("Microsoft") !=-1) {
return window[appName];
ADOBE FLEX 3 1059
Adobe Flex 3 Developer Guide
} else {
return document[appName];
}
}
function callApp() {
window.document.title = document.getElementById("newTitle").value;
getMyApp("mySwf").myFlexFunction(window.document.title);
}
</SCRIPT>
<h1>AddCallBack Wrapper</h1>
<form id="f1">
Enter a new title: <input type="text" size="30" id="newTitle" onchange="callApp()">
</form>
</body></html>
Value Description
sameDomain The call() method succeeds if the calling application is from same domain as the HTML page. This is the default
value.
always The call() method succeeds, regardless of whether the calling application is in the same domain as the HTML
page.
By default, an HTML page can only communicate with the ActionScript in your Flex application if it originates
from the same domain. You allow HTML pages outside of the Flex application’s domain to call methods of your
application using the allowDomain() method. For more information, see the Adobe Flex Language Reference.
1063
Topics
About the Flex Ajax Bridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1063
Integrating with the Flex Ajax Bridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1064
• You are building an integrated rich Internet application (RIA) with Flex and Ajax portions.Although you
could build the integration yourself using ExternalInterface, you might find it faster to start with the FABridge.
To script multiple applications on the same page, give them unique bridge names through the flashvars
mechanism. Use the bridge name to access them from the bridge, and to register for initialization callbacks, as the
following example shows:
<object ...>
<param name='flashvars' value='bridgeName=shoppingPanel'/>
<param name='src' value='app.swf'/>
<embed ... flashvars='bridgeName=shoppingPanel'/>
</object>
function initMaxPrice(maxPrice)
{
var initCallback = function()
{
var flexApp = FABridge.shoppingPanel.root();
flexApp.getMaxPriceSlider().setValue(maxPrice);
}
FABridge.addInitializationCallback("shoppingPanel",initCallback);
}
Handling exceptions
Exceptions that take place in the ActionScript of the bridge as a direct consequence of some JavaScript action are
now thrown over the bridge into JavaScript. The mechanism works as follows:
• When an exception is raised in the ActionScript section, it is caught in a try-catch block, serialized, and passed
to JavaScript.
• When the JavaScript part receives an answer from ActionScript, it checks for the exception serialization and,
if found, throws a JavaScript error with the message received from ActionScript.
Note: To catch and use the exception information, you must surround the code that calls into ActionScript with a
try-catch block. You can handle the error in the catch(e) block.
Topics
About deep linking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1069
Using the BrowserManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1072
Setting the title of the HTML wrapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1079
Passing request data with URL fragments. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1080
Using deep linking with navigator containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1082
Accessing information about the current URL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1086
Using the HistoryManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1088
• Recognize when the URL in the browser’s address bar has changed. If the user clicks the Forward or Back
button, or changes the URL in the address bar, the Flex application is notified and can react to the change.
What states of your application are bookmarkable will vary by application, but possibilities include a login page,
a product page, a search result page, or a drill down view into data.
Deep linking only works with certain browsers. The following browsers support deep linking:
• Microsoft Internet Explorer version 6 or later
• FireFox for Windows and Macintosh
• Safari for Macintosh
In addition to requiring these browsers, deep linking requires that the client browser also has scripting enabled.
Deep linking does not work with the standalone Adobe® Flash® Player or Adobe AIR™.
When writing an application that uses deep linking, you cannot use the HistoryManager class, as described in
“Using the HistoryManager” on page 1088. The deep linking functionality automatically sets the application’s
historyManagementEnabled property to false.
You typically use the methods of the URLUtil class to parse the URL. This class provides methods for detecting
the server name, port number, and protocol of a URL. In addition, you can use the objectToString() method
to convert an ActionScript object to a String that you then append to the end of a URL. Alternatively, you can
convert any number of name/value pairs on a query string into an object by using the URLUtil class’s
stringToObject() method. This lets you then manipulate the fragment more easily in your application logic.
If you use the multiple SDK feature in Flex Builder and change the SDK from 3 to 2.0.1, Flex Builder generates a
different set of files for history management support. For more information, see “Using multiple SDKs in Flex
Builder” on page 131 in Using Adobe Flex Builder 3.
To this:
http://localhost:8100/devapps/code/deeplinking/FragmentExample.html#panel=2
To this:
http://localhost:8100/devapps/code/deeplinking/FragmentExample.html#panel=0
Each time the Flex application changes the URL in the browser’s address bar, Flash Player dispatches an
applicationURLChange event. This example logs the previous and current URLs, which are properties of this
event object.
bm = BrowserManager.getInstance();
bm.init("", "Welcome!");
parseURL(e);
}
[Bindable]
private var indexFromURL:int;
private function parseURL(e:Event):void {
var o:Object = URLUtil.stringToObject(bm.fragment);
indexFromURL = o.index;
}
]]>
</mx:Script>
<mx:Accordion selectedIndex="{indexFromURL}">
<mx:VBox label="Panel 1">
<mx:Label text="Accordion container panel 1"/>
</mx:VBox>
<mx:VBox label="Panel 2">
<mx:Label text="Accordion container panel 2"/>
</mx:VBox>
<mx:VBox label="Panel 3">
<mx:Label text="Accordion container panel 3"/>
</mx:VBox>
</mx:Accordion>
</mx:Application>
The following example expands on the example from “Updating the URL” on page 1073. It reads the URL on
startup, and opens the application to the first, second, or third panel, depending on the value of the panel
fragment. It also sets the title of the HTML page according to which panel is opened.
<?xml version="1.0" encoding="utf-8"?>
<!-- deeplinking/TabNavExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp()"
historyManagementEnabled="false"
height="250"
width="500"
>
<mx:Script>
<![CDATA[
import mx.events.BrowserChangeEvent;
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
import mx.utils.URLUtil;
This example has one major drawback: it does not “remember” the state of the panel that is not in the current view.
If you copy the bookmark and open it in a new browser, the view that you were last looking at, and the state of the
CheckBox on that view, are maintained. However, the CheckBox in the other view that was hidden is reset to its
original value (unchecked). There are several techniques to solve this issue. For more information, see “Using
deep linking with navigator containers” on page 1082.
bm.addEventListener(BrowserChangeEvent.APPLICATION_URL_CHANGE, doEvent);
bm.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE, doEvent);
ADOBE FLEX 3 1079
Adobe Flex 3 Developer Guide
bm.addEventListener(BrowserChangeEvent.URL_CHANGE, doEvent);
<mx:Array id="dp">
<mx:Object label="one"/>
<mx:Object label="two"/>
<mx:Object label="three"/>
</mx:Array>
<mx:ComboBox id="cb"
dataProvider="{dp}"
change="bm.setFragment('selectedItem=' + cb.selectedItem.label);"
/>
<mx:DataGrid id="eventDG"
dataProvider="[]"
width="100%"
variableRowHeight="true"
wordWrap="true"
height="500"
/>
</mx:Application>
Changing the URL fragments in the browser’s address bar triggers a browserURLChange event but does not
trigger a page reload in FireFox. In Internet Explorer, changing the part of the address that is to the right of the
pound sign (“#”) does trigger a page reload.
import mx.managers.BrowserManager;
import mx.managers.IBrowserManager;
import mx.events.BrowserChangeEvent;
<mx:Form>
<mx:FormItem label="Name:">
<mx:TextInput id="ti1"/>
</mx:FormItem>
<mx:FormItem label="Hometown:">
<mx:TextInput id="ti2"/>
</mx:FormItem>
<mx:Button id="b1" click="updateTitle(event)" label="Submit"/>
</mx:Form>
</mx:Application>
To make the URL more “URL-like”, you can separate the fragments with an ampersand (“&”). When you convert
the fragment to an object with the stringToObject() method, you specify the new delimiter.
The following example takes a URL that sets the value of the firstName and lastName query string parameters
in its fragment. It specifies an ampersand as the delimiter.
<?xml version="1.0" encoding="utf-8"?>
<!-- deeplinking/PassURLParamsAsFragments.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
historyManagementEnabled="false"
creationComplete="init(event);"
>
<mx:Script>
<![CDATA[
import mx.managers.BrowserManager;
import mx.managers.IBrowserManager;
import mx.utils.URLUtil;
/* The following code will parse a URL that passes firstName and lastName as
query string parameters after the "#" sign; for example:
http://www.mydomain.com/MyApp.html#firstName=Nick&lastName=Danger */
var o:Object = URLUtil.stringToObject(bm.fragment, "&");
fName = o.firstName;
lName = o.lastName;
}
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="First name:">
<mx:Label id="ti1" text="{fName}"/>
</mx:FormItem>
<mx:FormItem label="Last name:">
<mx:Label id="ti2" text="{lName}"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
1082 CHAPTER 34
<![CDATA[
import mx.events.BrowserChangeEvent;
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
import mx.utils.URLUtil;
[Bindable]
private var agreeBoxFromURL:Boolean;
[Bindable]
private var personNameFromURL:String;
[Bindable]
private var hometownFromURL:String;
[Bindable]
private var cctypeFromURL:int;
[Bindable]
private var ccnumberFromURL:String;
private function init():void {
bm = BrowserManager.getInstance();
bm.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE, parseURL);
bm.init("", "Welcome!");
}
/* This method is called once when application starts up. It is also
called when the browser's address bar changes, either due to user action
or user navigation with the browser's Forward and Back buttons. */
private function parseURL(event:Event):void {
personNameFromURL = o.personName;
hometownFromURL = o.hometown;
ccnumberFromURL = o.ccnumber;
cctypeFromURL = o.cctype;
agreeBoxFromURL = o.agreeBox;
}
You must wrap the following assignments in a try/catch block, otherwise the
application tries to access components that have not yet been created.
You can circumvent this by setting the container's creationPolicy to "all",
but that is not a good solution for performance reasons. */
try {
1084 CHAPTER 34
personNameFromURL = personName.text;
hometownFromURL = hometown.text;
ccnumberFromURL = ccnumber.text;
cctypeFromURL = cctype.selectedIndex;
agreeBoxFromURL = agreeBox.selected;
} catch (e:Error) {
}
try {
o.panel = tn.selectedIndex;
o.personName = personName.text;
o.hometown = hometown.text;
o.ccnumber = ccnumber.text;
o.cctype = cctype.selectedIndex;
o.agreeBox = agreeBox.selected;
} catch (e:Error) {
} finally {
var s:String = URLUtil.objectToString(o, "&");
bm.setFragment(s);
}
}
]]>
</mx:Script>
</mx:dataProvider>
</mx:ComboBox>
</mx:FormItem>
<mx:FormItem label="Number:">
<mx:TextInput id="ccnumber"
text="{ccnumberFromURL}"
focusOut="updateURL()"
enter="updateURL()"
/>
</mx:FormItem>
</mx:Form>
</mx:Panel>
<mx:Panel label="Check Out">
<mx:TextArea id="ta2" text="You must agree to all the following conditions..."/>
<mx:CheckBox id="agreeBox"
label="Agree"
selected="{agreeBoxFromURL}"
click="updateURL()"
/>
</mx:Panel>
</mx:TabNavigator>
<mx:TextArea id="l1" height="400" width="300"/>
</mx:Application>
Rather than update the values of the bindable variables in the updateURL() method, you can also set their values
in the event handlers. For example, when the user changes the value of the hometown TextInput control, you can
use the focusOut and enter event handlers to set the value of the hometownFromURL property:
<mx:TextInput id="hometown"
text="{hometownFromURL}"
focusOut="hometownFromURL=hometown.text;updateURL()"
enter="hometownFromURL=hometown.text;updateURL()"
/>
In this example, the controls in the view update the model when the controls’ properties change. This helps
enforce a cleaner separation between the model and the view.
The following example use the URLUtil and BrowserManager classes to get information about the URL used to
return the application.
<?xml version="1.0" encoding="utf-8"?>
<!-- deeplinking/UseURLUtil.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
historyManagementEnabled="false"
creationComplete="initApp()"
height="250"
width="500"
>
<mx:Script>
<![CDATA[
import mx.utils.URLUtil;
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
import mx.events.BrowserChangeEvent;
<mx:Form>
<mx:FormItem label="Full URL:">
<mx:Label text="{fullURL}"/>
</mx:FormItem>
<mx:FormItem label="Base URL:">
<mx:Label text="{baseURL}"/>
</mx:FormItem>
<mx:FormItem label="Fragment:">
<mx:Label text="{fragment}"/>
</mx:FormItem>
<mx:FormItem label="Protocol:">
<mx:Label text="{protocol}"/>
</mx:FormItem>
<mx:FormItem label="Port:">
<mx:Label text="{port}"/>
</mx:FormItem>
<mx:FormItem label="Server name:">
<mx:Label text="{serverName}"/>
</mx:FormItem>
<mx:FormItem label="Is secure?:">
<mx:Label text="{isSecure}"/>
</mx:FormItem>
<mx:FormItem label="Previous URL:">
<mx:Label text="{previousURL}"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
History management is automatically supported by the Accordion and TabNavigator navigator containers. You
can also use the HistoryManager class in ActionScript to provide custom history management for other objects
in an application. History management is disabled by default for the ViewStack navigator container.
When history management is enabled, as the user navigates within different navigator containers in an appli-
cation, each navigation state is saved. Selecting the web browser’s Back or Forward button displays the previous
or next navigation state that was saved. History management keeps track of where you are in an application, but
it is not an undo and redo feature that remembers what you have done.
Note: When history management is enabled for a particular component, such as a navigator container, only the state
of the navigator container is saved. The state of any of the navigator container’s child components is not saved unless
history management is specifically added for that component.
<mx:Script><![CDATA[
import mx.managers.HistoryManager;
if (newState != selected) {
selected = newState;
} else {
if (newState) {
selected = false;
} else {
selected = true;
}
}
}
</mx:CheckBox>
The application that uses this control might look like the following (if the MXML files are in the same directory):
<?xml version="1.0"?>
<!-- historymanager/CheckBoxApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*">
<local:MyCheckBox/>
</mx:Application>
When the user checks and unchecks the custom CheckBox control, they can use the browser’s forward and back
buttons to return to the previous state of the control.
An application’s total navigation state is limited to the maximum URL size supported by the user’s web browser,
so you should write the saveState() method for a component to save the least amount of data possible. For
example, you can write a saveState() method for a List control that saves just the selectedIndex property.
change="listChanged()"
implements="mx.managers.IHistoryManagerClient"
>
<mx:Script><![CDATA[
import mx.managers.HistoryManager;
<mx:Script>
<![CDATA[
[Bindable]
private var listData:Array = ["Flex", "Dreamweaver",
"Flash", "Breeze", "Contribute"];
]]>
</mx:Script>
<mx:TextInput id="text1"
text="{list1.selectedItem? list1.selectedItem : ''}"/>
</mx:Application>
In this example, you populate the HistoryList control with an Array of Strings. As you select an item in the Histo-
ryList control, it also appears in the TextInput control. Use the browser’s back button to cycle back through your
selections.
ADOBE FLEX 3 1093
Adobe Flex 3 Developer Guide
Method Description
HistoryManager.register(myList);
save() Saves the current navigation state of all components registered with the HistoryManager class; for
example:
HistoryManager.save();
HistoryManager.unregister(myList);
1094 CHAPTER 34
1095
Topics
About shared objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1095
Creating a shared object. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096
Destroying shared objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1102
SharedObject example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1102
Method Description
clear() Purges all of the data from the SharedObject object, and deletes the SharedObject file from the disk.
getLocal() Returns a reference to the client’s domain-specific, local SharedObject object. If none exists, this method creates a
new shared object on the client.
getSize() Gets the size of the SharedObject file, in bytes. The default size limit is 100 KB, although it can be larger if the client
allows it.
Property Description
data Read-only property that represents the collection of attributes the shared object stores.
onStatus The shared object’s event handler that is invoked for every warning, error, or informational note.
When you create a shared object, Flash Player creates a new directory for the application and domain. It also
creates an empty *.sol file that stores the SharedObject data. The default location of this file is a subdirectory of
the user’s home directory. The following table shows the default locations of this directory:
Linux/Unix /home/username/.macromedia/Flash_Player/#SharedObjects
For example, if you request an application named MyApp.mxml on the local host, in the Flex context, and within
a subdirectory named /sos, Flash Player stores the *.sol file in the following location on Windows:
c:/Documents and Settings/fred/localhost/Application Data/Macromedia/Flash
Player/#localhost/flex/sos/MyApp.mxml.swf/data.sol
Note: If you do not provide a name in the SharedObject.getLocal() method, Flash Player names the file
undefined.sol.
Although usually predictable, the location of the SharedObject file can be anywhere that Flash Player has access
to within its sandbox and can have any name that Flash Player assigns to it.
By default, Flash can save locally persistent SharedObject objects of up to 100 KB per domain. When the appli-
cation tries to save data to a shared object that would make it bigger than 100 KB, Flash Player displays the Local
Storage dialog box, which lets the user allow or deny local storage for the domain that is requesting access.
Specifying a path
You can use the optional pathname parameter to specify a location for the SharedObject file. This file must be a
subdirectory of that domain’s SharedObject directory. For example, if you request an application on the localhost
and specify the following:
mySO = SharedObject.getLocal("myObjectFile","/");
Flash Player writes the SharedObject file in the /#localhost directory (or /localhost if the application is offline).
This is useful if you want more than one application on the client to be able to access the same shared object. In
this case, the client could run two Flex applications, both of which specify a path to the shared object that is the
root of the domain; the client could then access the same shared object from both applications. To share data
between more than application without persistence, you can use the LocalConnection object.
1098 CHAPTER 35
If you specify a directory that does not exist, Flash Player does not create a SharedObject file.
}
The following Flex application creates an instance of the ActionScript class for each of the types of shared objects
it needs. It then calls methods on that class when the user adds or removes blogs or site URLs.
<?xml version="1.0"?>
<!-- lsos/BlogAggregator.mxml -->
<mx:Application
xmlns:local="*"
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp()"
backgroundColor="#ffffff"
>
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.utils.ObjectUtil;
import flash.net.SharedObject;
[Bindable]
public var welcomeMessage:String;
[Bindable]
public var localFeeds:ArrayCollection = new ArrayCollection();
[Bindable]
public var localSites:ArrayCollection = new ArrayCollection();
if (lsofeeds.getObjects()) {
localFeeds = lsofeeds.getObjects();
}
if (lsosites.getObjects()) {
localSites = lsosites.getObjects();
}
}
]]>
</mx:Script>
<mx:Panel title="Blogs">
<mx:Form id="blogForm">
<mx:HBox>
<mx:FormItem label="Name:">
ADOBE FLEX 3 1101
Adobe Flex 3 Developer Guide
</mx:Application>
SharedObject example
The following example shows that you can store simple objects, such as a Date object, in a SharedObject object
without having to manually serialize and deserialize those objects.
The following example begins by welcoming you as a first-time visitor. When you click Log Out, the application
stores the current date in a shared object. The next time you launch this application or refresh the page, the appli-
cation welcomes you back with a reminder of the time you logged out.
To see the application in action, launch the application, click Log Out, and then refresh the page. The application
displays the date and time that you clicked the Log Out button on your previous visit. At any time, you can delete
the stored information by clicking the Delete LSO button.
<?xml version="1.0"?>
<!-- lsos/WelcomeMessage.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="initApp()">
<mx:Script><![CDATA[
public var mySO:SharedObject;
[Bindable]
public var welcomeMessage:String;
]]></mx:Script>
<mx:Label id="label1" text="{welcomeMessage}"/>
<mx:Button label="Log Out" click="storeDate()"/>
<mx:Button label="Delete LSO" click="deleteLSO()"/>
</mx:Application>
For more examples of using shared objects, see the Flex example applications in the samples.war file.
1104 CHAPTER 35
1105
Topics
Introduction to localization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1105
Creating resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1107
Using resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1113
Using resource modules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123
Creating resource bundles at run time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1131
Formatting dates, times, and currencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1138
Adding styles and fonts to localized resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1140
Editing framework resource properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1142
Introduction to localization
Localization is the process of including assets to support multiple locales. A locale is the combination of a language
and a country code; for example, en_US refers to the English language as spoken in the United States, and fr_FR
refers to the French language as spoken in France. To localize an application, you would provide two sets of assets,
one for the en_US locale and one for the fr_FR locale.
Locales can share languages. For example, en_US and en_GB (Great Britain) are different locales and therefore
use different sets of assets. In this case, both locales use the English language, but the country code indicates that
they are different locales, and might therefor use different assets. For example, an application in the en_US locale
might spell the word "color", whereas the word would be "colour" in the en_GB locale. Also, units of currency
would be represented in dollars or pounds, depending on the locale, and the format of dates and times might also
be different.
Localization goes beyond just translating Strings used in your application. It can also include any type of asset such
as audio files, images, and videos. Because the meanings of colors and images can vary based on the culture, you
can change the styles used by your application, in addition to the language used, based on the locale.
1106 CHAPTER 36
Choosing a locale
To determine which locale your users will want to experience your application in, you can use one of the following
methods:
• User prompt — You can start the application in some default locale, and then ask the user to choose their
preferred locale.
• Capabilities.language — The Capabilities.language property in ActionScript provides the language
code for Adobe® Flash® Player and Adobe AIR™. On English systems, this property returns only the language code,
not the country code. This property returns the user interface language, which refers to the language used for all
menus, dialog boxes, error messages, and help files in Flash Player and AIR.
• Accept-Language header — When a browser makes an HTTP request, it send a list of languages to the server
in the Accept-Language header. You can parse this header in your HTML wrapper and pass it as a flashVars
variable into your Flex application. If you use URLLoader to load an application, you will not have access to this
header.
ADOBE FLEX 3 1107
Adobe Flex 3 Developer Guide
• Browser and OS language settings — You can access the browser’s or operating system’s language settings in
the HTML wrapper by using JavaScript. You can then pass the values as flashVars variables to your application.
You can also use the ExternalInterface API to access the values from within your Flex application. The language
is typically accessible via the Navigator object’s language property. Depending on the browser, you also access the
userLanguage or systemLanguage properties. For more information on using the ExternalInterface API, see
“Using the ExternalInterface API to access JavaScript from Flex” on page 1047.
Creating resources
You define localization resources in properties files. These properties files contain key/value pairs and are in UTF-
8 format. You typically use these properties files to specify the values of Strings in your applications, such as the
label on a button or the items in a drop down list. The following example specifies the values for a form’s labels in
English:
# locale/en_US/RegistrationForm.properties
registration_title=Registration
submit_button=Submit Form
personname=Name
street_address=Street Address
city=City
state=State
zip=ZIP Code
thanks=Thank you for registering!
Resources can also reference binary assets such as audio files, video files, SWF files, and images. To reference these
assets in your properties files, you use the Embed() directive, just as you would include assets in a runtime style
sheet. The following example embeds a JPG file as a resource:
flag=Embed("images/unitedstates.jpg")
You can also extract symbols from an embedded SWF file when using the Embed() directive, as the following
example shows:
flag=Embed(source="FlagsOfTheWorld.swf", symbol="unitedstates")
To include custom classes, such as a programmatic skin, you can use the ClassReference() directive. The
following example embeds the Sorter class in the sortingClasses.en_US package:
SORTER=ClassReference("sortingClasses.en_US.Sorter")
For information on how to use these various types of resources in your application, see “Using resources” on
page 1113.
1108 CHAPTER 36
You typically store resource properties files in the locale/locale_name subdirectory. You add this directory to your
source path so that the compiler can find it when you compile your application. For information on how to
compile resources into your Flex application, see “Compiling resources into Flex applications” on page 1108.
4 Navigate to the resource properties files’ parent directory. Typically, you have locales in parallel directories
under a parent directory such as /loc or /locale. For the en_US locale, you might have c:/myapp/loc/en_US
directory. You will want to generalize the source path entry so that all locales are included. In this case, append
{locale} to the end of the directory path. For example:
c:/myapp/loc/{locale}
This instructs the compiler to include all directories that match the {locale} token. In this case, en_US. If
you add other locales, you only need to add them to the locale option and not the source path, as long as the
new locale’s resources are parallel to the existing locale’s resources. For more information, see “Adding new
locales” on page 1110.
5 Click OK to add this directory to your project’s source path.
You then add the locale and allow-source-path-overlap options to the Additional Compiler Arguments
field on the Flex Compiler pane in the project’s properties, as the following example shows:
-locale=en_US -allow-source-path-overlap=true
The locale option instructs the compiler which resource properties files to convert into resource bundles. By
default, the en_US locale is supported. If you want to use other locales, you must also generate the framework
resource bundles for those locales and that those locale’s to the locale option. For more information, see “Adding
new locales” on page 1110.
The value of the locale option (in this case, en_US) is also used by the library-path option. If you specify
multiple locales or change the locale, you will not be required to also change the library path.
The allow-source-path-overlap option lets you avoid a warning that the MXML compiler generates. You
typically create a new subdirectory named locale under your project and then a subdirectory under that for each
locale. You must explicitly add the locale directory to your source path. The directory where the application’s
MXML file is located is implicitly added to the source path. In the default Flex Builder project layout, this folder
is the project directory and it is therefore the parent of the locale directory. By settings this option to true, you
instruct the compiler not to warn you about overlapping values in the source path.
You can specify the locales in the flex-config.xml file by using the <locale> tag, as the following example shows:
<locale>
<localeElement>en_US</localeElement>
</locale>
To add entries to your source path in the configuration file, you use the <source-path> child tag, as the following
example shows:
<source-path>
<path-element>locale/{locale}</path-element>
</source-path>
The <source-path> tag is commented out by default, so you must first uncomment the tag block.
1110 CHAPTER 36
<locale>
<locale-element>en_US</locale-element>
<locale-element>es_ES</locale-element>
</locale>
2 Ensure that the new locale’s resource properties files are in the source path. The source path entry for localized
resources typically uses the {locale} token so that all new locales are automatically added to the source path, as
long as those locales’ resource directories have the same parent directory.
3 Create the framework resource bundles for the new locale.
The locale option defines what locales to include on the source path. It also instructs the compiler to include the
localized framework resources for the specified locales. Framework components such as Label and Button use
resources, just like your application and custom components can use resources. The resources required by these
classes are located in the libraries like framework.swc or in separate resource bundle libraries. By default,
framework resources for the en_US locale are included in the Flex SDK. If you add a locale to your Flex appli-
cation, you must generate the framework resources for that locale.
To use the en_US locale, you do not need to do anything other than create properties files for your locale. For all
other locales, such as ja_JP, fr_FR, or es_ES, in addition to creating the new properties files, you must also create
new framework locale files before compiling your Flex application.
Typically, you begin adding a new locale by creating a new resource properties file. The following example
specifies the values for a registration form’s labels in Spanish:
# locale/es_ES/RegistrationForm.properties
registration_title=Registro
submit_button=Someta La Forma
personname=Nombre
street_address=Dirección De la Calle
city=Ciudad
state=Estado
zip=Código postal
thanks=¡Gracias por colocarse!
You create a separate properties files for each locale, and store it in a new directory under the locale directory in
your project. You name the directory the same as the new locale. For example, if the locale is es_ES, then you store
the new resources properties file in the locale/es_ES directory. If you have not already specified a source path, you
add this resource directory to the source path as described in “Compiling resources into Flex applications” on
page 1108.
When adding other locales, you must also include the framework resources for that locale. The en_US locale is
already provided. For all other locales, you must create the framework resources. To create a locale’s framework
resources, use the copylocale utility in the /sdk/bin directory. For Flex Builder, the copylocale utility is located in
flex_builder_install/sdks/3.0.0/bin. You can only execute this utility from the command line.
The syntax for the copylocale utility is as follows:
copylocale original_locale new_locale
1112 CHAPTER 36
For example, to create the framework locale files for the es_ES locale, use the following command:
copylocale en_US es_ES
This utility creates a new directory under frameworks/locale/locale_name. The name of this directory matches the
name of the new locale. This directory is parallel to the en_US directory. In this example, it creates the
locale/es_ES directory. This utility also creates the following SWC files in the new directory:
• airframework_rb.swc
• framework_rb.swc
• rpc_rb.swc
These resources must be in the library path. By default, the locale/{locale} entry is already set for your
library-path compiler option, so you do not need to change any configuration options.
When you compile your application, and add the new locale to the locale option, the compiler includes the
localized framework resources in the SWC files for that new locale.
}
}
To view the generated classes, you can set the keep-generated-actionscript compiler option to true when
you compile your application with an existing resource properties file.
You can write your own classes that extend the ResourceBundle class rather than create resource properties files
that the compiler then uses to generate the resource bundle classes. You can then use those classes if you include
them in your project. For more information, see “Creating resource bundles at run time” on page 1131.
Using resources
After you create a resource properties file, you can use it in your Flex application as a resource bundle (the
compiler converts properties files to subclasses of the ResourceBundle class when you compile your application).
You can either bind values from the resource to an expression, or you can use methods of the ResourceBundle
class to access those values.
There are two methods of accessing the values in resource bundles:
• @Resource directive
• Methods of the ResourceManager class
Using the @Resource directive to include resource bundles in your application is the simplest method. In the
directive, you specify the name of the properties file and the key that you want to use. This method is simple to
use, but is also restrictive in how it can be used. For example, you can only use the @Resource directive in MXML
and you cannot change locales at run time. In addition, this directive only returns Strings.
The other way to access resource bundles is through the ResourceManager class. You can use the methods of the
ResourceManager class in ActionScript, whereas you can only use the @Resource directive in MXML. These
methods can return data types other than Strings, such as ints, Booleans, and Numbers. You can also use this class
to switch locales at run time, so if you compiled multiple locales into the same application, you can change from
one locale to the other.
The following sections describe how to use the @Resource directive and the ResourceManager class to access
resource bundles in your Flex application.
1114 CHAPTER 36
flag=Embed("images/unitedstates.gif")
The location of the image is relative to the location of the properties file. In this case, the images directory is under
locale/en_US.
In your application, you use the @Resource directive anywhere a String might supply the location of the image.
The following example uses the image as a source for the <mx:Image> tag:
<?xml version="1.0"?>
<!-- l10n/LocalizedFormResourceWithImage.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Form>
<mx:FormItem label="@Resource(key='personname', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='street_address', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='city', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='state', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='zip', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
</mx:Application>
For multiple resource bundles, add each one on a separate line inside the same <mx:Metadata> tag, as the
following example shows:
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
[ResourceBundle("StyleProperties")]
[ResourceBundle("FormatterProperties")]
</mx:Metadata>
On an ActionScript class, you apply the metadata above the class name, as the following example shows:
[ResourceBundle("RegistrationForm")]
public class MyComponent extends UIComponent {
...
}
You can also bind expressions to the ResourceManager. These expressions are updated any time the locale
changes.
The following example uses ActionScript to set the value of the Alert message, and binds the labels in the form to
resources by using the ResourceManager’s getString() method.
<?xml version="1.0"?>
<!-- l10n/LocalizedFormWithBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.resources.ResourceBundle;
import mx.controls.Alert;
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
</mx:Metadata>
<mx:Form>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem
label="{resourceManager.getString('RegistrationForm','street_address')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
ADOBE FLEX 3 1117
Adobe Flex 3 Developer Guide
<mx:Button id="b1"
label="{resourceManager.getString('RegistrationForm','submit_button')}"
click="registrationComplete()"/>
</mx:Application>
To use a binary asset such as an image with the ResourceManager, you embed the image in the resource properties
file. You can then use the asset anywhere that you might use an embedded image. To embed an image in the
properties file, you use the Embed directive in your properties file, as the following example shows:
flag=Embed("images/unitedstates.gif")
The location of the image is relative to the location of the properties file. In this case, the images directory is under
locale/en_US.
To use the image in your application, you use the ResourceManager’s getClass() method. The following
example uses the GIF file as both a skin for the Button control and a source for the <mx:Image> tag:
<?xml version="1.0"?>
<!-- l10n/LocalizedFormBindingWithImages.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.resources.ResourceBundle;
import mx.controls.Alert;
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
</mx:Metadata>
<mx:Form>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem
label="{resourceManager.getString('RegistrationForm','street_address')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
<mx:TextInput/>
</mx:FormItem>
1118 CHAPTER 36
</mx:Form>
<mx:Button id="b1"
label="{resourceManager.getString('RegistrationForm','submit_button')}"
click="registrationComplete()"/>
</mx:Application>
To use a class, such as a programmatic skin, as a resource, you use the ClassReference() directive in your
properties file. The following example embeds the MyCheckBoxIcon_en_US class in the properties file:
CHECKBOXSKIN=ClassReference("MyCheckBoxIcon_en_US")
You can bind the value of the getClass() method for programmatic skins, as the following example shows:
<mx:CheckBox selected="true"
selectedUpIcon="{resourceManager.getClass('bundle1','CHECKBOXSKIN')}"
selectedDownIcon="{resourceManager.getClass('bundle1','CHECKBOXSKIN')}"
selectedOverIcon="{resourceManager.getClass('bundle1','CHECKBOXSKIN')}"
/>
For more information about the ResourceManager, see “About the ResourceManager” on page 1122.
Before compiling additional locales into an application, you must generate the framework resources for that
locale, if they are not already created. You do this with the copylocale command-line utility. For more information,
see “Adding new locales” on page 1110.
The order of the locales on the command line can be important. The application defaults to the first locale in the
list if you do not specifically set the value of the ResourceManager’s localeChain property when the application
initializes.
The following example lets you select a new locale from the ComboBox control. When you change that value, the
application updates the localeChain property. The application’s locale-specific assets, such as the form labels,
flag image, and alert message should change to the new locale.
<?xml version="1.0"?>
<!-- l10n/BasicLocaleChain.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.resources.ResourceBundle;
import mx.controls.Alert;
[Bindable]
private var locales:Array = [ "es_ES","en_US" ];
// This style is not bound to the resource bundle, so it must be reset when
// the new locale is selected.
b1.setStyle("downSkin", resourceManager.getClass("RegistrationForm", "flag"));
}
]]></mx:Script>
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
</mx:Metadata>
<mx:Image source="{resourceManager.getClass('RegistrationForm', 'flag')}"/>
<mx:ComboBox id="localeComboBox"
dataProvider="{locales}"
change="comboChangeHandler()"
/>
1120 CHAPTER 36
<mx:Form>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem
label="{resourceManager.getString('RegistrationForm','street_address')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:Button id="b1"
label="{resourceManager.getString('RegistrationForm','submit_button')}"
click="registrationComplete()"/>
</mx:Application>
When you compile this example application, you must add both locales to the locale option, as the following list
of compiler options shows:
-locale=en_US,es_ES -allow-source-path-overlap=true -source-path=locale/{locale}
Because this application uses multiple locales, you must prepare properties files for each one. You should have the
following files in your project to use this example:
/main/BasicLocaleChain.mxml
/main/locale/en_US/RegistrationForm.properties
/main/locale/en_US/images/unitedstates.gif
/main/locale/es_ES/RegistrationForm.properties
/main/locale/es_ES/images/spain.gif
The contents of the properties files for this example should be similar to the following:
# /locale/en_US/RegistrationForm.properties
registration_title=Registration
submit_button=Submit Form
personname=Name
street_address=Street Address
city=City
state=State
zip=ZIP Code
thanks=Thank you for registering!
flag=Embed("images/unitedstates.gif")
# /locale/es_ES/RegistrationForm.properties
registration_title=Registro
submit_button=Someta La Forma
personname=Nombre
street_address=Dirección De la Calle
city=Ciudad
state=Estado
ADOBE FLEX 3 1121
Adobe Flex 3 Developer Guide
zip=Código postal
thanks=¡Gracias por colocarse!
flag=Embed("images/spain.gif")
If you do not bind the properties in your application to your resources, then those values are not updated when
the locale changes.
When you compile an application for multiple locales, the ResourceManager's localeChain property is
initialized to the locales specified by the locale compiler option. For example, if the locale option is -
locale=en_US,es_ES, the application defaults to the English resources because en_US is listed first. You can
override this default initial value at run time by specifying the value of the localeChain as an application
parameter in the flashVars variable in the HTML template.
If you write your own HTML template, you can pass variables as flashVars properties in the <object> and
<embed> tags. The following example specifies that the es_ES locale is the first in the localeChain property’s
Array:
<object id=’mySwf’
classid=’clsid:D27CDB6E-AE6D-11cf-96B8-444553540000’
codebase=’http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab’
height=’100%’
width=’100%’>
<param name=’src’ value=’BasicLocaleChain.swf’/>
<param name=’flashVars’ value=’localeChain=es_ES,en_US’/>
<embed name=’mySwf’
src=’FlashVarTest.swf’
pluginspage=’http://www.adobe.com/go/getflashplayer’
height=’100%’
width=’100%’
flashVars=’localeChain=es_ES’
/>
>
If you are using the Flex SDK templates provided in the /templates directory, pass the flashVars property to the
AC_FL_RunContent() JavaScript method, as the following example shows:
AC_FL_RunContent(
"src", "BasicLocaleChain",
"flashVars", "localeChain=es_ES,en_US",
"width", "500",
"height", "500",
"align", "middle",
"id", "BasicLocaleChain",
"name", "BasicLocaleChain",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer"
);
This initializes the value of the localeChain property to ["es_ES", "en_US"].
1122 CHAPTER 36
When using the resource-bundle-list option, you must also set the value of the locale option to an empty
string.
The following command-line example generates a resource bundle list for the application MyApp:
mxmlc -locale= -resource-bundle-list=myresources.txt MyApp.mxml
In this example, the compiler writes a file called myresources.txt. This file contains a list similar to the following:
bundles = RegistrationForm collections containers controls core effects skins styles
In Flex Builder, you add the locale and resource-bundle-list options to the Additional Compiler Arguments
field on the Flex Compiler pane in the project’s properties. On Windows, the output file’s location is relative to the
Flex Builder directory, not the project’s directory. You can specify an absolute path instead. On Macintosh, the
option must be an absolute path.
If you use custom resource bundles, those will be included in this list. In this example, the name of the resource
properties file is RegistrationForm. The others are bundles containing framework resources.
You use this list to instruct the compiler which resource bundles to include when you compile a resource module.
You should use a common naming convention for all of your locales’ resource modules. For example, specify the
locale in the SWF file’s name, but keep the rest of the file name the same for all locales. This is because when you
load the resource module, you want to be able to dynamically determine which SWF file to load. In the previous
example, the resource module for the en_US locale is named en_US_ResourceModule.swf. If you then generated
a resource module for the es_ES locale, it would be named es_ES_ResourceModule.swf.
import mx.events.ResourceEvent;
[Bindable]
private var locales:Array = [ "es_ES","en_US" ];
// Ensure that you are not loading the same resource module more than once.
if (resourceManager.getLocales().indexOf(newLocale) != -1) {
completeHandler(null);
} else {
// Build the file name of the resource module.
var resourceModuleURL:String = newLocale + "_ResourceModule.swf";
var eventDispatcher:IEventDispatcher =
resourceManager.loadResourceModule(resourceModuleURL);
eventDispatcher.addEventListener(ResourceEvent.COMPLETE, completeHandler);
}
}
// This style is not bound to the resource bundle, so it must be reset when
// the new locale is selected.
b1.setStyle("downSkin", resourceManager.getClass("RegistrationForm", "flag"));
}
]]></mx:Script>
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
</mx:Metadata>
<mx:ComboBox id="localeComboBox"
prompt="Select One..."
dataProvider="{locales}"
change="comboChangeHandler()"
/>
<mx:Form>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem
label="{resourceManager.getString('RegistrationForm','street_address')}">
<mx:TextInput/>
ADOBE FLEX 3 1127
Adobe Flex 3 Developer Guide
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:Button id="b1"
label="{resourceManager.getString('RegistrationForm','submit_button')}"
click="registrationComplete()"/>
</mx:Application>
To compile an application that uses only resource modules, do not specify any locales to be compiled into the
application. You do this by setting the value of the locale option to an empty String. For example, on the
command line, you can compile an application named MyApp.mxml with the following command:
mxmlc -locale= MyApp.mxml
In Flex Builder, you add the following option to the Additional Compiler Arguments field on the Flex Compiler
pane in the project’s properties:
-locale=
If you compile an application that uses both compiled-in resources and resource modules, then you specify the
locale(s) for the compiled-in resources with the locale option.
You should try to avoid loading the same resource module more than once in the application. To do this, you can
use the ResourceManager’s getLocales() method. This method returns an Array of locales. You can compare
this list against the resource module’s locale that you are about to load.
You can find out which resource bundles exist for a specified locale by using the getBundleNamesForLocale()
method.
You can get a reference to a particular locale’s resource bundle by calling the getResourceBundle() method.
Once you have a reference to a ResourceBundle, you can use a for-in loop to iterate over its content object. For
more information, see “Enumerating resources” on page 1137.
Also, to use a remote resource module, you must compile the loading application with network access (have the
use-network compiler option set to true, the default). If you compile and run the application on a local file
system, you might not be able to load a remotely accessible SWF file.
resourceModuleURLs A comma-separated list of URLs from which resource modules will be sequentially preloaded.
Resource modules are loaded by the same class as RSLs, but are loaded after the RSLs.
As with URL parameters, you must separate these values with an ampersand (&). You must also ensure that the
values are URL encoded.
ADOBE FLEX 3 1129
Adobe Flex 3 Developer Guide
If you write your own HTML template, you can pass variables as flashVars properties in the <object> and
<embed> tags. The following example specifies that the es_ES locale’s resource module is preloaded when the
application launches:
<object id=’mySwf’
classid=’clsid:D27CDB6E-AE6D-11cf-96B8-444553540000’
codebase=’http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab’
height=’100%’
width=’100%’>
<param name=’src’ value=’ResourceModuleApp.swf’/>
<param name=’flashVars’
value=’resourceModuleURLs=es_ES_ResourceModule.swf&localeChain=es_ES’/>
<embed name=’mySwf’
src=’ResourceModuleApp.swf’
pluginspage=’http://www.adobe.com/go/getflashplayer’
height=’100%’
width=’100%’
flashVars=’resourceModuleURLs=es_ES_ResourceModule.swf&localeChain=es_ES’
/>
>
If you are using the templates provided in the /templates directory, pass the flashVars property to the
AC_FL_RunContent() JavaScript method, as the following example shows:
AC_FL_RunContent(
"src", "ResourceModuleApp",
"flashVars", "resourceModuleURLs=es_ES_ResourceModule.swf&localeChain=es_ES",
"width", "500",
"height", "500",
"align", "middle",
"id", "ResourceModuleApp",
"name", "ResourceModuleApp",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer"
);
If you use the addResourceBundle() method to add another bundle with the same locale and bundle name, the
new one will overwrite the old one. However, creating new bundle values does not update the application. You
must also call the ResourceManager’s update() method to update existing resource bundles.
The following example replaces some of the existing resources in the en_US locale’s RegistrationForm resource
bundle with new values.
<?xml version="1.0"?>
<!-- l10n/CreateReplacementBundle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.resources.ResourceBundle;
import mx.controls.Alert;
[Bindable]
private var locales:Array = [ "es_ES","en_US" ];
resourceManager.addResourceBundle(newRB);
resourceManager.update();
}
]]></mx:Script>
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
</mx:Metadata>
<mx:ComboBox id="localeComboBox"
1132 CHAPTER 36
dataProvider="{locales}"
change="comboChangeHandler()"
/>
<mx:Form>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem
label="{resourceManager.getString('RegistrationForm','street_address')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:Button id="b1"
label="{resourceManager.getString('RegistrationForm','submit_button')}"
click="registrationComplete()"/>
</mx:Application>
You can also programmatically create a new locale and new resource bundles for that locale. However, you should
only create a new locale programmatically if you compiled with that locale’s framework resources, as described in
“Adding new locales” on page 1110.
If you programmatically create your own bundles for a new locale but do not create any framework bundles for
that locale prior to compiling the application, you will get run-time exceptions when the framework components
try to access framework bundles for the new locale. For example, suppose you programmatically create bundles
for the fr_FR locale but do not compile with the fr_FR framework bundles. If you then set the localeChain
property to ["fr_FR"], you will get run-time exceptions when the framework components try to access
framework resources for the fr_FR locale. As a result, if you plan on creating bundles for the fr_FR locale at run
time, you should compile the application with the fr_FR framework bundles. You can then set the localeChain
property to ["fr_FR"] without getting run-time errors.
When programmatically creating bundles, you cannot put the class of a run-time loaded image into the bundle
because its class did not exist at compile time. Classes representing images are created only at compile time, for
embedded images. As a result, you should explicitly set the source of an image rather than get the source of that
image from a resource bundle.
ADOBE FLEX 3 1133
Adobe Flex 3 Developer Guide
The following example creates a new bundle for the fr_FR locale at run time. It explicitly assigns the source of the
image when the fr_FR locale is selected rather than loading it from the resource bundle because the image’s class
was not available at compile time.
<?xml version="1.0"?>
<!-- l10n/CreateNewLocaleAndBundle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script><![CDATA[
import mx.resources.ResourceBundle;
import mx.controls.Alert;
import flash.display.*;
[Bindable]
private var locales:Array;
updateFlag();
}
updateFlag();
}
updateFlag();
resourceManager.addResourceBundle(newRB);
resourceManager.update();
}
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
</mx:Metadata>
<mx:Image id="flagImage"/>
<mx:ComboBox id="localeComboBox"
dataProvider="{locales}"
change="comboChangeHandler()"
/>
<mx:Form>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','personname')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem
label="{resourceManager.getString('RegistrationForm','street_address')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','city')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','state')}">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('RegistrationForm','zip')}">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:Button id="b1"
label="{resourceManager.getString('RegistrationForm','submit_button')}"
click="registrationComplete()"
/>
<mx:HBox>
<mx:Button id="b2" label="Add New Bundle" click="createNewBundle();"/>
<mx:Button id="b3" label="Reset" click="resetApp();"/>
</mx:HBox>
</mx:Application>
Enumerating resources
You can enumerate all resources in a resource bundle by using a for in loop ActionScript. To do this, you get a
reference to the resource bundle, and then loop over the content object.
Methods that you might use when enumerating resources include getLocales(),
getBundleNamesForLocale(), and getResourceBundle().
The getLocales() method returns an Array such as ["en_US", "ja_JP"] which contains, in no particular
order, all of the locales for bundles that exist in the ResourceManager. The getBundleNamesForLocale()
method returns an Array such as ["controls", "containers"] which contains all of the bundle names for the
specified locale. The getResourceBundle() method takes a locale and a bundle name and returns a reference to
the specified resource bundle.
The following example prints the keys and values for all resource bundles in all locales in the ResourceManager.
This includes the framework bundles for the locales, in addition to any custom resources such as Registra-
tionForm.properties.
<?xml version="1.0"?>
<!-- l10n/EnumerateAllBundles.mxml -->
1136 CHAPTER 36
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="enumerateBundles()">
<mx:Script><![CDATA[
import mx.resources.ResourceBundle;
import mx.controls.Alert;
<mx:Metadata>
[ResourceBundle("RegistrationForm")]
</mx:Metadata>
<mx:Form>
<mx:FormItem label="@Resource(key='personname', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='street_address', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='city', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='state', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='zip', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
<mx:Button id="b1" label="@Resource(key='submit_button', bundle='RegistrationForm')"
click="registrationComplete()"/>
[Bindable]
private var locales:Array = [ "es_ES","en_US" ];
[Bindable]
private var dateValue:String;
[Bindable]
private var timeValue:String;
[Bindable]
private var currencyValue:String;
localeComboBox.selectedIndex = locales.indexOf(resourceManager.localeChain[0]);
applyFormats(e);
// Updating the localeChain does not reapply formatters. As a result, you must
// apply them whenever the ResourceManager's change event is triggered.
resourceManager.addEventListener(Event.CHANGE, applyFormats);
}
<mx:Metadata>
[ResourceBundle("FormattingValues")]
</mx:Metadata>
<mx:ComboBox id="localeComboBox"
dataProvider="{locales}"
change="comboChangeHandler()"
/>
<mx:DateFormatter id="dateFormatter"
formatString="{resourceManager.getString('FormattingValues', 'DATE_FORMAT')}"
/>
<mx:DateFormatter id="timeFormatter"
formatString="{resourceManager.getString('FormattingValues', 'TIME_FORMAT')}"
/>
<mx:CurrencyFormatter id="currencyFormatter"
precision="{resourceManager.getInt('FormattingValues', 'CURRENCY_PRECISION')}"
currencySymbol="{resourceManager.getString('FormattingValues',
'CURRENCY_SYMBOL')}"
thousandsSeparatorTo="{resourceManager.getString('FormattingValues',
'THOUSANDS_SEPARATOR')}"
decimalSeparatorTo="{resourceManager.getString('FormattingValues',
'DECIMAL_SEPARATOR')}"
/>
<mx:Form>
<mx:FormItem label="Date">
<mx:TextInput id="ti1" text="{dateValue}"/>
</mx:FormItem>
<mx:FormItem label="Time">
<mx:TextInput text="{timeValue}"/>
</mx:FormItem>
<mx:FormItem label="Currency">
<mx:TextInput text="{currencyValue}"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
ADOBE FLEX 3 1139
Adobe Flex 3 Developer Guide
Topics
Accessibility overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1143
About screen reader technology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1145
Configuring Flex applications for accessibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1146
Accessible components and containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1147
Creating tab order and reading order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1154
Creating accessibility with ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1157
Accessibility for hearing-impaired users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1158
Testing accessible content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1158
Accessibility overview
You create accessible content by using accessibility features included with Flex, by taking advantage of Action-
Script designed to implement accessibility, and by following recommended design and development practices.
Visually impaired users, for example, might rely on assistive technology such as screen readers, which provide an
audio version of screen content, or screen magnifiers, which display a small portion of the screen at a larger size,
effectively reducing the visible screen area. Hearing-impaired users might read text and captions in the document
in place of audio content. Other considerations arise for users with mobility or cognitive impairments.
The following list of recommended practices is not exhaustive, but suggests common issues to consider.
Depending on your audience’s needs, additional requirements may arise.
Visually impaired users For visually impaired users, keep in mind the following design recommendations:
• Design and implement a logical tab order for the tabs.
• Design the document so that constant changes in content do not unnecessarily cause screen readers to refresh.
For example, you should group or hide looping elements.
1144 CHAPTER 37
• Provide captions for narrative audio. Be aware of audio in your document that might interfere with a user
being able to listen to the screen reader.
• Use percentage sizing so that your applications scale properly at smaller screen sizes. This allows users of
screen magnifiers to see more of your application at one time. Also take into account that many visually impaired
users run applications with lower screen resolutions than other users.
• Ensure that foreground and background colors contrast sufficiently to make text readable for people with low
vision.
• Ensure that controls don’t depend on the use of a specific pointer device, such as a mouse or trackball.
• Ensure that components are accessible by keyboard. All Flex components defined as accessible include
keyboard navigation. For a list of these components and the available keyboard commands for each, see “Acces-
sible components and containers” on page 1147.
Color-blind users For color-blind users, ensure that color is not the only means of conveying information.
Users with mobility impairment For users with mobility impairment, keep in mind the following design recom-
mendations:
• Ensure that controls don’t depend on the use of a specific pointer device.
• Ensure that components are accessible by keyboard. All Flex components defined as accessible include
keyboard navigation. For a list of these components and the available keyboard commands for each, see “Acces-
sible components and containers” on page 1147.
Hearing-impaired users For hearing-impaired users, ensure that you add captions to audio content.
Users with cognitive impairment For users with cognitive impairments, such as dyslexia, keep in mind the
following design recommendations:
• Ensure an uncluttered, easy-to-navigate design.
• Provide graphical imagery that helps convey the purpose and message of the application. These graphics
should enhance, not replace, textual or audio content.
• Provide more than one method to accomplish common tasks.
In the United States, the law that governs accessibility is commonly known as Section 508, which is an amendment
to the U.S. Rehabilitation Act. Section 508 prohibits federal agencies from buying, developing, maintaining, or
using electronic technology that is not accessible to those with disabilities. In addition to mandating standards,
Section 508 lets government employees and the public sue agencies in federal court for noncompliance.
For additional information about Section 508, see the U.S. government-sponsored website at www.section508.gov.
To use a JAWS screen reader with a Flex application, users must download a set of scripts before invoking the Flex
application. For more information, see “Configuring a JAWS screen reader for Flex applications” on page 1147.
• Enable accessibility when you are using the mxmlc command-line compiler.
When you compile a file by using the mxmlc command-line compiler, you can use the -accessible option
to enable accessibility, as the following example shows:
mxmlc -accessible c:/dev/myapps/mywar.war/app1.mxml
For more information on the command-line compiler, see “Using the Flex Compilers” on page 125 in Building
and Deploying Adobe Flex 3 Applications.
If you edited the flex-config.xml file to enable accessibility by default, you can disable it for an individual request
by setting the accessible query parameter to false, as the following example shows:
http://www.mycompany.com/myflexapp/app1.mxml?accessible=false
For more information on the command-line compiler, see “Using the Flex Compilers” on page 125 in Building and
Deploying Adobe Flex 3 Applications.
Flex comes with the following set of accessible components and containers.
Accordion container Press the arrow keys to move the focus to a different panel, and then use the Spacebar or Enter key to select
that panel. Use the Page Up and Page Down keys to move between individual panels of the container.
When a screen reader encounters an Accordion container, it indicates each panel with the word tab. It indicates
the current panel with the word active.
For more information on keyboard navigation, see “Accordion container Keyboard navigation” on page 541.
AdvancedDataGrid The AdvancedDataGrid control supports the accessibility features in the DataGrid and Tree controls and
control provides additional features. For more information, see “Accessibility for the AdvancedDataGrid control” on
page 1151.
For more information on standard keyboard navigation, see “Keyboard navigation” on page 320.
Alert control In Forms mode, the text in the Alert control is announced, and the label of its default button.
When not in Forms mode, the text in the Alert control is announced twice when you press the Down Arrow.
Button control Press the Spacebar to activate the Button control. To cancel activating a button, press the Tab key to move the
focus off the Button control before releasing the Spacebar.
When a screen reader encounters a Button control, activation varies, depending on the screen reader. In JAWS
6.10, the Spacebar activates Button controls when Forms mode is active. When Forms mode is inactive, the
Spacebar or Enter key can be used to activate Button controls.
For more information on keyboard navigation, see “Button control user interaction” on page 235.
CheckBox control Press the Spacebar to activate the check box items.
For more information on keyboard navigation, see “CheckBox control user interaction” on page 249.
Open by using Control+Down Arrow, and close by using Control+Up Arrow. When open, you can use the four
arrow keys to move among the colors.
When open, the Enter key sets the color value to the currently selected color, as will Control+Up Arrow.
When open, the Escape key closes the drop-down area and resets the color value to the previously selected
color value.
ComboBox control For more information on keyboard navigation, see “ComboBox control user interaction” on page 393.
ADOBE FLEX 3 1149
Adobe Flex 3 Developer Guide
DataGrid control Press the arrow keys to highlight the contents, and then move between the individual characters within that
field.
When using a screen reader in forms mode, use the Tab key to move between editable TextInput fields in the
DataGrid control.
For more information on keyboard navigation, see “DataGrid control user interaction” on page 404.
DateChooser control Press the Up, Down, Left, and Right Arrow keys to change the selected date. Use the Home key to reach the first
enabled date in the month and the End key to reach the last enabled date in a month. Use the Page Up and
Page Down keys to reach the previous and next months. For more information on keyboard navigation, see
“User interaction” on page 264.
DateField control Use the Control+Down Arrow keys to open the DateChooser control and select the appropriate date. When
using a screen reader in Forms mode, use the same keystrokes as for keyboard navigation.
When a screen reader encounters a DateChooser control in Forms mode, it announces the control as “Drop-
Down Calendar currentDate, to open press ControlDown, ComboBox,” where currentDate is the currently
selected date.
For more information on keyboard navigation, see “User interaction” on page 264.
Form container For information on keyboard navigation, see “Defining a default button” on page 492.
Image control An Image control with a tool tip defined is read by a screen reader only when Forms mode is inactive. The Image
control is not focusable in Forms mode, or by the keyboard.
Label control A Label control is read by a screen reader when it is associated with other controls, or when the Forms mode is
inactive. The Label control is not focusable in Forms mode, or by the keyboard.
LinkButton control LinkButton control activation when using a screen reader varies, depending on the screen reader. In JAWS 6.10,
press the Spacebar to activate a LinkButton control when in Forms mode. When Forms mode is inactive, use the
Spacebar or Enter key to activate the control.
For more information on keyboard navigation, see “LinkButton control user interaction” on page 267.
List control Screen reader navigation is the same as for keyboard navigation.
For more information on keyboard navigation, see “Keyboard navigation” on page 384.
For information on creating data tips (tool tips for individual list elements), see “Displaying DataTips” on
page 377. For information on creating scroll tips (tool tips that provide information while the user scrolls
through a list), see “Displaying ScrollTips” on page 378.
Menu control Screen reader navigation is the same as for keyboard navigation.
For more information on keyboard navigation, see “Menu control user interaction” on page 364.
1150 CHAPTER 37
MenuBar control Screen reader navigation is the same as for keyboard navigation.
For more information on keyboard navigation, see “Menu control user interaction” on page 364.
Panel container Screen reader announces the panel title only when Forms mode is inactive.
RadioButton control With one radio button selected within a group, press the Enter key to enter that group. Use the arrow keys to
move between items in that group. Press the Down and Right Arrow keys to move to the next item in a group;
press the Up and Left Arrow keys to move to a previous item in the group.
When using a screen reader, select a radio button by using the Spacebar key.
For more information on keyboard navigation, see “RadioButton user interaction” on page 251.
RadioButtonGroup Screen reader navigation is the same as for the RadioButton control.
control
Slider control In forms mode the control is announced along with the orientation of the control (left-right or up-down) and
the current value.
TabNavigator When a screen reader encounters a TabNavigator container pane, it indicates each pane with the word tab. It
container indicates the current pane with the word active. When a pane is selected, the user moves to that panel by
pressing the Enter key.
Press the arrow keys to move the focus to a different panel, and then use the Spacebar or Enter key to select
that panel. Use the Page Up and Page Down keys to move between individual panels of the container.
For more information on keyboard navigation, see “TabNavigator container Keyboard navigation” on page 538.
Text control A Text control is not focusable and is read by screen readers only when Forms mode is inactive.
TextArea control Use the Home or Page Down key to move to the beginning of a line. Use the End or Page Up key to move to the
end of a line.
TextInput control Use the Home or Page Down key to move to the beginning of a line. Use the End or Page Up key to move to the
end of a line.
ADOBE FLEX 3 1151
Adobe Flex 3 Developer Guide
TitleWindow container A screen reader announces the TitleWindow control only when Forms mode is inactive.
ToolTipManager When a screen reader is used, the contents of a tool tip are read after the item to which the tool tip is attached
gets focus. Tool tips attached to nonaccessible components (other than the Image control) are not read.
Tree control Press the Up and Down Arrow keys to move between items in a Tree control. To open a group, press the Right
Arrow key or Spacebar. To close a group, press the Left Arrow key or Spacebar. For more information on
keyboard navigation, see “Editing a node label at run time” on page 416 and “Tree user interaction” on
page 416.
The data reported for body cells depends on the setting of the selectionMode property of the AdvancedDataGrid
control, as described in the following table:
In this example:
• When you press the Tab key to move focus to the control, the screen reader reports: "ListBox."
• Pressing the Down Arrow and Up Arrow keys navigates the rows of the control.
• When the selectionMode property is set to singleRow, the screen reader reports all the data in the row,
for example: "Artist: Grateful Dead, Album: Shakedown Street, Price: 11.99."
• When the selectionMode property is set to singleCell, the screen reader reports only the selected cell's
data. For the cell in the first column of the row, the screen reader reports: "Artist: Grateful Dead, Row 1." The
row information is reported only when focus is on the first column, not for other columns in the row.
Therefore, for the second cell, the screen reader reports: "Album: ShakeDown Street."
ADOBE FLEX 3 1153
Adobe Flex 3 Developer Guide
• Pressing the Up Arrow key when the focus is on the first row of the control moves the focus to the header cell.
The screen reader reports: "From: Column 1 press space to sort ascending on this field. Press control space to add
this field to sort."
• Pressing the Spacebar sorts the column.
• Multicolumn sorting is supported. The sort order is reported in case of multicolumn sorting.
For example, if the Album column is sorted and the sort order is 2, the screen reader reports: "Album: Column
2 sorted ascending, sort order 2 Press space to sort descending on this field. Press Control+space to add this
field to sort."
In this example:
• When you press the Tab key to move focus to the control, the screen reader reports: "Treeview."
• Pressing the Shift+Control+Right Arrow keys opens a node.
• Pressing the Down Arrow key moves the focus to the next row.
If you move focus to the first row under Arizona, the screen reader reports: "Level2. Region: Southwest,
Territory: Arizona, TerritoryRep: Barbara Jennings, Actual: 38865, Estimate: 40000, 1 of 2. Press
Control+Shift+Right Arrow to open, Control+Shift+Left Arrow to close. Open."
1154 CHAPTER 37
<mx:Script>
<![CDATA[
import mx.core.Container;
import mx.core.EdgeMetrics;
[Bindable]
public var cards: Array = [
{label:"Visa", data:1},
{label:"Master Card", data:2},
{label:"American Express", data:3} ];
ADOBE FLEX 3 1155
Adobe Flex 3 Developer Guide
[Bindable]
public var selectedItem:Object;
[Bindable]
public var forListDP:Array = [
{label:'Apple', data:10.00},
{label:'Banana', data:15.00},
{label:'Melon', data:3.50},
{label:'Kiwi', data:7.65},
{label:'123', data:12.35 },
{label:'some', data:10.01 }];
target = target.parent;
}
description String Specifies a description for the component that is read by the screen reader.
forceSimple Boolean Hides the children of a component from a screen reader when set to true. The default value is
false.
name String Specifies a description of the component that is read by the screen reader. When accessible
objects do not have a specified name, a screen reader uses a generic word, such as Button.
shortcut String Indicates a keyboard shortcut associated with this display object.
silent Boolean Hides a component from a screen reader when set to true. The default value is false.
Modifying these properties has no effect by itself. You must also use the Accessibility.updateProperties()
method to inform screen reader users of Flash Player content changes. Calling this method causes Flash Player to
reexamine all accessibility properties, update property descriptions for the screen reader, and, if necessary, send
events to the screen reader that indicate changes occurred.
When updating the accessibility properties of multiple objects at once, you must include only a single call to the
Accessiblity.updateProperties() method. (Excessive updates to the screen reader can cause some screen
readers to become too verbose.)
1158 CHAPTER 37
• Ensure that you use a clean and simple interface to help screen readers and users with cognitive impairments
navigate through your application. Give your application to people who have never seen it before and watch while
they try to perform key tasks without any assistance or documentation. If they fail, consider modifying your
interface.
• Test your application with a screen reader, or have it tested by users of screen readers.
1160 CHAPTER 37
1161
Topics
Using HTTPService components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1163
Using WebService components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1172
Using RemoteObject components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1190
Explicit parameter passing and parameter binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1206
Handling service results. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1213
MXML code
The Flex application in the following example calls a PHP page with the POST method. The PHP page queries a
MySQL database table called users. It formats the query results as XML and returns the XML to the Flex appli-
cation, where it is bound to the dataProvider property of a DataGrid control and displayed in the DataGrid
control. The Flex application also sends the user name and e-mail address of new users to the PHP page, which
performs an insert into the user database table.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
xmlns="*" creationComplete="send_data()">
<mx:Script>
<![CDATA[
private function send_data():void {
userRequest.send();
}
]]>
</mx:Script>
<mx:Form x="22" y="10" width="493">
<mx:HBox>
<mx:Label text="Username"/>
<mx:TextInput id="username"/>
</mx:HBox>
<mx:HBox>
<mx:Label text="Email Address"/>
<mx:TextInput id="emailaddress"/>
</mx:HBox>
<mx:Button label="Submit" click="send_data()"/>
</mx:Form>
<mx:DataGrid id="dgUserRequest" x="22" y="128"
dataProvider="{userRequest.lastResult.users.user}">
<mx:columns>
<mx:DataGridColumn headerText="User ID" dataField="userid"/>
<mx:DataGridColumn headerText="User Name" dataField="username"/>
</mx:columns>
</mx:DataGrid>
<mx:TextInput x="22" y="292" id="selectedemailaddress"
text="{dgUserRequest.selectedItem.emailaddress}"/>
<mx:HTTPService id="userRequest" url="http://localhost/myproj/request_post2.php"
useProxy="false" method="POST">
<mx:request xmlns="">
<username>{username.text}</username>
<emailaddress>{emailaddress.text}</emailaddress>
</mx:request>
</mx:HTTPService>
</mx:Application>
The HTTPService’s send() method makes the call to the PHP page. This call is made in the send_data()
method in the Script block of the MXML file.
ADOBE FLEX 3 1165
Adobe Flex 3 Developer Guide
The resultFormat property of the HTTPService component is set to object, so the data is sent back to the Flex
application as a graph of ActionScript objects. This is the default value for the resultFormat property. Alterna-
tively, you can use a resultFormat of e4x to return data as an XMLList object on which you can perform
ECMAScript for XML (E4X) operations. Switching the resultFormat property to e4x requires the following
minor changes to the MXML code.
Note: If the result format is e4x, you do not include the root node of the XML structure in the dot notation when
binding to the DataGrid.
The XML returned in this example contains no namespace information. For information about working with
XML that does contain namespaces, see “Handling results as XML with the e4x result format” on page 1216.
...
<mx:DataGrid id="dgUserRequest" x="22" y="128"
dataProvider="{userRequest.lastResult.user}">
...
<mx:HTTPService id="userRequest" url="http://server/myproj/request_post2.php"
useProxy="false" method="POST" resultFormat="e4x">
...
When using the e4x result format, you can optionally bind the lastResult property to an XMLListCollection
object and then bind that object to the DataGrid.dataProvider property, as the following code snippet shows:
...
<mx:XMLListCollection id="xc"
source="{userRequest.lastResult.user}"/>
PHP code
This application calls the following PHP page. This PHP code performs SQL database inserts and queries, and
returns query results to the Flex application in an XML structure.
<html>
<head>
<title>PHP Test</title>
</head>
<body>
<?php
1166 CHAPTER 38
mysql_select_db( DATABASE_NAME );
$Return = "<users>";
MXML code
The Flex application in the following example calls a ColdFusion page with the POST method. The ColdFusion
page queries a MySQL database table called users. It formats the query results as XML and returns the XML to the
Flex application, where it is bound to the dataProvider property of a DataGrid control and displayed in the
DataGrid control. The Flex application also sends the user name and e-mail address of new users to the
ColdFusion page, which performs an insert into the user database table.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="absolute"
creationComplete="userRequest.send()">
<mx:Form x="22" y="10" width="493">
<mx:HBox>
<mx:Label text="Username"/>
<mx:TextInput id="username"/>
</mx:HBox>
<mx:HBox>
<mx:Label text="Email Address"/>
<mx:TextInput id="emailaddress"/>
</mx:HBox>
<mx:Button label="Submit" click="userRequest.send()"/>
</mx:Form>
<mx:DataGrid id="dgUserRequest" x="22" y="128"
dataProvider="{userRequest.lastResult.users.user}">
<mx:columns>
<mx:DataGridColumn headerText="User ID" dataField="userid"/>
<mx:DataGridColumn headerText="User Name" dataField="username"/>
</mx:columns>
</mx:DataGrid>
<mx:TextInput x="22" y="292" id="selectedemailaddress"
text="{dgUserRequest.selectedItem.emailaddress}"/>
<mx:HTTPService id="userRequest" url="http://server:8500/flexapp/returncfxml.cfm"
useProxy="false" method="POST">
<mx:request xmlns="">
<username>{username.text}</username>
<emailaddress>{emailaddress.text}</emailaddress>
</mx:request>
</mx:HTTPService>
</mx:Application>
The HTTPService’s send() method makes the call to the ColdFusion page. This call is made in the send_data()
method in the Script block of the MXML file.
1168 CHAPTER 38
The resultFormat property of the HTTPService component is set to object, so the data is sent back to the Flex
application as a graph of ActionScript objects. This is the default value for the resultFormat property. Alterna-
tively, you can use a result format of e4x to return data as an XMLList object on which you can perform ECMAS-
cript for XML (E4X) operations. Switching the resultFormat property to e4x requires the following minor
changes to the MXML code.
Note: If the result format is e4x, you do not include the root node of the XML structure in the dot notation when
binding to the DataGrid.
The XML returned in this example contains no namespace information. For information about working with
XML that does contain namespaces, see “Handling results as XML with the e4x result format” on page 1216.
...
<mx:DataGrid id="dgUserRequest" x="22" y="128"
dataProvider="{userRequest.lastResult.user}">
...
<mx:HTTPService id="userRequest" url="http://server:8500/flexapp/returncfxml.cfm"
useProxy="false" method="POST" resultFormat="e4x">
...
When using the e4x result format, you can optionally bind the lastResult property to an XMLListCollection
object and then bind that object to the DataGrid dataProvider property, as the following code snippet shows:
...
<mx:XMLListCollection id="xc"
source="{userRequest.lastResult.user}"/>
<mx:DataGrid id="dgUserRequest" x="22" y="128" dataProvider="{xc}">
...
SQL script
The ColdFusion code for this application uses a database table called users in a MySQL database called sample.
The following MySQL script creates the table:
CREATE TABLE `users` (
`userid` int(10) unsigned NOT NULL auto_increment,
`username` varchar(255) collate latin1_general_ci NOT NULL,
`emailaddress` varchar(255) collate latin1_general_ci NOT NULL,
PRIMARY KEY (`userid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=3 ;
ColdFusion code
This application calls the following ColdFusion page. This ColdFusion code performs SQL database inserts and
queries, and returns query results to the Flex application. The ColdFusion page uses the cfquery tag to insert data
into the database and query the database, and it uses the cfxml tag to format the query results in an XML
structure.
<cfprocessingdirective pageencoding = "utf-8" suppressWhiteSpace = "Yes">
<cfif isDefined("username") and isDefined("emailaddress") and username NEQ "">
<cfquery name="addempinfo" datasource="sample">
ADOBE FLEX 3 1169
Adobe Flex 3 Developer Guide
MXML code
The Flex application in the following example calls a JSP page that retrieves data from a SQL database. It formats
database query results as XML and returns the XML to the Flex application, where it is bound to the
dataProvider property of a DataGrid control and displayed in the DataGrid control.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:HTTPService id="srv" url="catalog.jsp"/>
</mx:Application>
1170 CHAPTER 38
The HTTPService’s send() method makes the call to the JSP page. This call is made in the click event of the
Button in the MXML file.
The resultFormat property of the HTTPService component is set to object, so the data is sent back to the Flex
application as a graph of ActionScript objects. This is the default value for the resultFormat property. Alterna-
tively, you can use a result format of e4x to return data as an XMLList object on which you can perform ECMAS-
cript for XML (E4X) operations. Switching the resultFormat property to e4x requires the following minor
changes to the MXML code.
Note: If the result format is e4x, you do not include the root node of the XML structure in the dot notation when
binding to the DataGrid.
The XML returned in this example contains no namespace information. For information about working with
XML that does contain namespaces, see “Handling results as XML with the e4x result format” on page 1216.
...
<mx:HTTPService id="srv" url="catalog.jsp" resultFormat="e4x"/>
...
<mx:DataGrid dataProvider="{srv.lastResult.product}" width="100%" height="100%"/>
When using the e4x result format, you can optionally bind the lastResult property to an XMLListCollection
object and then bind that object to the DataGrid.dataProvider property:
...
<mx:XMLListCollection id="xc"
source="{userRequest.lastResult.product}"/>
JSP code
The following example shows the JSP page used in this application. This JSP page does not call a database directly.
It gets its data from a Java class called ProductService, which in turn uses a Java class called Product to represent
individual products.
<%@page import="flex.samples.product.ProductService,
flex.samples.product.Product,
java.util.List"%>
<?xml version="1.0" encoding="utf-8"?>
<catalog>
<%
ProductService srv = new ProductService();
List list = null;
list = srv.getProducts();
Product product;
for (int i=0; i<list.size(); i++)
{
product = (Product) list.get(i);
%>
<product productId="<%= product.getProductId()%>">
<name><%= product.getName() %></name>
ADOBE FLEX 3 1171
Adobe Flex 3 Developer Guide
MXML code
The Flex application in the following example calls a web service that queries a SQL database table called users
and returns data to the Flex application, where it is bound to the dataProvider property of a DataGrid control
and displayed in the DataGrid control. The Flex application also sends the user name and e-mail address of new
users to the web service, which performs an insert into the user database table. The back-end implementation of
the web service is a ColdFusion component; the same ColdFusion component is accessed as a remote object in
“Using RemoteObject components” on page 1190.
ADOBE FLEX 3 1173
Adobe Flex 3 Developer Guide
WSDL document
The following example shows the WSDL document that defines the API of the web service:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://flexapp"
xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://flexapp"
xmlns:intf="http://flexapp" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns1="http://rpc.xml.coldfusion" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by ColdFusion version 8,0,0,171651-->
<wsdl:types>
<schema targetNamespace="http://rpc.xml.coldfusion"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://flexapp"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="CFCInvocationException">
<sequence/>
</complexType>
<complexType name="QueryBean">
<sequence>
<element name="columnList" nillable="true" type="impl:ArrayOf_xsd_string"/>
<element name="data" nillable="true" type="impl:ArrayOfArrayOf_xsd_anyType"/>
</sequence>
</complexType>
</schema>
<schema targetNamespace="http://flexapp" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://rpc.xml.coldfusion"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="ArrayOf_xsd_string">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
</restriction>
</complexContent>
</complexType>
<complexType name="ArrayOfArrayOf_xsd_anyType">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:anyType[][]"/>
</restriction>
</complexContent>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="CFCInvocationException">
<wsdl:message name="returnRecordsResponse">
<wsdl:part name="returnRecordsReturn" type="tns1:QueryBean"/>
</wsdl:message>
<wsdl:message name="insertRecordRequest">
<wsdl:part name="username" type="xsd:string"/>
<wsdl:part name="emailaddress" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="returncfxml">
<wsdl:operation name="insertRecord" parameterOrder="username emailaddress">
<wsdl:input message="impl:insertRecordRequest" name="insertRecordRequest"/>
<wsdl:output message="impl:insertRecordResponse" name="insertRecordResponse"/>
<wsdl:fault message="impl:CFCInvocationException" name="CFCInvocationException"/>
</wsdl:operation>
<wsdl:operation name="returnRecords">
<wsdl:input message="impl:returnRecordsRequest" name="returnRecordsRequest"/>
<wsdl:output message="impl:returnRecordsResponse" name="returnRecordsResponse"/>
<wsdl:fault message="impl:CFCInvocationException" name="CFCInvocationException"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="returncfxml.cfcSoapBinding" type="impl:returncfxml">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="insertRecord">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="insertRecordRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://flexapp" use="encoded"/>
</wsdl:input>
<wsdl:output name="insertRecordResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://flexapp" use="encoded"/>
</wsdl:output>
<wsdl:fault name="CFCInvocationException">
<wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
name="CFCInvocationException" namespace="http://flexapp" use="encoded"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="returnRecords">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="returnRecordsRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://flexapp" use="encoded"/>
</wsdl:input>
<wsdl:output name="returnRecordsResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://flexapp" use="encoded"/>
</wsdl:output>
<wsdl:fault name="CFCInvocationException">
<wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
name="CFCInvocationException" namespace="http://flexapp" use="encoded"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="returncfxmlService">
<wsdl:port binding="impl:returncfxml.cfcSoapBinding" name="returncfxml.cfc">
<wsdlsoap:address location="http://localhost:8500/flexapp/returnusers.cfc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
1176 CHAPTER 38
Tag Description
<binding> Specifies the protocol that clients, such as Flex applications, use to communicate with a web service. Bindings exist for
SOAP, HTTP GET, HTTP POST, and MIME. Flex supports the SOAP binding only.
<fault> Specifies an error value that is returned as a result of a problem processing a message.
<input> Specifies a message that a client, such as a Flex application, sends to a web service.
<output> Specifies a message that the web service sends to a web service client, such as a Flex application.
<port> Specifies a web service endpoint, which specifies an association between a binding and a network address.
<service> Defines a collection of <port> tags. Each service maps to one <portType> tag and specifies different ways to access
the operations in that <portType> tag.
The style property of the associated <soap:binding> tag determines the operation style. In this example, the
style is document.
Any operation in a service can specify the same style or override the style that is specified for the port associated
with the service, as the following example shows:
<operation name="SendMSN">
<soap:operation soapAction="http://www.bindingpoint.com/ws/imalert/
SendMSN"style="document"/>
The addSimpleHeader() method is a shortcut for a single name-value SOAP header. When you use the
addSimpleHeader() method, you create SOAPHeader and QName objects in parameters of the method. The
addSimpleHeader() method has the following signature:
addSimpleHeader(qnameLocal:String, qnameNamespace:String, headerName:String,
headerValue:Object):void
The addSimpleHeader() method takes the following parameters:
• qnameLocal is the local name for the header QName.
• qnameNamespace is the namespace for the header QName.
• headerName is the name of the header.
• headerValue is the value of the header. This can be a string if it is a simple value, an object that will undergo
basic XML encoding, or XML if you want to specify the header XML yourself.
The code in the following example shows how to use the addHeader() method and the addSimpleHeader()
method to add a SOAP header. The methods are called in an event listener function called headers, and the event
listener is assigned in the load property of an <mx:WebService> tag:
<?xml version="1.0"?>
<!-- fds\rpc\WebServiceAddHeader.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" height="600">
<mx:WebService id="ws" destination="wsDest" load="headers();"/>
<mx:Script>
<![CDATA[
import mx.rpc.soap.SOAPHeader;
private var header1:SOAPHeader;
private var header2:SOAPHeader;
<!-- The value of the destination property is for demonstration only and is not a real
destination. -->
<mx:WebService id="ws" destination="wsDest" load="headers();"/>
<mx:Script>
<![CDATA[
import mx.rpc.*;
import mx.rpc.soap.SOAPHeader;
<mx:HBox>
<mx:Button label="Clear headers and run again" click="clear();"/>
</mx:HBox>
</mx:Application>
ADOBE FLEX 3 1181
Adobe Flex 3 Developer Guide
// Redirect all service operations to the URL received in the login result.
serviceName.endpointURI=newServiceURL;
}
...
A web service that requires you to pass security credentials might also return an identifier that you must attach in
a SOAP header for subsequent requests. For more information, see “Working with SOAP headers” on page 1178.
Top-level elements
xsd:element Object If input value is null, encoded output is set with the
xsi:nil attribute.
nillable == true
xsd:element Object Input value is ignored and fixed value is used instead.
fixed != null
xsd:element Object If input value is null, this default value is used instead.
default != null
Local elements
1182 CHAPTER 38
xsd:element Object Input value is ignored and omitted from encoded output.
maxOccurs == 0
The following table shows the encoding mappings from ActionScript 3 types to XML schema built-in types.
The following table shows the mapping from ActionScript 3 types to SOAP-encoded types.
soapenc:Array Array SOAP-encoded arrays are special cased and are supported only with
RPC-encoded style web services.
mx.collections.IList
soapenc:* Object Any other SOAP-encoded type is processed as if it were in the XSD
namespace based on the localName of the type's QName.
and derivatives:
xsd:byte
xsd:int
xsd:long
xsd:negativeInteger
xsd:nonNegativeInteger
xsd:nonPositiveInteger
xsd:positiveInteger
xsd:short
xsd:unsignedByte
xsd:unsignedInt
xsd:unsignedLong
xsd:unsignedShort
ADOBE FLEX 3 1187
Adobe Flex 3 Developer Guide
xsd:IDREF
xsd:IDREFS
xsd:ENTITY
xsd:ENTITIES xsd:language
xsd:Name
xsd:NCName
xsd:NMTOKEN
xsd:NMTOKENS
xsd:normalizedString
xsd:token
xsi:nil null
The following table shows the decoding mappings from SOAP-encoded types to ActionScript 3 types.
soapenc:* Object Any other SOAP-encoded type is processed as if it were in the XSD
namespace based on the localName of the type's QName.
The following table shows the decoding mappings from custom data types to ActionScript 3 data types.
http://xml.apache.org/x
ml-soap:Rowset
<simpleType>
<restriction>
<minExclusive>
<minInclusive>
<maxExclusiv>
<maxInclusive>
<totalDigits>
<fractionDigits>
<length>
<minLength>
<maxLength>
<enumeration>
<whiteSpace>
<pattern>
</restriction>
</simpleType>
<complexType
final="..."
block="..."
mixed="..."
ADOBE FLEX 3 1189
Adobe Flex 3 Developer Guide
abstract="..."/>
<any
processContents="..."/>
<annotation>
typeReg2.registerClass(qn, anotherClass);
myWS.anotherOperation.decoder.typeRegistry = typeReg2;
1190 CHAPTER 38
MXML code
The Flex application in the following example uses a RemoteObject component to call a ColdFusion component.
The ColdFusion component queries a MySQL database table called users. It returns the query result to the Flex
application where it is bound to the dataProvider property of a DataGrid control and displayed in the DataGrid
control. The Flex application also sends the user name and e-mail address of new users to the ColdFusion
component, which performs an insert into the user database table.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="absolute"
creationComplete="userRequest.returnRecords()">
<mx:Form x="22" y="10" width="493">
<mx:HBox>
<mx:Label text="Username"/>
<mx:TextInput id="username"/>
</mx:HBox>
<mx:HBox>
<mx:Label text="Email Address"/>
<mx:TextInput id="emailaddress"/>
</mx:HBox>
<mx:Button label="Submit" click="clickHandler()"/>
</mx:Form>
<mx:DataGrid id="dgUserRequest" x="22" y="128">
<mx:columns>
<mx:DataGridColumn headerText="User ID" dataField="userid"/>
<mx:DataGridColumn headerText="User Name" dataField="username"/>
</mx:columns>
</mx:DataGrid>
<mx:TextInput x="22" y="292" id="selectedemailaddress"
text="{dgUserRequest.selectedItem.emailaddress}"/>
<mx:RemoteObject
id="userRequest"
destination="ColdFusion"
source="flexapp.returnusers">
<mx:method name="returnRecords" result="returnHandler(event)"
fault="mx.controls.Alert.show(event.fault.faultString)"/>
<mx:method name="insertRecord" result="insertHandler()"
fault="mx.controls.Alert.show(event.fault.faultString)"/>
</mx:RemoteObject>
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
ColdFusion component
The Flex application calls the following ColdFusion component. This ColdFusion code performs SQL database
inserts and queries and returns query results to the Flex application. The ColdFusion page uses the cfquery tag
to insert data into the database and query the database, and it uses the cfreturn tag to format the query results
as a ColdFusion query object.
<cfcomponent name="returnusers">
<cffunction name="returnRecords" access="remote" returnType="query">
<?xml version="1.0"?>
<!-- fds\rpc\ROInAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.rpc.remoting.RemoteObject;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
[Bindable]
public var empList:Object;
public var employeeRO:RemoteObject;
flash.utils.ByteArray byte []
flash.utils.IExternalizable java.io.Externalizable
ADOBE FLEX 3 1197
Adobe Flex 3 Developer Guide
if null is sent, primitive types of double, long, float, int, short, byte
Object (generic) java.util.Map If a Map interface is specified, creates a new java.util.HashMap for
java.util.Map and a new java.util.TreeMap for java.util.SortedMap.
(legacy XML type) You can enable legacy XML support for the XMLDocument type on
any channel defined in the services-config.xml file. This setting is
important only for sending data from the server back to the client; it
controls how org.w3c.dom.Document instances are sent to Action-
Script. For more information, see “Configuring AMF serialization on a
channel” on page 1201.
1198 CHAPTER 38
Primitive values cannot be set to null in Java. When passing Boolean and Number values from the client to a Java
object, Flex interprets null values as the default values for primitive types; for example, 0 for double, float, long,
int, short, byte, \u0000 for char, and false for Boolean. Only primitive Java types get default values.
LiveCycle Data Services ES and Vega handle java.lang.Throwable objects like any other typed object. They are
processed with rules that look for public fields and bean properties, and typed objects are returned to the client.
The rules are like normal bean rules except that they look for getters for read-only properties. This lets you get
more information from a Java exception. If you require legacy behavior for Throwable objects, you can set the
legacy-throwable property to true on a channel; for more information, see “Configuring AMF serialization
on a channel” on page 1201.
You can pass strict arrays as parameters to methods that expect an implementation of the java.util.Collection or
native Java Array APIs.
A Java Collection can contain any number of object types, whereas a Java Array requires that entries are the same
type (for example, java.lang.Object[ ], and int[ ]).
LiveCycle Data Services ES and Vega also convert ActionScript strict arrays to appropriate implementations for
common Collection API interfaces. For example, if an ActionScript strict array is sent to the Java object method
public void addProducts(java.util.Set products), LiveCycle Data Services ES and Vega convert it to a
java.util.HashSet instance before passing it as a parameter, because HashSet is a suitable implementation of the
java.util.Set interface. Similarly, LiveCycle Data Services ES and Vega pass an instance of java.util.TreeSet to
parameters typed with the java.util.SortedSet interface.
LiveCycle Data Services ES and Vega pass an instance of java.util.ArrayList to parameters typed with the
java.util.List interface and any other interface that extends java.util.Collection. Then these types are sent back to
the client as mx.collections.ArrayCollection instances. If you require normal ActionScript arrays to be sent back
to the client, you must set the legacy-collection element to true in the serialization section of a channel-
definition's properties. For more information, see “Configuring AMF serialization on a channel” on page 1201.
In the ActionScript class, you use the [RemoteClass(alias=" ")] metadata tag to create an ActionScript object
that maps directly to the Java object. The ActionScript class to which data is converted must be used or referenced
in the MXML file for it to be linked into the SWF file and available at run time. A good way to do this is by casting
the result object, as the following example shows:
var result:MyClass = MyClass(event.result);
The class itself should use strongly typed references so that its dependencies are also linked.
The following examples shows the source code for an ActionScript class that uses the [RemoteClass(alias="
")] metadata tag:
package samples.contact {
[Bindable]
[RemoteClass(alias="samples.contact.Contact")]
public class Contact {
public var contactId:int;
java.lang.String String
If value < 0xF0000000 || value > 0x0FFFFFFF, the value is promoted to Number due to
AMF encoding requirements.
java.lang.Byte[] flash.utils.ByteArray
java.math.BigDecimal String
java.util.Calendar Date
Dates are sent in the Coordinated Universal Time (UTC) time zone. Clients and servers
must adjust time accordingly for time zones.
java.util.Date Date
Dates are sent in the UTC time zone. Clients and servers must adjust time accordingly for
time zones.
ADOBE FLEX 3 1201
Adobe Flex 3 Developer Guide
java.lang.Object[] Array
java.util.Map Object (untyped). For example, a java.util.Map[] is converted to an array (of objects).
null null
Property Description
<ignore-property-errors> Default value is true. Determines if the endpoint should throw an error when an
true incoming client object has unexpected properties that cannot be set on the server
</ignore-property-errors> object.
<log-property-errors> Default value is false. When true, unexpected property errors are logged.
false
</log-property-errors>
<legacy-collection>false</legacy- Default value is false. When true, instances of java.util.Collection are returned as
collection> ActionScript arrays. When false, instances of java.util.Collection are returned as
mx.collections.ArrayCollection.
<legacy-map>false</legacy-map> Default value is false. When true, java.util.Map instances are serialized as an ECMA
array or associative array instead of an anonymous object.
<legacy-xml>false</legacy-xml> Default value is false. When true, org.w3c.dom.Document instances are serialized as
flash.xml.XMLDocument instances instead of intrinsic XML (E4X capable) instances.
<legacy-throwable>false</legacy- Default value is false. When true, java.lang.Throwable instances are serialized as AMF
throwable> status-info objects (instead of normal bean serialization, including read-only properties).
1202 CHAPTER 38
Property Description
<restore-references> Default value is false. An advanced switch to make the deserializer keep track of object
false references when a type translation has to be made; for example, when an anonymous
</restore-references> object is sent for a property of type java.util.SortedMap, the object is first deserialized to
a java.util.Map as normal, and then translated to a suitable implementation of Sort-
edMap (such as java.util.TreeMap). If other objects pointed to the same anonymous
object in an object graph, this setting restores those references instead of creating Sort-
edMap implementations everywhere. Notice that setting this property to true can slow
down performance significantly for large amounts of data.
<instantiate-types> Default value is true. Advanced switch that when set to false stops the deserializer
true from creating instances of strongly typed objects and instead retains the type informa-
</instantiate-types> tion and deserializes the raw properties in a Map implementation, specifically
flex.messaging.io.ASObject. Notice that any classes under flex.* package are always
instantiated.
On the server side, a Java class that implements the java.io.Externalizable interface performs functionality that is
analogous to an ActionScript class that implements the flash.utils.IExternalizable interface.
Note: If precise by-reference serialization is required, you should not use types that implement the IExternalizable
interface with the HTTPChannel. When you do this, references between recurring objects are lost and appear to be
cloned at the endpoint.
The following example shows the complete source code for the client (ActionScript) version of a Product class that
maps to a Java-based Product class on the server. The client Product implements the IExternalizable interface, and
the server Product implements the Externalizable interface.
// Product.as
package samples.externalizable {
import flash.utils.IExternalizable;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
[RemoteClass(alias="samples.externalizable.Product")]
public class Product implements IExternalizable {
public function Product(name:String=null) {
this.name = name;
}
As the following example shows, the writeExternal() method of the server Product is almost identical to the
client version of this method:
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(properties);
out.writeFloat(price);
}
In the client Product’s writeExternal() method, the flash.utils.IDataOutput.writeFloat() method is
an example of standard serialization methods that meet the specifications for the Java
java.io.DataInput.readFloat() methods for working with primitive types. This method sends the price
property, which is a Float, to the server Product.
The example of AMF 3 serialization in the client Product’s writeExternal() method is the call to the
flash.utils.IDataOutput.writeObject() method, which maps to the
java.io.ObjectInput.readObject() method call in the server Product’s readExternal() method. The
flash.utils.IDataOutput.writeObject() method sends the properties property, which is an object, and
the name property, which is a string, to the server Product. This is possible because the AMFChannel endpoint
has an implementation of the java.io.ObjectInput interface that expects data sent from the writeObject()
method to be formatted as AMF 3.
In turn, when the readObject() method is called in the server Product’s readExternal() method, it uses AMF
3 deserialization; this is why the ActionScript version of the properties value is assumed to be of type Map and
name is assumed to be of type String.
The following example shows the complete source of the server Product class:
// Product.java
package samples.externalizable;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Map;
/**
* This Externalizable class requires that clients sending and
* receiving instances of this type adhere to the data format
* required for serialization.
*/
public class Product implements Externalizable {
private String inventoryId;
public String name;
public Map properties;
public float price;
public Product()
{
}
ADOBE FLEX 3 1205
Adobe Flex 3 Developer Guide
/**
* Local identity used to track third-party inventory. This property is
* not sent to the client because it is server specific.
* The identity must start with an 'X'.
*/
public String getInventoryId() {
return inventoryId;
}
public void setInventoryId(String inventoryId) {
if (inventoryId != null && inventoryId.startsWith("X"))
{
this.inventoryId = inventoryId;
}
else
{
throw new IllegalArgumentException("3rd party product
inventory identities must start with 'X'");
}
}
/**
* Deserializes the client state of an instance of ThirdPartyProxy
* by reading in String for the name, a Map of properties
* for the description, and
* a floating point integer (single precision) for the price.
*/
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
// Read in the server properties from the client representation.
name = (String)in.readObject();
properties = (Map)in.readObject();
price = in.readFloat();
setInventoryId(lookupInventoryId(name, price));
}
/**
* Serializes the server state of an instance of ThirdPartyProxy
* by sending a String for the name, a Map of properties
* String for the description, and a floating point
* integer (single precision) for the price. Notice that the inventory
* identifier is not sent to external clients.
*/
public void writeExternal(ObjectOutput out) throws IOException {
// Write out the client properties from the server representation.
out.writeObject(name);
out.writeObject(properties);
out.writeFloat(price);
}
<mx:RemoteObject
id="employeeRO"
destination="SalaryManager"
result="empList=event.result"
fault="Alert.show(event.fault.faultString, 'Error');"/>
If you do not specify a parameter to the send() method, the HTTPService component uses any query parameters
specified in an <mx:request> tag.
The following examples show two ways to call an HTTP service by using the send() method with a parameter.
The second example also shows how to call the cancel() method to cancel an HTTP service call.
<?xml version="1.0"?>
<!-- fds\rpc\RPCSend.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function callService():void {
// Cancel all previous pending calls.
myService.cancel();
<mx:HTTPService
id="myService"
destination="Dest"
useProxy="true"/>
<!-- HTTP service call with a send() method that takes a variable as its parameter. The
value of the variable is an Object. -->
<mx:Button click="myService.send({param1: 'val1'});"/>
<!-- HTTP service call with an object as a send() method parameter that provides query
parameters. -->
<mx:Button click="callService();"/>
</mx:Application>
The following example shows a method with two parameters bound to the text properties of TextInput controls.
A PhoneNumberValidator validator is assigned to arg1, which is the name of the first argument tag.
<?xml version="1.0"?>
<!-- fds\rpc\ROParamBind1.mxml. -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:RemoteObject
id="ro"
destination="roDest">
<mx:method name="setData">
<mx:arguments>
<arg1>{text1.text}</arg1>
<arg2>{text2.text}</arg2>
</mx:arguments>
</mx:method>
</mx:RemoteObject>
<mx:TextInput id="text1"/>
<mx:TextInput id="text2"/>
<mx:PhoneNumberValidator source="{ro.setData.arguments}" property="arg1"/>
</mx:Application>
Flex sends the argument tag values to the method in the order that the MXML tags specify.
The following example uses parameter binding in a RemoteObject component’s <mx:method> tag to bind the data
of a selected ComboBox item to the employeeRO.getList operation when the user clicks a Button control. When
you use parameter binding, you call a service by using the send() method with no parameters.
<?xml version="1.0"?>
<!-- fds\rpc\ROParamBind2.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="10">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.utils.ArrayUtil;
]]>
</mx:Script>
<mx:RemoteObject
id="employeeRO"
destination="roDest"
showBusyCursor="true"
fault="Alert.show(event.fault.faultString, 'Error');">
<mx:method name="getList">
<mx:arguments>
<deptId>{dept.selectedItem.data}</deptId>
</mx:arguments>
</mx:method>
</mx:RemoteObject>
<mx:ArrayCollection id="employeeAC"
source="{ArrayUtil.toArray(employeeRO.getList.lastResult)}"/>
<mx:HBox>
<mx:Label text="Select a department:"/>
<mx:ComboBox id="dept" width="150">
<mx:dataProvider>
1210 CHAPTER 38
<mx:ArrayCollection>
<mx:source>
<mx:Object label="Engineering" data="ENG"/>
<mx:Object label="Product Management" data="PM"/>
<mx:Object label="Marketing" data="MKT"/>
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:ComboBox>
<mx:Button label="Get Employee List"
click="employeeRO.getList.send()"/>
</mx:HBox>
<mx:DataGrid dataProvider="{employeeAC}" width="100%">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="phone" headerText="Phone"/>
<mx:DataGridColumn dataField="email" headerText="Email"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
If you are unsure whether the result of a service call contains an array or an individual object, you can use the
toArray() method of the mx.utils.ArrayUtil class to convert it to an array, as this example shows. If you pass the
toArray() method to an individual object, it returns an array with that object as the only Array element. If you
pass an array to the method, it returns the same array. For information about working with ArrayCollection
objects, see “Using Data Providers and Collections” on page 137.
<mx:HTTPService
id="employeeSrv"
url="employees.jsp">
<mx:request>
ADOBE FLEX 3 1211
Adobe Flex 3 Developer Guide
<deptId>{dept.selectedItem.data}</deptId>
</mx:request>
</mx:HTTPService>
<mx:ArrayCollection
id="employeeAC"
source=
"{ArrayUtil.toArray(employeeSrv.lastResult.employees.employee)}"/>
<mx:HBox>
<mx:Label text="Select a department:"/>
<mx:ComboBox id="dept" width="150">
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<mx:Object label="Engineering" data="ENG"/>
<mx:Object label="Product Management" data="PM"/>
<mx:Object label="Marketing" data="MKT"/>
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:ComboBox>
<mx:Button label="Get Employee List" click="employeeSrv.send();"/>
</mx:HBox>
<mx:DataGrid dataProvider="{employeeAC}"
width="100%">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="phone" headerText="Phone"/>
<mx:DataGridColumn dataField="email" headerText="Email"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
If you are unsure whether the result of a service call contains an array or an individual object, you can use the
toArray() method of the mx.utils.ArrayUtil class to convert it to an array, as the previous example shows. If you
pass the toArray() method to an individual object, it returns an array with that object as the only Array element.
If you pass an array to the method, it returns the same array. For information about working with ArrayCollection
objects, see “Using Data Providers and Collections” on page 137.
The following example uses parameter binding in a WebService component’s <mx:operation> tag to bind the
data of a selected ComboBox item to the employeeWS.getList operation when the user clicks a Button control.
The <deptId> tag corresponds directly to the getList operation’s deptId parameter. When you use parameter
binding, you call a service by using the send() method with no parameters. This example shows a destination
property on the WebService component, but the way you call a service is the same whether you connect to the
service directly or go through a destination.
<?xml version="1.0"?>
<!-- fds\rpc\WebServiceParamBind.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="10">
<mx:Script>
<![CDATA[
import mx.utils.ArrayUtil;
import mx.controls.Alert;
]]>
</mx:Script>
<mx:WebService
id="employeeWS"
destination="wsDest"
showBusyCursor="true"
fault="Alert.show(event.fault.faultString)">
<mx:operation name="getList">
<mx:request>
<deptId>{dept.selectedItem.data}</deptId>
</mx:request>
</mx:operation>
</mx:WebService>
<mx:ArrayCollection
id="employeeAC"
source="{ArrayUtil.toArray(employeeWS.getList.lastResult)}"/>
<mx:HBox>
<mx:Label text="Select a department:"/>
<mx:ComboBox id="dept" width="150">
<mx:dataProvider>
<mx:ArrayCollection>
<mx:source>
<mx:Object label="Engineering" data="ENG"/>
<mx:Object label="Product Management" data="PM"/>
<mx:Object label="Marketing" data="MKT"/>
</mx:source>
</mx:ArrayCollection>
</mx:dataProvider>
</mx:ComboBox>
<mx:Button label="Get Employee List"
click="employeeWS.getList.send()"/>
</mx:HBox>
<mx:DataGrid dataProvider="{employeeAC}" width="100%">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="phone" headerText="Phone"/>
<mx:DataGridColumn dataField=" to email" headerText="Email"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
ADOBE FLEX 3 1213
Adobe Flex 3 Developer Guide
You can also manually specify an entire SOAP request body in XML with all of the correct namespace information
defined in an <mx:request> tag. To do this, you must set the value of the format attribute of the <mx:request>
tag to xml, as the following example shows:
<?xml version="1.0"?>
<!-- fds\rpc\WebServiceSOAPRequest.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="10">
<mx:WebService id="ws" wsdl="http://api.google.com/GoogleSearch.wsdl"
useProxy="true">
<mx:operation name="doGoogleSearch" resultFormat="xml">
<mx:request format="xml">
<ns1:doGoogleSearch xmlns:ns1="urn:GoogleSearch"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<key xsi:type="xsd:string">XYZ123</key>
<q xsi:type="xsd:string">Balloons</q>
<start xsi:type="xsd:int">0</start>
<maxResults xsi:type="xsd:int">10</maxResults>
<filter xsi:type="xsd:boolean">true</filter>
<restrict xsi:type="xsd:string"/>
<safeSearch xsi:type="xsd:boolean">false</safeSearch>
<lr xsi:type="xsd:string" />
<ie xsi:type="xsd:string">latin1</ie>
<oe xsi:type="xsd:string">latin1</oe>
</ns1:doGoogleSearch>
</mx:request>
</mx:operation>
</mx:WebService>
</mx:Application>
</mx:operation>
</mx:WebService>
<mx:TextInput id="myZip"/>
</mx:Application>
In the following ActionScript example, a result event listener is added to a WebService operation; a fault event
listener is added to the WebService component:
<?xml version="1.0"?>
<!-- fds\rpc\RPCResultFaultAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.rpc.soap.WebService;
import mx.rpc.soap.SOAPFault;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
No namespace
The following example shows how to get an element or attribute value when no namespace is specified on the
element or attribute:
var attributes:XMLList = XML(event.result).Description.value;
The previous code returns xxx for the following XML document:
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<Description>
<value>xxx</value>
</Description>
</RDF>
Any namespace
The following example shows how to get an element or attribute value when any namespace is specified on the
element or attribute:
var attributes:XMLList = XML(event.result).*::Description.*::value;
The previous code returns xxx for either one of the following XML documents:
XML document one:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description>
<rdf:value>xxx</rdf:value>
</rdf:Description>
</rdf:RDF>
XML document two:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cm="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<cm:Description>
<rdf:value>xxx</rdf:value>
</cm:Description>
</rdf:RDF>
Specific namespace
The following example shows how to get an element or attribute value when the declared rdf namespace is
specified on the element or attribute:
var rdf:Namespace = new Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
var attributes:XMLList = XML(event.result).rdf::Description.rdf::value;
The previous code returns xxx for the following XML document:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description>
<rdf:value>xxx</rdf:value>
</rdf:Description>
</rdf:RDF>
ADOBE FLEX 3 1219
Adobe Flex 3 Developer Guide
The following example shows an alternate way to get an element or attribute value when the declared rdf
namespace is specified on an element or attribute:
namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
use namespace rdf;
var attributes:XMLList = XML(event.result).rdf::Description.rdf::value;
The previous code also returns xxx for the following XML document:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description>
<rdf:value>xxx</rdf:value>
</rdf:Description>
</rdf:RDF>
Property Description
result.Tables["someTable "].Columns Array of column names in the order specified in the DataSet or
DataTable schema for the table.
result.Tables["someTable "].Rows Array of objects that represent the data of each table row. For
example, {columnName1:value, columnName2:value,
columnName3:value}.
The following MXML application populates a DataGrid control with DataTable data returned from a .NET web
service.
1220 CHAPTER 38
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.controls.DataGrid;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
</mx:Application>
ADOBE FLEX 3 1221
Adobe Flex 3 Developer Guide
The following example shows the .NET C# class that is the backend web service implementation called by the Flex
application; this class uses the Microsoft SQL Server Northwind sample database:
:
<%@ WebService Language="C#" Class="CustomerList" %>
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Services.Description;
using System.Data;
using System.Data.SqlClient;
using System;
public class CustomerList : WebService {
[WebMethod]
public DataTable getSingleDataTable() {
string cnStr = "[Your_Database_Connection_String]";
string query = "SELECT TOP 10 * FROM Customers";
SqlConnection cn = new SqlConnection(cnStr);
cn.Open();
SqlDataAdapter adpt = new SqlDataAdapter(new SqlCommand(query, cn));
DataTable dt = new DataTable("Customers");
adpt.Fill(dt);
return dt;
}
[WebMethod]
public DataSet getMultiTableDataSet() {
string cnStr = "[Your_Database_Connection_String]";
string query1 = "SELECT TOP 10 CustomerID, CompanyName FROM Customers";
string query2 = "SELECT TOP 10 OrderID, CustomerID, ShipCity,
ShipCountry FROM Orders";
SqlConnection cn = new SqlConnection(cnStr);
cn.Open();
return ds;
}
}
1222 CHAPTER 38
1223
Topics
About data representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1223
The following diagram illustrates what happens in Flex for two different user input examples. In one example, the
user enters ZIP code data, and Flex validates the format. In the other example, the user requests the current
temperature in Celsius.
ADOBE FLEX 3 1225
Adobe Flex 3 Developer Guide
Client tier
1 User interface 9
UI controls UI controls
input data/send request display result data
3 7
Data validators Data model object
Ex: Check if ZIP code is valid. Intermediate data storage.
4 6
Request Result
Client-side data service object
Resource tier
Server tier
1226 CHAPTER 39
Data binding
The data binding feature provides a syntax for automatically copying the value of a property of one client-side
object to a property of another object at run time. Data binding is usually triggered when the value of the source
property changes. You can use data binding to pass user input data from user interface controls to a data service.
You can also use data binding to pass results returned from a data service to user interface controls.
The following example shows a Text control that gets its data from an HSlider control’s value property. The
property name inside the curly braces ({ }) is a binding expression that copies the value of the source property,
mySlider.value, into the Text control’s text property.
<mx:HSlider id="mySlider"/>
<mx:Text text="{mySlider.value}"/>
For more information, see “Binding Data” on page 1229.
Data models
The data model feature lets you store data in client-side objects. A data model is an ActionScript object that
contains properties for storing data, and that optionally contains methods for additional functionality. Data
models are useful for partitioning the user interface and data in an application.
You can use the data binding feature to bind user interface data into a data model. You can also use the data
binding feature to bind data from a data service to a data model.
You can define a simple data model in an MXML tag. When you require functionality beyond storage of untyped
data, you can use an ActionScript class as a data model.
The following example shows an MXML-based data model with properties of TextInput controls bound into its
fields:
<?xml version="1.0"?>
<!-- datarep\DatarepModelTag.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Model id="reg">
<registration>
<name>{nme.text}</name>
<email>{email.text}</email>
<phone>{phone.text}</phone>
<zip>{zip.text}</zip>
<ssn>{ssn.text}</ssn>
</registration>
</mx:Model>
<mx:TextInput id="nme"/>
<mx:TextInput id="email"/>
<mx:TextInput id="phone"/>
<mx:TextInput id="zip"/>
<mx:TextInput id="ssn"/>
</mx:Application>
For more information about data models, see “Storing Data” on page 1257.
ADOBE FLEX 3 1227
Adobe Flex 3 Developer Guide
Data validation
The data validation feature lets you ensure that data meets specific criteria before the application uses the data.
Data validators are ActionScript objects that check whether data in a component is formatted correctly. You can
apply a data validator to a property of any component. For models in a remote procedure call (RPC) component
declaration, properties to which a validator component is applied are validated just before the request is sent to an
RPC service destination. Only valid requests are sent.
The following example shows MXML code that uses the standard ZipCodeValidator component, represented by
the <mx:ZipCodeValidator> tag, to validate the format of the ZIP code that a user enters. The source property
of the ZipCodeValidator validator indicates the property that it validates.
<?xml version="1.0"?>
<!-- datarep\Validate.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:TextInput id="input" text="enter zip" width="80"/>
<mx:Model id="zipModel">
<root>
<zip>{input.text}</zip>
</root>
</mx:Model>
Data formatting
The data formatting feature lets you change the format of data before displaying it in a user interface control. For
example, when a data service returns a string that you want to display in the (xxx)xxx-xxxx phone number format,
you can use a formatter component to ensure that the string is reformatted before it is displayed.
A data formatter component is an object that formats raw data into a customized string. You can use data formatter
components with data binding to reformat data that is returned from a data service.
The following example declares a DateFormatter component with an MM/DD/YYYY date format, and binds the
formatted version of a Date object returned by a web service to the text property of a TextInput control:
<?xml version="1.0"?>
<!-- datarep\Format.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:WebService id="myService" destination="Shop"/>
Topics
About data binding. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1229
Data binding examples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1234
Binding to functions, Objects, and Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1236
Using ActionScript in data binding expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1243
Using an E4X expression in a data binding expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1245
Defining data bindings in ActionScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1247
Using the Bindable metadata tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1249
Considerations for using the binding feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1254
You can include ActionScript code and E4X expressions as part of the data binding expressions, as the following
example shows:
<?xml version="1.0"?>
<!-- binding/BasicBindingWithAS.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:TextInput id="myTI"/>
<mx:Text id="myText" text="{myTI.text.toUpperCase()}"/>
</mx:Application>
In this example, you use the ActionScript method String.toUpperCase() to convert the text in the source
property to upper case when Flex copies it to the destination property. For more information, see “Using Action-
Script in data binding expressions” on page 1243 and “Using an E4X expression in a data binding expression” on
page 1245.
You can use the <mx:Binding> tag as an alternative to the curly braces syntax. When you use the <mx:Binding>
tag, you provide a source property in the <mx:Binding> tag’s source property and a destination property in its
destination property. The following example uses the <mx:Binding> tag to define a data binding from a
TextInput control to a Text control:
<?xml version="1.0"?>
<!-- binding/BasicBindingMXML.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:TextInput id="myTI"/>
<mx:Text id="myText"/>
<mx:Script>
<![CDATA[
import mx.binding.utils.*;
<mx:TextInput id="myTI"/>
<mx:Text id="myText" preinitialize="initBindingHandler();"/>
</mx:Application>
In this example, you use the static BindingUtils.bindProperty() method to define the binding. You can also
use the BindingUtils.bindSetter() method to define a binding to a function. For more information, see
“Defining data bindings in ActionScript” on page 1247.
Notice in this example that you use the preinitialize event to define the data biding. This is necessary because
Flex triggers all data bindings at application startup when the source object dispatches the initialize event. For
more information, see “When data binding occurs” on page 1231.
In the Adobe Flex Language Reference, a property that can be used as the source of a data binding expression
includes the following statement in its description:
“This property can be used as the source for data binding.”
For more information on creating properties that can be used as the source of a data binding expression, see
“Creating properties to use as the source for data binding” on page 1232.
<mx:Script>
<![CDATA[
// Define public vars for tracking font size.
[Bindable]
ADOBE FLEX 3 1233
Adobe Flex 3 Developer Guide
[Bindable]
public var minFontSize:Number = 5;
]]>
</mx:Script>
<mx:Text text="{maxFontSize}"/>
<mx:Text text="{minFontSize}"/>
<!-- Data model stores registration data that user enters. -->
<mx:Model id="reg">
<registration>
<name>{fullname.text}</name>
<email>{email.text}</email>
<phone>{phone.text}</phone>
<zip>{zip.text}</zip>
<ssn>{ssn.text}</ssn>
</registration>
</mx:Model>
<mx:Model id="mod1">
<data>
<part>{input1.text}</part>
</data>
</mx:Model>
<mx:Model id="mod2">
<data>
<part>{input1.text}</part>
</data>
</mx:Model>
<mx:Label text="{mod1.part}"/>
<mx:Label text="{mod2.part}"/>
</mx:Application>
<mx:TextInput id="input1"/>
<mx:TextInput id="input2"/>
If the function is not passed an argument that can be used as the source of a data binding expression, the function
only gets called once when the applications starts.
<mx:Script>
<![CDATA[
import flash.events.Event;
<!-- Use the function as the source of a data binding expression. -->
<mx:TextArea id="myTA" text="{isEnabled()}"/>
Binding to Objects
When you make an Object the source of a data binding expression, the data binding occurs when the Object is
updated, or when a reference to the Object is updated, but not when an individual field of the Object is updated.
In the following example, you create subclass of Object that defines two properties, stringProp and intProp,
but does not make the properties bindable:
package myComponents
{
// binding/myComponents/NonBindableObject.as
<mx:Script>
<![CDATA[
import myComponents.NonBindableObject;
[Bindable]
public var myObj:NonBindableObject = new NonBindableObject();
[Bindable]
public var anotherObj:NonBindableObject =
new NonBindableObject();
public function initObj():void {
anotherObj.stringProp = 'anotherObject';
anotherObj.intProp = 8;
}
]]>
</mx:Script>
ADOBE FLEX 3 1239
Adobe Flex 3 Developer Guide
By placing the [Bindable] metadata tag before the class definition, you make bindable all public properties
defined as variables, and all public properties defined by using both a setter and a getter method. You can then use
the stringProp and intProp properties as the source for a data binding, as the following example shows:
<?xml version="1.0"?>
<!-- binding/SimpleObjectBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initObj();">
<mx:Script>
<![CDATA[
import myComponents.BindableObject;
[Bindable]
public var myObj:BindableObject = new BindableObject();
[Bindable]
public var anotherObj:BindableObject =
new BindableObject();
Note: When defining a data binding expression that uses an array as the source of a data binding expression, the array
should be of type ArrayCollection because the ArrayCollection class dispatches an event when the array or the array
elements change to trigger data binding. For example, a call to ArrayCollection.addItem(),
ArrayCollection.addItemAt(), ArrayCollection.removeItem(), and
ArrayCollection.removeItemAt() all trigger data binding.
Binding to arrays
You often bind arrays to the dataProvider property of Flex controls, as the following example shows for the List
control:
<?xml version="1.0"?>
<!-- binding/ArrayBindingDP.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var myAC:ArrayCollection = new ArrayCollection([
"One", "Two", "Three", "Four"]);
[Bindable]
public var myAC2:ArrayCollection = new ArrayCollection([
"Uno", "Dos", "Tres", "Quatro"]);
]]>
</mx:Script>
This example defines an ArrayCollection object, and then uses data binding to set the data provider of the List
control to the ArrayCollection. When you modify an element of the ArrayCollection object, or when you modify
a reference to the ArrayCollection object, you trigger a data binding.
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var myAC:ArrayCollection = new ArrayCollection([
"One", "Two", "Three", "Four"]);
[Bindable]
public var myAC2:ArrayCollection = new ArrayCollection([
"Uno", "Dos", "Tres", "Quatro"]);
]]>
</mx:Script>
<mx:Button id="button1"
label="Change Element"
click="myAC[0]='new One'"/>
<mx:Button id="button2"
label="Change ArrayCollection"
click="myAC=myAC2"/>
</mx:Application>
If you specify an array element as the source of a data binding expression by using the square bracket syntax, [],
data binding is only triggered when the application starts and when the array or a reference to the array is updated;
data binding is not triggered when the individual array element is updated.
However, the data binding expression myAC.getItemAt(0) is triggered when an array element changes.
Therefore, the text2 Text control is updated when you click button1, while text1 is not. When using an array
element as the source of a data binding expression, you should use the ArrayCollection.getItemAt() method
in the binding expression.
ADOBE FLEX 3 1243
Adobe Flex 3 Developer Guide
Clicking button2 copies myAC2 to myAC, and triggers all data bindings to array elements regardless of how you
implemented them.
<mx:Model id="myModel">
<myModel>
<!-- Perform simple property binding. -->
<a>{nameInput.text}</a>
<!-- Perform string concatenation. -->
<b>This is {nameInput.text}</b>
<!-- Perform a calculation. -->
<c>{(Number(numberInput.text)) * 6 / 7}</c>
<!-- Perform a conditional operation using a ternary operator. -->
<d>{(isMale.selected) ? "Mr." : "Ms."} {nameInput.text}</d>
</myModel>
</mx:Model>
<mx:Form>
<mx:FormItem label="Last Name:">
<mx:TextInput id="nameInput"/>
</mx:FormItem>
<mx:FormItem label="Select sex:">
<mx:RadioButton id="isMale"
1244 CHAPTER 40
label="Male"
groupName="gender"
selected="true"/>
<mx:RadioButton id="isFemale"
label="Female"
groupName="gender"/>
</mx:FormItem>
<mx:FormItem label="Enter a number:">
<mx:TextInput id="numberInput" text="0"/>
</mx:FormItem>
</mx:Form>
<mx:Text
text="{'Calculation: '+numberInput.text+' * 6 / 7 = '+myModel.c}"/>
<mx:Text text="{'Conditional: '+myModel.d}"/>
</mx:Application>
<mx:Script>
<![CDATA[
public function whatDogAte():String {
return "homework";
}
]]>
</mx:Script>
<mx:Binding
source="'The dog ate my '+ whatDogAte()"
destination="field1.text"/>
<mx:Binding
source="{'The dog ate my '+ whatDogAte()}"
destination="field2.text"/>
<mx:Binding
source="The dog ate my {whatDogAte()}"
destination="field3.text"/>
<mx:TextArea id="field1"/>
<mx:TextArea id="field2"/>
<mx:TextArea id="field3"/>
</mx:Application>
The source property in the following example is not valid because it is not an ActionScript expression:
<mx:Binding source="The dog ate my homework" destination="field1.text"/>
ADOBE FLEX 3 1245
Adobe Flex 3 Developer Guide
<mx:Script>
<![CDATA[
[Bindable]
public var xdata:XML = <order>
<item id = "3456">
<description>Big Screen Television</description>
<price>1299.99</price><quantity>1</quantity>
</item>
<item id = "56789">
<description>DVD Player</description>
<price>399.99</price>
<quantity>1</quantity>
</item>
</order>;
]]>
</mx:Script>
1246 CHAPTER 40
<mx:Script>
<![CDATA[
[Bindable]
public var xdata:XML =
<order>
<item id = "3456">
<description>Big Screen Television</description>
<price>1299.99</price><quantity>1</quantity>
</item>
<item id = "56789">
<description>DVD Player</description>
<price>399.99</price>
<quantity>1</quantity>
</item>
</order>;
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import mx.binding.utils.*;
import mx.events.FlexEvent;
<mx:Script>
<![CDATA[
import mx.binding.utils.*;
import mx.events.FlexEvent;
import mx.events.PropertyChangeEvent;
ADOBE FLEX 3 1249
Adobe Flex 3 Developer Guide
If you omit the event name, Flex automatically creates an event named propertyChange of type PropertyChan-
geEvent.
You can use the [Bindable] metadata tag in three places:
1 Before a public class definition.
The [Bindable] metadata tag makes usable as the source of a binding expression all public properties that
you defined as variables, and all public properties that are defined by using both a setter and a getter method.
In this case, [Bindable] takes no parameters, as the following example shows:
[Bindable]
public class TextAreaFontControl extends TextArea {}
The Flex compiler automatically generates an event named propertyChange, of type PropertyChangeEvent,
for all public properties so that the properties can be used as the source of a data binding expression.
If the property value remains the same on a write, Flex does not dispatch the event or update the property,
where not the same translates to the following test:
(oldValue !== value)
That means if a property contains a reference to an object, and that reference is modified to reference a
different but equivalent object, the binding is triggered. If the property is not modified, but the object that it
points to changes internally, the binding is not triggered.
Note: When you use the [Bindable] metadata tag before a public class definition, it only applies to public
properties; it does not apply to private or protected properties, or to properties defined in any other namespace.
You must insert the [Bindable] metadata tag before a nonpublic property to make it usable as the source for a
data binding expression.
2 Before a public, protected, or private property defined as a variable to make that specific property support
binding.
The tag can have the following forms:
[Bindable]
public var foo:String;
The Flex compiler automatically generates an event named propertyChange, of type PropertyChangeEvent,
for the property. If the property value remains the same on a write, Flex does not dispatch the event or update
the property.
You can also specify the event name, as the following example shows:
[Bindable(event="fooChanged")]
public var foo:String;
In this case, you are responsible for generating and dispatching the event, typically as part of some other
method of your class. You can specify a [Bindable] tag that includes the event specification if you want to
name the event, even when you already specified the [Bindable] tag at the class level.
ADOBE FLEX 3 1251
Adobe Flex 3 Developer Guide
// Get method.
public function get shortNames():Boolean {
...
}
In this case, you are responsible for generating and dispatching the event, typically in the setter method, and
Flex does not check to see if the old value and the new value are different. You can specify a [Bindable] tag
that includes the event specification to name the event, even when you already specified the [Bindable] tag
at the class level.
The following example makes the maxFontSize and minFontSize properties that you defined as variables that
can be used as the sources for data bindings:
// Define public vars for tracking font size.
[Bindable]
public var maxFontSize:Number = 15;
[Bindable]
public var minFontSize:Number = 5;
1252 CHAPTER 40
In the following example, you make a public property that you defined by using a setter and a getter method that
is usable as the source for data binding The [Bindable] metadata tag includes the name of the event broadcast
by the setter method when the property changes:
// Define private variable.
private var _maxFontSize:Number = 15;
[Bindable(event="maxFontSizeChanged")]
// Define public getter method.
public function get maxFontSize():Number {
return _maxFontSize;
}
You can automatically use a static constant as the source for a data-binding expression. Flex performs the data
binding once when the application starts. Because the data binding occurs only once at application start up, you
omit the [Bindable] metadata tag for the static constant. The following example uses a static constant as the
source for a data-binding expression:
<?xml version="1.0"?>
<!-- binding/StaticBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
// This syntax casues a compiler error.
// [Bindable]
// public static var varString:String="A static var.";
Topics
About data models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1257
Defining a data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1257
Specifying an external source for an <mx:Model> tag or <mx:XML> tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1261
Using validators with a data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1262
Using a data model as a value object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1263
Binding data into an XML data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1265
Note: The <mx:Model> and <mx:XML> tags are Flex compiler tags and do not correspond directly to ActionScript
classes. The Adobe Flex Language Reference contains information about these tags and other compiler tags. Click the
Appendixes link on the main page in the Adobe Flex Language Reference.
You can place an <mx:Model> tag or an <mx:XML> tag in a Flex application file or in an MXML component file.
The tag should have an id value, and it cannot be the root tag of an MXML component.
</mx:Model>
</mx:Application>
Script-based models
As an alternative to using an MXML-based model, you can define a model as a variable in an <mx:Script> tag.
The following example shows a very simple model defined in an ActionScript script block. It would be easier to
declare this model in an <mx:Model> tag.
<?xml version="1.0"?>
<!-- Models\ScriptModel.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
[Bindable]
public var myEmployee:Object={
name:{
first:null,
last:null
},
department:null,
email:null
};
]]>
</mx:Script>
</mx:Application>
There is no advantage to using a script-based model instead of an MXML-based model. As with MXML-based
models, you cannot type the properties of a script-based model. To type properties, you must use a class-based
model.
Class-based models
Using an ActionScript class as a model is a good option when you want to store complex data structures with typed
properties, or when you want to execute client-side business logic by using application data. Also, the type infor-
mation in a class-based model is retained on the server when the model is passed to a server-side data service.
1260 CHAPTER 41
The following example shows a model defined in an ActionScript class. This model is used to store shopping cart
items in an e-commerce application. It also provides business logic in the form of methods for adding and
removing items, getting an item count, and getting the total price. For more information on ActionScript compo-
nents, see Creating and Extending Adobe Flex 3 Components.
package
{
[Bindable]
public class ShoppingCart {
public var items:Array = [];
public var total:Number = 0;
This component is in the same directory as the MXML file, as indicated by the XML namespace value *. For more
information about specifying the location of components, see Creating and Extending Adobe Flex 3 Components.
</employee>
</employees>
<mx:Script>
<![CDATA[
[Bindable]
public var tent:Object;
]]>
</mx:Script>
<mx:Style>
.title{fontFamily:Arial;fontWeight:bold;color:#3D3D3D;fontSize:16pt;}
.flabelColor
{fontFamily:Arial;fontWeight:bold;color:#3D3D3D;fontSize:11pt}
.productSpec{fontFamily:Arial;color:#5B5B5B;fontSize:10pt}
</mx:Style>
<mx:HRule width="209"/>
</mx:VBox>
</mx:Panel>
Topics
Validating data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1267
Using validators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1271
General guidelines for validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1284
Working with validation errors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1287
Working with validation events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1290
Using standard validators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1293
Validating data
The data that a user enters in a user interface might or might not be appropriate to the application. In Flex, you
use a validator to ensure the values in the fields of an object meet certain criteria. For example, you can use a
validator to ensure that a user enters a valid phone number value, to ensure that a String value is longer than a set
minimum length, or ensure that a ZIP code field contains the correct number of digits.
In typical client-server environments, data validation occurs on the server after data is submitted to it from the
client. One advantage of using Flex validators is that they execute on the client, which lets you validate input data
before transmitting it to the server. By using Flex validators, you eliminate the need to transmit data to and receive
error messages back from the server, which improves the overall responsiveness of your application.
Note: Flex validators do not eliminate the need to perform data validation on the server, but provide a mechanism
for improving performance by performing some data validation on the client.
Flex includes a set of validators for common types of user input data, including the following:
• Validating credit card numbers
• Validating currency
• Validating dates
• Validating e-mail addresses
• Validating numbers
• Validating phone numbers
1268 CHAPTER 42
About validators
You define validators by using MXML or ActionScript. You declare a validator in MXML by using the
<mx:Validator> tag or the tag for the appropriate validator type. For example, to declare the standard Phone-
NumberValidator validator, you use the <mx:PhoneNumberValidator> tag, as the following example shows:
<?xml version="1.0"?>
<!-- validators\PNValidator.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
ADOBE FLEX 3 1269
Adobe Flex 3 Developer Guide
// Import PhoneNumberValidator.
import mx.validators.PhoneNumberValidator;
<!-- Define the TextInput control for entering the phone number. -->
<mx:TextInput id="phoneInput" creationComplete="createValidator();"/>
<mx:TextInput id="zipCodeInput"/>
</mx:Application>
<mx:ZipCodeValidator id="zipV"
source="{myZip}"
property="text"/>
<mx:TextInput id="phoneInput"/>
<mx:TextInput id="myZip"/>
</mx:Application>
In this example, you use the Flex ZipCodeValidator to validate the data entered in a TextInput control. The
TextInput control stores the input data in its text property.
1270 CHAPTER 42
Alternatively, Flex components dispatch valid and invalid events, depending on the results of the validation.
This lets you listen for the events being dispatched from the component being validated, rather than listening for
events dispatched by the validator.
You are not required to listen for validation events. By default, Flex handles a failed validation by drawing a red
box around the control that is associated with the source of the data binding. For a successful validation, Flex
clears any indicator of a previous failure. For more information, see “Working with validation events” on
page 1290.
Using validators
Triggering validation by using events
You can trigger validators automatically by associating them with an event. In the following example, the user
enters a ZIP code in a TextInput control, and then triggers validation by clicking the Button control:
<?xml version="1.0"?>
<!-- validators\ZCValidatorTriggerEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:ZipCodeValidator id="zipV"
source="{myZip}"
property="text"
trigger="{mySubmit}"
triggerEvent="click"/>
<mx:TextInput id="myZip"/>
<mx:Button id="mySubmit" label="Submit"/>
</mx:Application>
This example uses the trigger and triggerEvent properties of the ZipCodeValidator class to associate an event
with the validator. These properties have the following values:
trigger Specifies the component generating the event that triggers the validator. If omitted, by default Flex uses
the value of the source property.
1272 CHAPTER 42
triggerEvent Specifies the event that triggers the validation. If omitted, Flex uses the valueCommit event. Flex
dispatches the valueCommit event whenever the value of a control changes. Usually this is when the user removes
focus from the component, or when a property value is changed programmatically. If you want a validator to
ignore all events, set triggerEvent to an empty string ("").
For information on specific validator classes, see “Using standard validators” on page 1293.
<mx:ZipCodeValidator id="zipV"
source="{myZip}"
property="text"/>
<mx:TextInput id="myZip"/>
<mx:Button id="mySubmit" label="Submit"/>
</mx:Application>
By omitting the trigger and triggerEvent properties, Flex triggers the validator when the TextInput control
dispatches the valueCommit event. Flex controls dispatch the valueCommit event when its values changes by user
interaction or programmatically.
<!-- Define a data model for storing the phone number. -->
<mx:Model id="userInfo">
<phoneInfo>
<phoneNum>{phoneInput.text}</phoneNum>
</phoneInfo>
</mx:Model>
<!-- Define the TextInput control for entering the phone number. -->
<mx:TextInput id="phoneInput"/>
ADOBE FLEX 3 1273
Adobe Flex 3 Developer Guide
<mx:TextInput id="zipCodeInput"/>
</mx:Application>
You can use a validator along with a data binding to validate either the source or destination of the data binding,
as the following example shows:
<?xml version="1.0"?>
<!-- validators\ValTriggerWithDataBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- Define a data model for storing the phone number. -->
<mx:Model id="userInfo">
<phoneInfo>
<phoneNum>{phoneInput.text}</phoneNum>
</phoneInfo>
</mx:Model>
<!-- Define the TextInput control for entering the phone number. -->
<mx:TextInput id="phoneInput"/>
<mx:TextInput id="zipCodeInput"/>
</mx:Application>
This example uses a PhoneNumberValidator to validate the data entered in the TextInput control. In this example,
the following occurs:
• You assign the validator to the source of the data binding.
• You use the default event, valueCommit, on the TextInput control to trigger the validator. This means the
validator executes when the user removes focus from the TextInput control by selecting the TextInput control for
the ZIP code.
• Flex updates the destination of the data binding on every change to the source. This means that the
userInfo.phoneNum field updates on every change to the TextInput control, while the validator executes only
when the user removes focus from the TextInput control to trigger the valueCommit event. You can use the
validator’s triggerEvent property to specify a different event to trigger the validation.
In a model-view-controller (MVC) design pattern, you isolate the model from the view and controller portions of
the application. In the previous example, the data model represents the model, and the TextInput control and
validator represents the view.
The TextInput control is not aware that its data is bound to the data model, or that there is any binding on it at all.
Since the validator is also assigned to the TextInput control, you have kept the model and view portions of your
application separate and can modify one without affecting the other.
1274 CHAPTER 42
However, there is nothing in Flex to prohibit you from assigning a validator to the data model, as the following
example shows:
<?xml version="1.0"?>
<!-- validators\ValTriggerWithDataBindingOnModel.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- Define a data model for storing the phone number. -->
<mx:Model id="userInfo">
<phoneInfo>
<phoneNum>{phoneInput.text}</phoneNum>
</phoneInfo>
</mx:Model>
<!-- Define the TextInput control for entering the phone number. -->
<mx:TextInput id="phoneInput"/>
<mx:TextInput id="zipCodeInput"/>
</mx:Application>
In this example, you trigger the data validator by using the valueCommit event of the TextInput control, but assign
the validator to a field of the data model, rather than to a property of the TextInput control.
This example also uses the listener property of the validator. This property configures the validator to display
validation error information on the specified object, rather than on the source of the validation. In this example,
the source of the validation is a model, so you display the visual information on the TextInput control that
provided the data to the model. For more information, see “Specifying a listener for validation” on page 1290.
If the model has a nesting structure of elements, you use dot-delimited Strings with the source property to specify
the model element to validate, as the following example shows:
<?xml version="1.0"?>
<!-- validators\ValTriggerWithDataBindingComplexModel.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<!-- Define a data model for storing the phone number. -->
<mx:Model id="userInfo">
<user>
<phoneInfo>
<homePhoneNum>{homePhoneInput.text}</homePhoneNum>
<cellPhoneNum>{cellPhoneInput.text}</cellPhoneNum>
</phoneInfo>
</user>
</mx:Model>
trigger="{homePhoneInput}"
listener="{homePhoneInput}"/>
<!-- Define the TextInput controls for entering the phone number. -->
<mx:Label text="Home Phone:"/>
<mx:TextInput id="homePhoneInput"/>
In the following example, you create and invoke a validator programmatically in when a user clicks a Button
control:
<?xml version="1.0"?>
<!-- validators\ValTriggerProg.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
// Import ZipCodeValidator.
import mx.validators.ZipCodeValidator;
<mx:TextInput id="myZip"/>
<mx:Button label="Submit" click="performValidation();"/>
</mx:Application>
Notice that you are still using an event to trigger the performValidation() function that creates and invokes the
validator, but the event itself does not automatically invoke the validator.
Any errors in the validator are shown on the associated component, just as if you had triggered the validation
directly by using an event.
<mx:Script>
<![CDATA[
import mx.validators.ZipCodeValidator;
if (vResult.type==ValidationResultEvent.VALID) {
// Validation succeeded.
myTA.text='OK';
}
else {
// Validation failed.
myTA.text='Fail';
}
}
]]>
</mx:Script>
<mx:TextInput id="myZip"/>
<mx:Button label="Submit" click="performValidation();"/>
<mx:TextArea id="myTA"/>
</mx:Application>
The ValidationResultEvent class has additional properties that you can use when processing validation events. For
more information, see “Working with validation events” on page 1290.
<mx:Model id="date">
<dateInfo>
<month>{monthInput.text}</month>
<day>{dayInput.text}</day>
<year>{yearInput.text}</year>
</dateInfo>
</mx:Model>
<mx:Script>
<![CDATA[
<mx:Model id="person">
<userInfo>
<zipCode>{zipCodeInput.text}</zipCode>
<phoneNumber>{phoneNumberInput.text}</phoneNumber>
</userInfo>
</mx:Model>
<mx:Form>
<!-- Collect input data -->
<mx:TextInput id="zipCodeInput"/>
<mx:TextInput id="phoneNumberInput"/>
</mx:Form>
<mx:Button label="Validate"
click="validateZipPhone();"/>
</mx:Application>
In this example, you use the predefined ZipCodeValidator and PhoneNumberValidator to validate user infor-
mation as the user enters it. Then, when the user clicks the Submit button to submit the form, you validate that
the ZIP code is actually within the specified area code of the phone number.
You can also use the static Validator.validateAll() method to invoke all of the validators in an Array. This
method returns an Array containing one ValidationResultEvent object for each validator that failed, and an empty
Array if all validators succeed. The following example uses this method to invoke two validators in response to the
click event for the Button control:
<?xml version="1.0"?>
<!-- validators\ValidatorMultipleValids.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initValidatorArray();">
1280 CHAPTER 42
<mx:Script>
<![CDATA[
import mx.validators.Validator;
<mx:Model id="person">
<userInfo>
<zipCode>{zipCodeInput.text}</zipCode>
<phoneNumber>{phoneNumberInput.text}</phoneNumber>
</userInfo>
</mx:Model>
<mx:Form>
<!-- Collect input data -->
<mx:TextInput id="zipCodeInput"/>
<mx:TextInput id="phoneNumberInput"/>
</mx:Form>
<mx:Button label="Validate"
click="Validator.validateAll(myValidators);"/>
</mx:Application>
<mx:Script>
<![CDATA[
import flash.events.Event;
zipV.validate(eventObj.currentTarget.text);
}
]]>
</mx:Script>
<mx:ZipCodeValidator id="zipV"
triggerEvent=""/>
<mx:TextInput id="shippingZip"
focusOut="performValidation(event);"/>
<mx:TextInput id="billingZip"
focusOut="performValidation(event);"/>
</mx:Application>
In this example, you have two address areas for a customer: one for a billing address and one for a shipping
address. Both addresses have a ZIP code field, so you can reuse a single ZipCodeValidator for both fields. The
event listener for the focusOut event passes the field to validate to the validate() method.
Alternatively, you can write the performValidation() function as the following example shows:
<?xml version="1.0"?>
<!-- validators\ReusableValsSpecifySource.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import flash.events.Event;
<mx:ZipCodeValidator id="zipV"
triggerEvent=""/>
<mx:TextInput id="shippingZip"
focusOut="performValidation(event);"/>
<mx:TextInput id="billingZip"
focusOut="performValidation(event);"/>
</mx:Application>
<?xml version="1.0"?>
<!-- validators\ConditionalVal.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ValidationResultEvent;
<mx:ZipCodeValidator id="zipUS"
domain="US Only"
listener="{zipInput}"/>
<mx:ZipCodeValidator id="zipCN"
domain="US or Canada"
listener="{zipInput}"/>
<mx:RadioButtonGroup id="country"/>
<mx:RadioButton groupName="country" label="US"/>
<mx:RadioButton groupName="country" label="Canada"/>
<mx:TextInput id="zipInput"/>
<mx:StringValidator id="reqV"
source="{inputA}"
property="text"
required="true"/>
<mx:TextInput id="inputA"/>
<mx:Button label="Submit"
click="reqV.validate();"/>
</mx:Application>
In this example, the StringValidator executes when the following occurs:
• The TextInput control dispatches the valueCommit event. However, to dispatch that event, the user must give
the TextInput control focus, and then remove focus. If the user never gives the TextInput control focus, the
validator does not trigger, and Flex does not recognize that the control is empty. Therefore, you must call the
validate() method to ensure that the validator checks for missing data.
• The user clicks the Button control. The validator issues a validation error when the user does not enter any
data into the TextInput control. It also issues a validation error if the user enters an invalid String value.
<mx:ZipCodeValidator id="zcVal"
source="{inputA}"
property="text"
required="true"
enabled="{enableV.selected}"/>
<mx:TextInput id="inputA"/>
<mx:TextInput/>
<mx:CheckBox id="enableV"
label="Validate input?"/>
</mx:Application>
In this example, you enable the validator only when the user selects the CheckBox control.
1284 CHAPTER 42
<mx:NumberValidator
source="{inputA}"
property="text"
minValue="{Number(inputMin.text)}"
maxValue="{Number(inputMax.text)}"/>
<mx:TextInput id="inputA"/>
<mx:TextInput id="inputMin" text="1"/>
<mx:TextInput id="inputMax" text="10"/>
</mx:Application>
In this example, you use data binding to configure the properties of the validators.
• Define a Submit button to invoke any validators before submitting data to a server. Typically, you use the
click event of the Button control to invoke validators programmatically, and then submit the data if all validation
succeeds.
The following example uses many of these guidelines to validate a form made up of several TextInput controls:
<?xml version="1.0"?>
<!-- validators\FullApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ValidationResultEvent;
vResult = lNameV.validate();
if (vResult.type==ValidationResultEvent.INVALID)
return;
// Since the date requires 3 fields, perform the validation
// when the Submit button is clicked.
vResult = dayV.validate();
if (vResult.type==ValidationResultEvent.INVALID)
return;
// Invoke any other validators or validation logic to make
// an additional check before submitting the data.
• The validateAndSubmit() function invokes the DateValidator because it requires three different input
fields.
• Upon detecting the first validation error, the validateAndSubmit() function returns but does not submit
the data.
• When all validations succeed, the validateAndSubmit() function submits the data to the server.
<!-- Define the TextInput control for entering the phone number. -->
<mx:TextInput id="phoneInput"/>
<mx:TextInput id="zipCodeInput"/>
</mx:Application>
1288 CHAPTER 42
<!-- Define the TextInput control for entering the phone number. -->
<mx:TextInput id="phoneInput"/>
<mx:TextInput id="zipCodeInput"/>
</mx:Application>
In this example, the error message appears as light green.
For example, you might provide a form to gather user input. Within your form, you might also provide a button,
or other mechanism, that lets the user reset the form. However, clearing form fields that are tied to validators could
trigger a validation error. The following example uses the errorString property as part of resetting the text
property of a TextInput control to prevent validation errors when the form resets:
<?xml version="1.0"?>
<!-- validators\ResetVal.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ValidationResultEvent;
private var vResult:ValidationResultEvent;
<mx:ZipCodeValidator id="zipV"
source="{zipInput}"
property="text"/>
<mx:Form>
<mx:FormItem label="Enter ZIP code">
<mx:TextInput id="zipInput"/>
</mx:FormItem>
<mx:FormItem label="Enter Country">
<mx:TextInput id="cntryInput"/>
</mx:FormItem>
</mx:Form>
<mx:ZipCodeValidator id="zipV"
source="{zipCodeInput}"
property="text"
listener="{errorMsg}"/>
<mx:TextInput id="zipCodeInput"/>
<mx:TextArea id="errorMsg"/>
</mx:Application>
<mx:Script>
<![CDATA[
<mx:TextInput id="phoneInput"
initialize="myCreationComplete(event);"
invalid="handleInvalidVal(event);"
valid="handleValidVal(event);"/>
<mx:TextInput id="zipInput"/>
</mx:Application>
<mx:Script>
<![CDATA[
]]>
</mx:Script>
<mx:ZipCodeValidator
source="{inputZip}" property="text"
valid="handleValid(event);"
invalid="handleValid(event);"/>
<mx:TextInput id="inputZip"/>
<mx:TextInput id="inputPn"/>
<mx:Button id="submitButton"
label="Submit"
enabled="false"
click="submitForm();"/>
</mx:Application>
In this example, the Button control is disabled until the TextInput field contains a valid ZIP code. The type
property of the event object is either ValidationResultEvent.VALID or ValidationResultEvent.INVALID,
based on the result of the validation.
Within the event listener, you can use all the properties of the ValidationResultEvent class, including the
following:
field A String that contains the name of the field that failed validation and triggered the event.
message A String that contains all the validator error messages created by the validation.
results An Array of ValidationResult objects, one for each field examined by the validator. For a successful
validation, the ValidationResultEvent.results Array property is empty. For a validation failure, the
ValidationResultEvent.results Array property contains one ValidationResult object for each field checked
by the validator, both for fields that failed the validation and for fields that passed. Examine the
ValidationResult.isError property to determine if the field passed or failed the validation.
ADOBE FLEX 3 1293
Adobe Flex 3 Developer Guide
The following example validates a credit card number based on the card type that the users specifies. Any
validation errors propagate to the Application object and open an Alert window.
<?xml version="1.0"?>
<!-- validators\CCExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:CreditCardValidator id="ccV"
cardTypeSource="{cardTypeCombo.selectedItem}"
cardTypeProperty="data"
cardNumberSource="{cardNumberInput}"
cardNumberProperty="text"/>
<mx:Form id="creditCardForm">
<mx:FormItem label="Card Type">
<mx:ComboBox id="cardTypeCombo">
<mx:dataProvider>
<mx:Object label="American Express"
data="American Express"/>
<mx:Object label="Diners Club"
data="Diners Club"/>
<mx:Object label="Discover"
data="Discover"/>
<mx:Object label="MasterCard"
data="MasterCard"/>
<mx:Object label="Visa"
data="Visa"/>
</mx:dataProvider>
</mx:ComboBox>
</mx:FormItem>
<mx:FormItem label="Credit Card Number">
<mx:TextInput id="cardNumberInput"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Check Credit" click="ccV.validate();"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
The following example performs a similar validation, but uses the source and property properties to specify an
object that contains the credit card information. In this example, you use the listener property to configure the
validator to display validation error information on the TextInput control:
<?xml version="1.0"?>
<!-- validators\CCExampleSource.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
[Bindable]
public var ccObj:Object = {cardType:String, cardNumber:String};
ccObj.cardNumber = cardNumberInput.text;
// Validate ccObj.
ccV.validate();
}
]]>
</mx:Script>
<mx:CreditCardValidator id="ccV"
source="{this}"
property="ccObj"
listener="{cardNumberInput}"/>
<mx:Form id="creditCardForm">
<mx:FormItem label="Card Type">
<mx:ComboBox id="cardTypeCombo">
<mx:dataProvider>
<mx:Object label="American Express"
data="American Express"/>
<mx:Object label="Diners Club"
data="Diners Club"/>
<mx:Object label="Discover"
data="Discover"/>
<mx:Object label="MasterCard"
data="MasterCard"/>
<mx:Object label="Visa"
data="Visa"/>
</mx:dataProvider>
</mx:ComboBox>
</mx:FormItem>
<mx:FormItem label="Credit Card Number">
<mx:TextInput id="cardNumberInput"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Check Credit" click="valCC();"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
Validating currency
The CurrencyValidator class checks that a string is a valid currency expression based on a set of parameters. The
CurrencyValidator class defines the properties that let you specify the format of the currency value, whether to
allow negative values, and the precision of the values.
The following example uses the CurrencyValidator class to validate a currency value entered in U.S. dollars and
in Euros:
<?xml version="1.0"?>
<!-- validators\CurrencyExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
trigger="{valButton}"
triggerEvent="click"/>
Validating dates
The DateValidator class validates that a String, Date, or Object contains a proper date and matches a specified
format. Users can enter a single digit or two digits for month, day, and year. By default, the validator ensures that
the following information is provided:
• The month is between 1 and 12 (or 0-11 for Date objects)
• The day is between 1 and 31
• The year is a number
If you specify a single String to validate, the String can contain digits and the formatting characters that the
allowedFormatChars property specifies, including the slash (/), backslash (\), dash (-), and period (.) characters.
By default, the input format of the date in a String is “mm/dd/yyyy” where “mm” is the month, “dd” is the day, and
“yyyy” is the year. You can use the inputFormat property to specify a different format.
You can also specify to validate a date represented by a single Object, or by multiple fields of different objects. For
example, you could use a data model that contains three fields that represent the day, month, and year portions of
a date, or three TextInput controls that let a user enter a date as three separate fields. Even if you specify a date
format that excludes a day, month, or year element, you must specify all three fields to the validator.
ADOBE FLEX 3 1297
Adobe Flex 3 Developer Guide
The following table describes how to specify the date to the DateValidator:
String object containing the Use the source and property Flex associates error messages with the field specified by the
date properties to specify the String. property property.
Date object containing the Use the source and property Flex associates error messages with the field specified by the
date properties to specify the Date. property property.
Object or multiple fields Use all of the following properties Flex associates error messages with the field specified by the
containing the day, month, to specify the day, month, and daySource, monthSource, and yearSource properties,
and year year inputs: daySource, depending on the field that caused the validation error.
dayProperty, monthSource,
monthProperty, yearSource,
and yearProperty.
<mx:DateValidator id="dateV"
daySource="{dayInput}" dayProperty="text"
monthSource="{monthInput}" monthProperty="text"
yearSource="{yearInput}" yearProperty="text"/>
<mx:Form >
<mx:FormItem label="Month">
<mx:TextInput id="monthInput"/>
</mx:FormItem>
<mx:FormItem label="Day">
<mx:TextInput id="dayInput"/>
</mx:FormItem>
<mx:FormItem label="Year">
<mx:TextInput id="yearInput"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Check Date" click="dateV.validate();"/>
</mx:FormItem>
</mx:Form>
<!-- Alternate method for a single field containing the date. -->
<mx:Model id="alternateDate">
<dateInfo>
<date>{dateInput.text}</date>
</dateInfo>
</mx:Model>
<mx:DateValidator id="stringDateV"
source="{dateInput}" property="text"
inputFormat="dd/mm/yyyy"
allowedFormatChars="*#~/"/>
1298 CHAPTER 42
<mx:Form>
<mx:FormItem label="Date of Birth (dd/mm/yyyy)">
<mx:TextInput id="dateInput"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Check Date" click="stringDateV.validate();"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
In the next example, you validate a Date object:
<?xml version="1.0"?>
<!-- validators\DateObjectExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
// myDate is set to the current date and time.
[Bindable]
public var myDate:Date = new Date();
]]>
</mx:Script>
<mx:DateValidator id="dateV"
source="{this}" property="myDate"
valid="Alert.show('Validation Succeeded!');"/>
<mx:Form id="contactForm">
<mx:FormItem id="homePhoneItem" label="Home Phone">
<mx:TextInput id="homePhoneInput"/>
</mx:FormItem>
<mx:FormItem id="cellPhoneItem" label="Cell Phone">
<mx:TextInput id="cellPhoneInput"/>
</mx:FormItem>
<mx:FormItem id="emailItem" label="Email">
ADOBE FLEX 3 1299
Adobe Flex 3 Developer Guide
<mx:TextInput id="emailInput"/>
</mx:FormItem>
</mx:Form>
<mx:PhoneNumberValidator id="pnVHome"
source="{homePhoneInput}" property="text"/>
<mx:PhoneNumberValidator id="pnVCell"
source="{cellPhoneInput}" property="text"/>
<mx:EmailValidator id="emV"
source="{emailInput}" property="text"/>
</mx:Application>
Validating numbers
The NumberValidator class ensures that a string represents a valid number. This validator can ensure that the
input falls within a given range (specified by the minValue and maxValue properties), is an integer (specified by
the domain property), is non-negative (specified by the allowNegative property), and does not exceed the
specified precision. The NumberValidator correctly validates formatted numbers (for example, "12,345.67"), and
you can customize its thousandsSeparator and decimalSeparator properties for internationalization.
The following example uses the NumberValidator class to ensure that an integer is between 1 and 10:
<?xml version="1.0"?>
<!-- validators\NumberExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Form >
<mx:FormItem
label="Number of Widgets (max 10 per customer)">
<mx:TextInput id="quantityInput"/>
</mx:FormItem>
<mx:FormItem >
<mx:Button label="Submit"/>
</mx:FormItem>
</mx:Form>
<mx:NumberValidator id="numV"
source="{quantityInput}" property="text"
minValue="1" maxValue="10" domain="int"/>
</mx:Application>
<mx:Form id="contactForm">
<mx:FormItem id="homePhoneItem" label="Home Phone">
<mx:TextInput id="homePhoneInput"/>
</mx:FormItem>
<mx:FormItem id="cellPhoneItem" label="Cell Phone">
<mx:TextInput id="cellPhoneInput"/>
</mx:FormItem>
<mx:FormItem id="emailItem" label="Email">
<mx:TextInput id="emailInput"/>
</mx:FormItem>
</mx:Form>
<mx:PhoneNumberValidator id="pnVHome"
source="{homePhoneInput}" property="text"/>
<mx:PhoneNumberValidator id="pnVCell"
source="{cellPhoneInput}" property="text"/>
<mx:EmailValidator id="emV"
source="{emailInput}" property="text"/>
</mx:Application>
<?xml version="1.0"?>
<!-- validators\RegExpExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ValidationResultEvent;
import mx.validators.*;
<mx:Form>
<mx:FormItem label="Search string">
<mx:TextInput id="exp"/>
</mx:FormItem>
<mx:FormItem label="Regular expression">
<mx:TextInput id="source" text="ABC\d"/>
</mx:FormItem>
<mx:FormItem label="Results">
<mx:TextArea id="myTA"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
In this example, you specify the regular expression in the TextInput control named source, and bind it to the
expression property of the validator. You can modify the regular expression by entering a new expression in the
TextInput control. A value of g for the flags property specifies to find multiple matches in the input field.
1302 CHAPTER 42
The event handler for the valid event writes to the TextArea control the index in the input String and matching
substring of all matches of the regular expression. The invalid event handler clears the TextArea control.
<mx:Form id="identityForm">
<mx:FormItem id="ssnItem" label="Social Security Number">
<mx:TextInput id="ssnField"/>
</mx:FormItem>
<mx:FormItem id="licenseItem" label="Driver's License Number">
<mx:TextInput id="licenseInput"/> <!-- Not validated -->
</mx:FormItem>
</mx:Form>
<mx:SocialSecurityValidator id="ssV"
source="{ssnField}" property="text"/>
</mx:Application>
Validating strings
The StringValidator class validates that a string length is within a specified range. The following example ensures
that a string is between 6 and 12 characters long:
<?xml version="1.0"?>
<!-- validators\StringExample.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Form id="membershipForm">
<mx:FormItem id="fullNameItem" label="Full Name">
<!-- Not validated -->
<mx:TextInput id="fullNameInput"/>
</mx:FormItem>
<mx:FormItem id="userNameItem" label="Username">
<mx:TextInput id="userNameInput"/>
</mx:FormItem>
</mx:Form>
<mx:Form id="addressForm">
<mx:FormItem id="zipCodeItem" label="Zip Code">
<mx:TextInput id="zipInput"/>
</mx:FormItem>
<mx:FormItem id="submitArea">
<mx:Button label="Submit"/>
</mx:FormItem>
</mx:Form>
<mx:ZipCodeValidator id="zipV"
source="{zipInput}" property="text"
domain="US or Canada"/>
</mx:Application>
1304 CHAPTER 42
1305
Topics
Using formatters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1305
Writing an error handler function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1307
Using the standard formatters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1308
Using formatters
Adobe® Flex® formatters are components that you use to format data into strings. Formatters perform a one-way
conversion of raw data to a formatted string. You typically trigger a formatter just before displaying data in a text
field. Flex includes standard formatters that let you format currency, dates, numbers, phone numbers, and ZIP
codes.
All Flex formatters are subclasses of the mx.formatters.Formatter class. The Formatter class declares a format()
method that takes a value and returns a String value.
For most formatters, when an error occurs, an empty string is returned and a string describing the error is written
to the formatter’s error property. The error property is inherited from the Formatter class.
The following steps describe the general process for using a formatter:
1 Declare a formatter in your MXML code, specifying the appropriate formatting properties.
2 Call the formatter’s format() method within the curly braces ({ }) syntax for binding data, and specify the
value to be formatted as a parameter to the format() method.
The following example formats a phone number that a user inputs in an application by using the TextInput
control:
<?xml version="1.0"?>
<!-- formatters\Formatter2TextFields.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
formatString="###-####" />
You do not have to use a format() method within curly braces ({ }) of a binding data expression; you can call this
method from anywhere in your application, typically in response to an event. The following example declares a
DateFormatter with an MM/DD/YYYY date format. The application then writes a formatted date to the text
property of a TextInput control in response to the click event of a Button control:
<?xml version="1.0"?>
<!-- formatters\FormatterDateField.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
<mx:Script>
<![CDATA[
// Define variable to hold the price.
[Bindable]
private var todaysPrice:Number=4025;
]]>
</mx:Script>
Invalid value An invalid numeric value is passed to the format() method. The value should be a valid number in the form of
a Number or a String.
Formatting dates
The DateFormatter class gives you a wide range of combinations for displaying date and time information. The
format() method accepts a Date object, which it converts to a String based on a user-defined pattern. The
format() method can also accept a String-formatted date, which it attempts to parse into a valid Date object prior
to formatting.
The DateFormatter class has a parseDateString() method that accepts a date formatted as a String. The
parseDateString() method examines sections of numbers and letters in the String to build a Date object. The
parser is capable of interpreting long or abbreviated (three-character) month names, time, am and pm, and
various representations of the date. If the parseDateString() method is unable to parse the String into a Date
object, it returns null.
The following examples show some of the ways strings can be parsed:
"12/31/98" or "12-31-98" or "1998-12-31" or "12/31/1998"
"Friday, December 26, 2005 8:35 am"
"Jan. 23, 1989 11:32:25"
The DateFormatter class parses strings from left to right. A date value should appear before the time and must be
included. The time value is optional. A time signature of 0:0:0 is the Date object’s default for dates that are defined
without a time. Time zone offsets are not parsed.
1310 CHAPTER 43
Y Year. If the number of pattern letters is two, the year is truncated to two digits; otherwise, it appears as four digits.
The year can be zero-padded, as the third example shows in the following set of examples:
Examples:
YY = 05
YYYY = 2005
YYYYY = 02005
• If the number of pattern letters is one, the format is interpreted as numeric in one or two digits.
• If the number of pattern letters is two, the format is interpreted as numeric in two digits.
• If the number of pattern letters is three, the format is interpreted as short text.
• If the number of pattern letters is four, the format is interpreted as full text.
Examples:
M=7
MM= 07
MMM=Jul
MMMM= July
D Day in month. While a single-letter pattern string for day is valid, you typically use a two-letter pattern string.
Examples:
D=4
DD=04
DD=10
1312 CHAPTER 43
• If the number of pattern letters is one, the format is interpreted as numeric in one or two digits.
• If the number of pattern letters is two, the format is interpreted as numeric in two digits.
• If the number of pattern letters is three, the format is interpreted as short text.
• If the number of pattern letters is four, the format is interpreted as full text.
Examples:
E=1
EE = 01
EEE = Mon
EEEE = Monday
A am/pm indicator.
N Minute in hour.
Examples:
N=3
NN = 03
S Second in minute.
Examples:
SS = 30
Other text You can add other text into the pattern string to further format the string. You can use punctuation, numbers, and
all lowercase letters. You should avoid uppercase letters because they may be interpreted as pattern letters.
Example:
The following table shows sample pattern strings and the resulting presentation:
Pattern Result
H:NN A 12:08 PM
HH o'clock A 12 o'clock PM
K:NN A 0:08 PM
<mx:Script>
<![CDATA[
// Define variable to hold the date.
[Bindable]
private var today:Date = new Date();
]]>
</mx:Script>
Invalid value A value that is not a Date object is passed to the format() method. (An empty argument is allowed.)
Formatting numbers
The NumberFormatter class provides basic formatting options for numeric data, including decimal formatting,
thousands separator formatting, and negative sign formatting. The format() method accepts a number or a
number formatted as a String value, and formats the resulting string.
When a number formatted as a String value is passed to the format() method, the function parses the string from
left to right and attempts to extract the first sequence of numbers it encounters. The function parses the thousands
separators and decimal separators along with their trailing numbers. The parser searches for a comma (,) for the
thousands separator unless you set a different character in the thousandsSeparatorFrom property. The parser
searches for a period (.) for the decimal separator unless you define a different character in the
decimalSeparator property.
Note: The format() method recognizes a dash (-) immediately preceding the first number in the sequence as a
negative number. A dash, space, and then number sequence are not interpreted as a negative number.
The rounding and precision properties of the NumberFormatter class affect the formatting of the decimal in a
number. If you use both rounding and precision properties, rounding is applied first, and then the decimal
length is set by using the specified precision value. This lets you round a number and still have a trailing decimal;
for example, 303.99 = 304.00.
<mx:Script>
<![CDATA[
// Define variable to hold the number.
ADOBE FLEX 3 1315
Adobe Flex 3 Developer Guide
[Bindable]
private var bigNumber:Number = 6000000000.65;
]]>
</mx:Script>
Invalid value An invalid numeric value is passed to the format() method. The value should be a valid number in the form of
a Number or a String.
The PhoneFormatter formatString property accepts a formatted string as a definition of the format pattern. The
following table shows common options for formatString values. The format() method for the PhoneFormatter
accepts a sequence of numbers. The numbers correspond to the number of placeholder (#) symbols in the
formatString value. The number of placeholder symbols in the formatString property and the number of
digits in the format() method value must match.
In the preceding table, dashes (-) are used as separator elements where applicable. You can substitute period (.)
characters or blank spaces for the dashes. You can change the default allowable character set as needed by using
the validPatternChars property. You can change the default character that represents a numeric placeholder by
using the numberSymbol property (for example, to change from # to $).
Note: A shortcut is provided for the United States seven-digit format. If the areaCode property contains a value and
you use the seven-digit format string, a seven-digit format entry automatically adds the area code to the string
returned. The default format for the area code is (###). You can change this by using the areaCodeFormat property.
You can format the area code any way you want as long as it contains three number placeholders.
<mx:Script>
<![CDATA[
// Define variable to hold the phone number.
[Bindable]
private var newNumber:Number = 1234567;
]]>
</mx:Script>
formatString="###-####"/>
Invalid value • An invalid numeric value is passed to the format() method. The value should be a valid number in the form
of a Number or a String.
• The value contains a different number of digits than what is specified in the format string.
Invalid format • One or more of the characters in the formatString do not match the allowed characters specified in the
validPatternChars property.
• The areaCodeFormat property is specified but does not contain exactly three numeric placeholders.
For United States ZIP codes, if a nine-digit format is requested and a five-digit value is supplied, -0000 is
appended to the value to make it compliant with the nine-digit format. Inversely, if a nine-digit value is supplied
for a five-digit format, the number is truncated to five digits.
For Canadian postal codes, only a six-digit value is allowed for either the formatString or the input value.
Note: For United States ZIP codes, only numeric characters are valid. For Canadian postal codes, alphanumeric
characters are allowed. Alphabetic characters must be in uppercase.
<mx:Script>
<![CDATA[
// Define variable to hold the ZIP code.
[Bindable]
private var storedZipCode:Number=123456789;
]]>
</mx:Script>
Invalid value • An invalid numeric value is passed to the format() method. The value should be a valid number in the form
of a Number or a String, except for Canadian postal codes, which allow alphanumeric values.
• The number of digits does not match the allowed digits from the formatString property.
Invalid format • One or more of the characters in the formatString do not match the allowed characters specified in the
validFormatChars property.