Creating and Extending Flex Components
Creating and Extending Flex Components
® ™
Adobe Flex 3
Creating and Extending Flex Components
Flex 3 Beta 1
© 2007 Adobe Systems Incorporated. All rights reserved.
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, Flex, Flex Builder and Flash Player are either registered trademarks or trademarks of Adobe Systems
Incorporated in the United States and/or other countries. Windows is either a registered trademark or trademark of Microsoft
Corporation in the United States and/or other countries. Macintosh is a trademark of Apple Computer, Inc., registered 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/). Macromedia Flash 8
video is powered by On2 TrueMotion video technology. © 1992-2005 On2 Technologies, Inc. All Rights Reserved. http://
www.on2.com. This product includes software developed by the OpenSymphony Group (http://www.opensymphony.com/).
Portions licensed from Nellymoser (www.nellymoser.com). Portions utilize Microsoft Windows Media Technologies. Copyright
(c) 1999-2002 Microsoft Corporation. All Rights Reserved. Includes DVD creation technology used under license from Sonic
Solutions. Copyright 1996-2005 Sonic Solutions. All Rights Reserved. This Product includes code licensed from RSA Data
Security. Portions copyright Right Hemisphere, Inc. This product includes software developed by the OpenSymphony Group
(http://www.opensymphony.com/).
Sorenson™ Spark™ video compression and decompression technology licensed from Sorenson Media, Inc.
Adobe Systems Incorporated, 345 Park Avenue, San Jose, California 95110, 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. Adobe Systems Incorporated, 345 Park Avenue, San Jose, CA 95110-2704, USA. 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.
Contents
3
Flex 3 Beta 1
4
Flex 3 Beta 1
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
5
Flex 3 Beta 1
6
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
CHAPTER 1
Contents
Using this manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Accessing the Flex documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Part Description
Part 1, “Creating Custom Flex Components” Describes how to create
custom Flex components.
Part 4, “Creating Nonvisual Flex Components” Describes how to create formatter, validator,
and effect components for Flex.
7
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Accessing the Flex documentation
The Flex documentation is designed to provide support for the complete spectrum of
participants.
Documentation set
The Flex documentation set includes the following titles:
Book Description
Getting Started with Flex Contains an overview of Flex features and
application development procedures.
Flex Developer’s Guide Describes how to develop your dynamic web
applications.
Creating and Extending Flex Components Describes how to create and extend
Flex components.
Building and Deploying Flex Applications Describes how to build and deploy
Flex applications.
Adobe Flex Language Reference Provides descriptions, syntax, usage, and code
examples for the Flex API.
Typographical conventions 9
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
PART 1
11
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
CHAPTER 2
Contents
About creating components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Creating custom components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Where to go from here . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
13
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
A common coding practice is to divide an application into functional units, or modules,
where each module performs a discrete task. Dividing your application into modules provides
you with many benefits, including the following:
Ease of development Different developers or development groups can develop and debug
modules independently of each other.
Reusability You can reuse modules in different applications so that you do not have to
duplicate your work.
Maintainability By developing your application in discrete modules, you can isolate and
debug errors faster than you could if you developed your application in a single file.
In Flex, a module corresponds to a custom component, implemented either in MXML or in
ActionScript. The following image shows an example of a Flex application divided into
components:
<mx:Application> ActionScript
classes
<..>
*.AS
*.MXML *.SWF
*.AS
Use <mx:Script>
to write, import,
or include
ActionScript *.AS
<..>
*.MXML
*.AS
SWC and RSL files
UIComponent
VBox
N OTE
For a complete description of the class hierarchy, see the Adobe Flex Language
Reference.
All visual components are derived from the UIComponent ActionScript class. Flex nonvisual
components are also implemented as a class hierarchy in ActionScript. The most commonly
used nonvisual classes are the Validator, Formatter, and Effect base classes.
You create custom components by extending the Flex class hierarchy using the MXML and
ActionScript languages. Components inherit the properties, methods, events, styles, and
effects of their superclasses.
Button.as
MyASButton.as MyMXMLButton.mxml
package <mx:Button>
{
public class MyASButton extends Button <mx:Script>
{
// Override inherited methods
// Override inherited methods // and properties.
// and properties.
// Define new methods
// Define new methods // and properties.
// and properties.
// Define custom logic
// Define custom logic // in ActionScript.
// in ActionScript.
} </mx:Script>
}
<!-- Add MXML code. -->
</mx:Button>
Both implementations create a component as a subclass of the Button class and, therefore,
inherit all of the public and protected properties, methods, and other elements of the Button
class. Within each implementation, you can override inherited items, define new items, and
add your custom logic.
N OTE
You cannot override an inherited property defined by a variable, but you can override a
property defined by setter and getter methods. You can reset the value of an inherited
property defined by a variable. You typically reset it in the constructor of the subclass for
an ActionScript component, or in an event handler for an MXML component because
MXML components cannot define a constructor.
However, when you use MXML, the Flex compiler performs most of the overhead required to
create a subclass of a component for you. This makes it much easier to create components in
MXML than in ActionScript.
The Flash Professional 8 authoring environment does not support ActionScript 3.0.
Therefore, you should not use it to create ActionScript components for Flex 2. Instead,
you should use the Flex Builder IDE.
For more information on custom MXML components, see Chapter 7, “Creating Simple
MXML Components,” on page 77. For more information on ActionScript components, see
Chapter 9, “Creating Simple Visual Components in ActionScript,” on page 121.
<!-- Include the namespace definition for your custom components. -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:MyComp="*">
</mx:Application>
The MXML tag name for a custom component is composed of two parts: the namespace
prefix, in this case MyComp, and the tag name. The namespace prefix tells Flex where to look
for the file that implements the custom component. The tag name corresponds to the
filename of the component, in this case StateComboBox.mxml. Therefore, a file named
StateComboBox.mxml defines a component with the tag name of
<namespace:StateComboBox>.
As part of the <mx:Application> tag, the main application file includes the following
namespace definition: xmlns:MyComp="*". This definition specifies that the component is in
the same directory as the main application file, or in a directory included in the ActionScript
classpath. For more information on deploying MXML components, see Chapter 7, “Creating
Simple MXML Components,” on page 77.
A best practice is to put your custom components in a subdirectory of your application. That
practice helps to ensure that you do not have duplicate component names because they have a
different namespace. If you stored your component in the myComponents subdirectory of
your application, you would specify the namespace definition as
xmlns:MyComp="myComponents.*".
<mx:Script>
<![CDATA[
import flash.events.Event;
</mx:Application>
For more information on MXML components, see “Creating Simple MXML Components”
on page 77.
<!-- Include the namespace definition for your custom components. -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
</mx:Application>
In this example, you first define the MyComp namespace that specifies the location of your
custom component in the application’s directory structure. You then reference the component
as an MXML tag using the namespace prefix.
For more information, see Chapter 9, “Creating Simple Visual Components in ActionScript,”
on page 121.
CHAPTER 3
Contents
Using ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Using ActionScript
Before you start developing custom components, you should be familiar with basic
ActionScript coding practices.
25
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Your package statement must wrap the entire class definition. If you write your ActionScript
class file to the same directory as your other application files, you can leave the package name
blank. However, as a best practice, you should store your components in a subdirectory, where
the package name reflects the directory location. In this example, your write your
ActionScript class file to the directory myComponents, a subdirectory of your main
application directory.
Formatters are a particular type of component. You might also create a subdirectory of your
application’s root directory called myFormatters for all of your custom formatter classes. Each
formatter class would then define its package statement, as the following example shows:
package myFormatters
{
// Formatter class definition goes here.
}
If you create a component that is shared among multiple applications, or a component that
might be used with third-party components, assign a unique package name to avoid naming
conflicts. For example, you might prefix your package name with your company name, as in:
package Acme.myFormatters
{
// Formatter class definition goes here.
}
When you reference a custom component from an MXML file, you specify a namespace
definition for the component that corresponds to its directory location and package name, as
the following example shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myFormatters.*">
...
</mx:Application>
...
</mx:Application>
Using ActionScript 27
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Using the class statement
You use the class statement to define your class name, and to specify its superclass, as the
following example shows:
package myComponents
{
// Import necessary classes
import mx.core.Container;
import mx.controls.Button;
// Import all classes in the mx.events package
import mx.events.*;
}
}
The class definition of your component must be prefixed by the public keyword, or it cannot
be used as an MXML tag. A file that contains a class definition can have one, and only one,
public class definition, although it can have additional internal class definitions. Place any
internal class definitions at the bottom of your source file below the closing curly brace of the
package definition.
In a single ActionScript file, you can define only one class in the package. To define more than
one class in a file, define the additional classes outside of the package body.
N OTE
The class definition is one of the few ActionScript constructs that you cannot use in an
<mx:Script> block in an MXML file.
If you do not define a constructor, the compiler inserts one for you and adds a call to
super(). However, it is considered a best practice to write a constructor and to explicitly
call super(), unless the class contains nothing but static members. If you define the
constructor, but omit the call to super(), Flex automatically calls super() at the beginning
of your constructor.
In the following example, you define a constructor that uses super() to call the superclass’s
constructor:
package myComponents
{
// Import necessary classes
import mx.core.Container;
import mx.controls.Button;
// Import all classes in the mx.events package
import mx.events.*;
// Public constructor.
public function MyButton()
{
// Call the constructor in the superclass.
super();
}
// Define properties and methods.
}
}
N OTE
You cannot define a constructor for an MXML component. For more information, see
“About implementing IMXMLObject” on page 116
Using ActionScript 29
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Defining properties as variables
Properties let you define data storage within your class. You can define your properties as
public, which means that they can be accessed by users of the class. You can also define
properties as private, which means that they are used internally by the class, as the following
example shows:
public class MyButton extends Button {
Users of the class can access the public variables but not the private variables, as the following
example shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myControls.*">
Although you can define your classes to use public properties, you may find it advantageous to
define properties by using setter and getter methods. For more information, see “Defining
methods” on page 32.
N OTE
You cannot override an inherited property defined by a variable, but you can override a
property defined by setter and getter methods. You can reset the value of an inherited
property defined by a variable. You typically reset it in the constructor of the subclass for
an ActionScript component, or in an event handler for an MXML component because
MXML components cannot define a constructor.
By convention, setters use the identifier value for the name of the argument.
The variable that stores the property’s value cannot have the same name as the getter or setter.
By convention, precede the name of the variables with one (_) or two underscores (__). In
addition, Adobe recommends that you declare the variable as private or protected.
Users of the class can access the public property as the following example shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myControls.*" >
If the getter or setter overrides a getter or setter in a superclass, ensure that you include the
override keyword, as the following example shows:
override public function get label():String {}
override public function set label(value:String):void {}
Using ActionScript 31
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Defining methods
Methods define the operations that your class can perform. You define methods in the body of
the class. Your methods can override a method of a superclass, or define new functionality for
your components.
If the method adds new functionality, you define it using the function keyword, as the
following example shows:
public function myMethod():void {
// Method definition
}
If you define this method as a public method, users of the class can call it.
You can also define private methods, as the following example shows:
N OTE
If a function takes no arguments, ensure that you specify its argument list as empty
parentheses (), not as (void). The latter specifies a single argument of type Object named
void.
If a function, other than a constructor, returns no value, you must specify a return value of
void. If you omit the return type, the compiler issues a warning.
Private methods are for internal use by the class, and cannot be called by users of the class.
If the method overrides a method in a superclass, you must include the override keyword
and the signature of the method must exactly match that of the superclass method, as the
following example shows:
override protected function createChildren():void {
// Method definition
}
Your methods may take required or optional arguments. To make any of the arguments
optional, assign default values to them, as the following example shows:
override public validate(value:Object = null,
supressEvents:Boolean = false):ValidationResultEvent {
// Method definition
}
If the method takes a variable number of arguments, use the “...” syntax, as the following
example shows:
function foo(n:Number, ... rest):void {
// Method definition
}
This technique is useful when you create a subclass method that adds behavior to a superclass
method but also invokes the superclass method to perform its original behavior.
NOT E
Although Flex automatically calls the super() method in a constructor to execute the
superclass’s constructor, you must call super.methodName() in a method override.
Otherwise, the superclass’s version of the method does not execute.
Whether you call super.myMethod() within a method override depends on your application
requirement, as follows:
■ Typically, you extend the existing functionality of the superclass method, so the most
common pattern is to call super.myMethod() first in your method override, and then add
your logic.
■ You might need to change something before the superclass method does its work. In this
case, you might call super.myMethod() in the override after your logic.
■ In some method overrides, you might not want to invoke the superclass method at all.
Only call super.myMethod() if and when you want the superclass to do its work.
■ Sometimes the superclass has an empty method that does nothing, which requires you to
implement the functionality in the method. In this case, you should still call
super.myMethod() because in a future version of Flex, that method might implement
some functionality. For more information, see the documentation on each Flex class.
Using ActionScript 33
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
About scope
Scoping is mostly a description of what the this keyword refers to at any given point in your
application. In the main MXML application file, the file that contains the
<mx:Application> tag, the current scope is the Application object and, therefore, the this
keyword refers to the Application object.
In an ActionScript component, the scope is the component itself and not the application or
other file that references the component. As a result, the this keyword inside the component
refers to the component instance and not the Flex Application object.
Nonvisual ActionScript components do not have access to their parent application with the
parentDocument property. However, you can access the top-level Application object by using
the mx.core.Application.application property.
For more information on scope, see Chapter 4, “Using ActionScript,” in Flex Developer’s
Guide.
CHAPTER 4
Contents
About events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Dispatching custom events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
About events
Adobe Flex applications are event-driven. Events let an application know when the user
interacts with the interface, and also when important changes happen in the appearance or life
cycle of a component, such as the creation of a component or its resizing. Events can be
generated by user input devices, such as the mouse and keyboard, or by the asynchronous
operations, such as the return of a web service call or the firing of a timer.
The core class of the Flex component architecture, mx.core.UIComponent, defines core
events, such as updateComplete, resize, move, creationComplete, and others that are
fundamental to all components. Subclasses of UIComponent inherit these events.
35
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Custom components that extend existing Flex classes inherit all the events of the base class.
Therefore, if you extend the Button class to create the MyButton class, you can use the click
event, and the events that all controls inherit, such as mouseOver or initialize, as the
following example shows:
<?xml version="1.0"?>
<!-- events/MyApplication.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
<mx:Script>
<![CDATA[
import flash.events.Event;
<MyComp:MyButton
click="handleClick(event);"
initialize="handleInit(event);"/>
</mx:Application>
In addition to using the events inherited from its superclasses, your custom components can
define custom events. You use custom events to support data binding, to respond to user
interactions, or to trigger actions by your component.
For more information on the Flex event mechanism, see Chapter 5, “Using Events,” in Flex
Developer’s Guide.
About events 37
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Dispatching custom events
Flex defines many of the most common events, such as the click event for the Button
control, however, your application may require that you create events. In your custom Flex
components, you can dispatch any of the predefined events inherited by the component from
its superclass, and dispatch new events that you define within the component.
To dispatch a new event from your custom component, you must do the following:
1. (Optional) Create a subclass from the flash.events.Event class to create an event class that
describes the event object. For more information, see “Creating a subclass from the Event
class” on page 38.
2. (Optional) Use the [Event] metadata tag to make the event public so that the MXML
compiler recognizes it. For more information, see “Using the Event metadata tag”
on page 40.
3. Dispatch the event using the dispatchEvent() method. For more information, see
“Dispatching an event” on page 41.
// Public constructor.
public function EnableChangeEvent(type:String,
isEnabled:Boolean=false) {
// Call the constructor of the superclass.
super(type);
ActionScript components Above the class definition, but within the package definition, so
that the events are bound to the class and not a particular member of the class.
MXML components In the <mx:Metadata> tag of an MXML file.
The Event metadata keyword has the following syntax:
[Event(name=”eventName”, type=”package.eventType”)]
The eventName argument specifies the name, including the package, of the event. The
eventType argument specifies the class that defines the event.
The following example identifies the enableChange event as an event that an ActionScript
component can dispatch:
[Event(name="enableChange", type="myEvents.EnableChangeEvent")]
public class MyComponent extends TextArea
{
...
}
The following example shows the [Event] metadata tag within the <mx:Metadata> tag of an
MXML file:
<?xml version="1.0"?>
<!-- events\myComponents\MyButton.mxml -->
<mx:Button xmlns:mx="http://www.adobe.com/2006/mxml"
click="dispatchEvent(new EnableChangeEvent('enableChanged'));">
<mx:Script>
<![CDATA[
import myEvents.EnableChangeEvent;
]]>
</mx:Script>
<mx:Metadata>
[Event(name="enableChanged", type="myEvents.EnableChangeEvent")]
</mx:Metadata>
</mx:Button>
<mx:Script>
<![CDATA[
import myEvents.EnableChangeEvent;
public function
enableChangedListener(eventObj:EnableChangeEvent):void {
// Handle event.
}
]]>
</mx:Script>
</mx:Application>
If you do not identify an event with the [Event] metadata tag, the compiler generates an
error if you try to use the event name in MXML. The metadata for events is inherited from
the superclass, however, so you do not need to tag events that are already defined with the
[Event] metadata tag in the superclass.
Dispatching an event
You use the dispatchEvent() method to dispatch an event. The dispatchEvent() method
has the following signature:
public dispatchEvent(event:Event):Boolean
This method requires an argument of type Event, which is the event object. The
dispatchEvent() method initializes the target property of the event object with a reference
to the component dispatching the event.
You can create an event object and dispatch the event in a single statement, as the following
example shows:
dispatchEvent(new Event("click"));
You can also create an event object, initialize it, and then dispatch it, as the following example
shows:
var eventObj:EnableChangeEvent = new EnableChangeEvent("enableChange");
For complete examples that create and dispatch custom events, see Chapter 8, “Creating
Advanced MXML Components,” on page 91 and Chapter 9, “Creating Simple Visual
Components in ActionScript,” on page 121.
The Flex compiler does not examine the string passed to the constructor to determine if it is
valid. Therefore, the following code compiles, even though enableChangeAgain might not
be a valid value for the type property:
var eventObj:EnableChangeEvent =
new EnableChangeEvent("enableChangeAgain");
Because the compiler does not check the value of the type property, the only time that your
application can determine if enableChangeAgain is valid is at run time.
However, to ensure that the value of the type property is valid at compile time, Flex event
classes define static constants for the possible values for the type property. For example, the
Flex EffectEvent class defines the following static constant:
// Define static constant for event type.
public static const EFFECT_END:String = "effectEnd";
If you incorrectly reference the constant in the constructor, the compiler generates a syntax
error because it cannot locate the associated constant. For example, the following constructor
generates a syntax error at compile time because MY_EFFECT_END is not a predefined constant
of the EffectEvent class:
var eventObj:EffectEvent = new EffectEvent(EffectEvent.MY_EFFECT_END);
<mx:Button xmlns:mx="http://www.adobe.com/2006/mxml"
click="dispatchEvent(new
EnableChangeEventConst(EnableChangeEventConst.ENABLE_CHANGED));">
<mx:Script>
<![CDATA[
import myEvents.EnableChangeEventConst;
]]>
</mx:Script>
<mx:Metadata>
[Event(name="myEnable", type="myEvents.EnableChangeEventConst")]
</mx:Metadata>
</mx:Button>
This technique does not preclude you from passing a string to the constructor.
CHAPTER 5
Contents
About metadata tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Metadata tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
45
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
About metadata tags
Metadata tags provide information to the Flex compiler that describe how your components
are used in a Flex application. For example, you might create a component that defines a new
event. To make that event known to the Flex compiler so that you can reference it in MXML,
you insert the [Event] metadata tag into your component, as the following ActionScript class
definition shows:
[Event(name="enableChanged", type="flash.events.Event")]
class ModalText extends TextArea {
...
}
In this example, the [Event] metadata tag specifies the event name, and the class that defines
the type of the event object dispatched by the event. After you identify the event to the Flex
compiler, you can reference it in MXML, as the following example shows:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:MyComp="*">
<mx:Script>
<![CDATA[
function handleEnableChangeEvent(eventObj:Event):void {
...
}
]]>
</mx:Script>
<MyComp:ModalText enableChanged="handleEnableChangeEvent(event);"/>
</mx:Application>
If you omit the [Event] metadata tag from your class definition, Flex issues a syntax error
when it compiles your MXML file. The error message indicates that Flex does not recognize
the enableChanged property.
...
<mx:Metadata>
[Event(name="enableChange", type="flash.events.Event")]
</mx:Metadata>
<mx:Script>
<![CDATA[
A key difference between the <mx:Metadata> and <mx:Script> tags is that text within the
<mx:Metadata> tag is inserted before the generated class declaration, but text within
<mx:Script> tag is inserted in the body of the generated class declaration. Therefore,
metadata tags like [Event] and [Effect] must go in an <mx:Metadata> tag, but the
[Bindable] and [Embed] metadata tags must go in an <mx:Script> tag.
Tag Description
[ArrayElementType] Defines the allowed data type of each element of an Array. For
more information, see “ArrayElementType metadata tag”
on page 50.
[Bindable] Identifies a property that you can use as the source of a data
binding expression. For more information, see “Bindable
metadata tag” on page 51.
[DefaultProperty] Defines the name of the default property of the component
when you use the component in an MXML file. For more
information, see “DefaultProperty metadata tag” on page 53.
[Effect] Defines the MXML property name for the effect. For more
information, see “Effect metadata tag” on page 54.
[Embed] Imports JPEG, GIF, PNG, SVG, and SWF files at compile time.
Also imports image assets from SWC files.
This is functionally equivalent to the MXML @Embed syntax, as
described in Chapter 32, “Embedding Assets,” in Flex
Developer’s Guide.
[Event] Defines the MXML property for an event and the data type of
the event object that a component emits. For more information,
see “Event metadata tag” on page 55.
[Exclude] Omits the class element from the FlexBuilder tag inspector.
The syntax is as follows:
[Exclude(name="label", kind="property")]
[ExcludeClass] Omits the class from the FlexBuilder tag inspector. This is
equivalent to the @private tag in ASDoc when applied to a
class.
[IconFile] Identifies the filename for the icon that represents the
component in the Insert bar of Adobe® Flex™ Builder™. For
more information, see “IconFile metadata tag” on page 56.
[Inspectable] Defines an attribute exposed to component users in the
attribute hints and Tag inspector of Flex Builder. Also limits
allowable values of the property. For more information, see
“Inspectable metadata tag” on page 56.
[InstanceType] Specifies the allowed data type of a property of type
IDeferredInstance. For more information, see “InstanceType
metadata tag” on page 58.
Metadata tags 49
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Tag Description
[NonCommittingChangeEvent] Identifies an event as an interim trigger. For more information,
see “NonCommittingChangeEvent metadata tag” on page 59.
[RemoteClass] Maps the ActionScript object to a Java object. For more
information, see the LiveCycle Data Services ES Developer’s
Guide.
[Style] Defines the MXML property for a style property for the
component. For more information on using the [Style]
metadata tag, see “Style metadata tag” on page 59.
[Transient] Identifies a property that should be omitted from data that is
sent to the server when an ActionScript object is mapped to a
Java object using [RemoteClass].
The following sections describe the component metadata tags in more detail.
[ArrayElementType("String")]
public var newStringProperty:Array;
[ArrayElementType("Number")]
public var newNumberProperty:Array;
...
}
In this example, you specify String as the allowed data type of the Array elements. If a user
attempts to assign elements of a data type other than String to the Array in an MXML file, the
compiler issues a syntax error, as the following example shows:
<MyComp:MyTypedArrayComponent>
<MyComp:newStringProperty>
<mx:Number>94062</mx:Number>
<mx:Number>14850</mx:Number>
<mx:Number>53402</mx:Number>
</MyComp:newStringProperty>
</MyComp:MyTypedArrayComponent>
This MXML code generates an error because Flex cannot convert the Strings {abc} and {def }
to a Number.
You insert the [ArrayElementType] metadata tag before the variable definition. The tag has
the following syntax:
[ArrayElementType("elementType")]
The following table describes the property of the [ArrayElementType] metadata tag:
If you omit the event name, Flex automatically creates an event named propertyChange.
For more infomration on data binding and on this metadata tag, see Chapter 42, “Binding
Data,” in Flex Developer’s Guide.
Metadata tags 51
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Working with bindable property chains
When you specify a property as the source of a data binding, Flex monitors not only that
property for changes, but also the chain of properties leading up to it. The entire chain of
properties, including the destination property, is called a bindable property chain. In the
following example, firstName.text is a bindable property chain that includes both a
firstName object and its text property:
<first>{firstName.text}</first>
You should raise an event when any named property in a bindable property chain changes. If
the property is marked with the [Bindable] metadata tag, the Flex compiler generates the
event for you. For more examples using the [Bindable] metadata tag, see “Bindable
metadata tag” in Creating and Extending Flex Components.
The following example shows an example that uses the [Bindable] metadata tag for a
variable and a getter property and how to call the dispatchEvent() function:
[Bindable]
public var minFontSize:Number = 5;
[Bindable("textChanged")]
public function get text():String {
return myText;
}
If you omit the event name in the [Bindable] metadata tag, the Flex compiler automatically
generates and dispatches an event named propertyChange so that the property can be used as
the source of a data binding expression.
You should also provide the compiler with better information about an object by casting the
object to a known type. In the following example, the myList List control contains Customer
objects, so the selectedItem property is cast to a Customer object:
<mx:Model id="selectedCustomer">
<customer>
<name>{Customer(myList.selectedItem).name}</name>
<address>{Customer(myList.selectedItem).address}</address>
...
</customer>
</mx:Model>
There are some situations in which binding does not execute automatically as expected.
Binding does not execute automatically when you change an entire item of a dataProvider
property.
In this code example, the problem with {temp.label} is that temp is an Object. You can
solve in one of the following ways:
■ Preinitialize the Object.
■ Assign an ObjectProxy to temp; all of an ObjectProxy’s properties are bindable.
■ Make temp a strongly typed object with a label property that is bindable.
Binding also does not execute automatically when you are binding data to a property that
Flash Player updates automatically, such as the mouseX property.
The executeBindings() method of the UIComponent class executes all the bindings for
which a UIComponent object is the destination. All containers and controls, as well as the
Repeater component, extend the UIComponent class. The executeChildBindings()
method of the Container and Repeater classes executes all of the bindings for which the child
UIComponent components of a Container or Repeater class are destinations. All containers
extend the Container class.
These methods give you a way to execute bindings that do not occur as expected. By adding
one line of code, such as a call to executeChildBindings() method, you can update the user
interface after making a change that does not cause bindings to execute. However, you should
only use the executeBindings() method when you are sure that bindings do not execute
automatically.
Metadata tags 53
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
You can use the [DefaultProperty] metadata tag in your ActionScript component to define
a single default property. For more information, and an example, see “Creating a default
property” on page 130.
The following table describes the properties of the [Effect] metadata tag:
The [Effect] metadata tag is often paired with an [Event] metadata tag, where the
[Event] metadata tag defines the event corresponding to the effect’s trigger. By convention,
the name of the effect is the event name with the suffix Effect, as the following example of
an ActionScript file shows:
// Define event corresponding to the effect trigger.
[Event(name="darken", type="flash.events.Event")]
// Define the effect.
[Effect(name="darkenEffect", event="darken")]
class ModalText extends TextArea {
...
}
In an MXML file, you can define the event and effect in an <mx:Metadata> block, as the
following example shows:
<mx:Metadata>
[Event(name="darken", type="flash.events.Event")]
The following table describes the properties of the [Event] metadata tag:
The following example identifies the myClickEvent event as an event that the component
can dispatch:
[Event(name="myClickEvent", type="flash.events.Event")]
If you do not identify an event in the class file with the [Event] metadata tag, the MXML
compiler generates an error if you try to use the event name in MXML. Any component can
register an event listener for the event in ActionScript by using the addEventListener()
method, even if you omit the [Event] metadata tag.
The following example identifies the myClickEvent event as an event that an ActionScript
component can dispatch:
[Event(name="myEnableEvent", type="flash.events.Event")]
public class MyComponent extends UIComponent
{
...
}
The following example shows the [Event] metadata tag in the <mx:Metadata> tag in an
MXML file:
<?xml version="1.0"?>
<!-- TextAreaEnabled.mxml -->
<mx:TextArea xmlns:mx="http://www.adobe.com/2006/mxml">
Metadata tags 55
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
<mx:Metadata>
[Event(name="myEnableEvent", type="flash.events.Event")]
</mx:Metadata>
....
</mx:TextArea>
The fileName property specifies a PNG, GIF, or JPEG file that contains the icon, as the
following example shows:
[IconFile("MyButton.png")]
public class MyButton extends Button
{
...
}
The following table describes the properties of the [Inspectable] metadata tag:
defaultValue String or Sets the initial value in the editor that appears in the Property
Number Inspector when you modify the attribute. The default value is
determined from the property definition.
enumeration String Specifies a comma-delimited list of legal values for the property.
Only these values are allowed; for example, item1, item2, item3.
This information appear as code hints and in the Property Inspector.
If you define a Boolean variable, Flex Builder automatically shows
true and false without you having to specifying them using
enumeration.
environment String Specifies which inspectable properties should not be allowed (none),
which are used only for Flex Builder (Flash), and which are used only
by Flex and not Flex Builder (MXML).
format String Determines the type of editor that appears in the Property Inspector
when you modify the attribute. You can use this property when the
data type of the attribute is not specific to its function. For example,
for a property of type Number, you can specify format="Color" to
cause Flex Builder to open a color editor when you modify the
attribute. Common values for the format property include "Length",
"Color", "Time", "EmbeddedFile", and "File".
Metadata tags 57
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Property Type Description
type String Specifies the type specifier. If omitted, use the property’s type. The
following values are valid:
• Array
• Boolean
• Color
• Font Name
• List
• Number
• Object
• String
If the property is an Array, you must list the valid values for the Array.
variable String Specifies the variable to which this parameter is bound.
verbose Number Indicates that this inspectable property should be displayed in the
Flex Builder user interface only when the user indicates that verbose
properties should be included. If this property is not specified, Flex
Builder assumes that the property should be displayed.
The Flex compiler validates that users only assign values of the specified type to the property.
In this example, if the component user sets the topRow property to a value of a type other
than mx.controls.Label, the compiler issues an error message.
You use the [InstanceType] metadata tag when creating template components. For more
information, see Chapter 12, “Creating Template Components,” on page 197.
The [InstanceType] metadata tag has the following syntax:
[InstanceType("package.className")]
In the following example, the component dispatches the change event every time the user
enters a keystroke, but the change event does not trigger data binding or data validators.
When the user completes data entry, by pressing the Enter key, the component broadcasts the
valueCommit event to trigger any data bindings and data validators:
[Event(name="change", type="flash.events.Event")]
class MyText extends UIComponent {
...
[Bindable(event="valueCommit")]
[NonCommittingChangeEvent("change")]
function get text():String {
return getText();
}
function set text(t):void {
setText(t);
// Dispatch events.
}
}
Metadata tags 59
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
The following table describes the properties for the [Style] metadata tag:
The next example shows the definition of the verticalAlign style property:
[Style(name="verticalAlign", type="String",
enumeration="bottom,middle,top", inherit="no")]
For more information on the [Style] metadata tag, see Chapter 11, “Creating Custom Style
Properties,” on page 185.
Metadata tags 61
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
CHAPTER 6
Compiling Components 6
When you compile an application, you create a SWF file that a user can download and play.
You can also compile any custom components that you create as part of the application.
When you create a component, you save it to a location that the Flex compiler can access. You
can save your components as MXML and ActionScript files, as SWC files, or as Runtime
Shared Libraries (RSLs). This topic describes the options you have when you compile
components.
Contents
About compiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Compiling components with Flex SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Compiling components with LiveCycle Data Services ES . . . . . . . . . . . . . . . . . . . . . 72
About compiling
You compile a custom component so that you can use it as part of your application. You can
compile the component when you compile the entire application, or you can compile it
separately so that you can link it into the application at a later time.
63
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Flex component file types
When you create a Flex component, you can distribute it in one of several different file
formats, as the following table shows:
You must take into consideration the file format and file location when you compile an
application that uses the component.
64 Compiling Components
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
The default option is the target file to compile into a SWF file, and it is required to have a
value. If you use a space-separated list as part of the options, you can terminate the list with a
double hyphen before adding the target file; for example:
$ mxmlc -option arg1 arg2 arg3 -- target_file.mxml
When LiveCycle Data Services ES receives an HTTP request for an MXML file, LiveCycle
Data Services ES performs the following steps:
1. Compiles the MXML file to produce a SWF file.
2. Caches the compiled SWF file on the server.
3. Returns the SWF file to the client.
About compiling 65
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
■ An ActionScript component in a subdirectory of the main application directory must
define a fully qualified package name that is relative to the location of the application’s
root directory. For example, if you define a custom component in the
dir1/dir2/myControls/PieChart.as file, its fully qualified package name must be
dir1.dir2.myControls, assuming dir1 is an immediate subdirectory of the main
application directory.
■ An MXML component does not include a package name definition. However, you must
declare a namespace definition in the file that references the MXML component that
corresponds to the directory location of the MXML component, either in a subdirectory
of the application’s root directory, or in a subdirectory of the classpath. For more
information, see Chapter 7, “Creating Simple MXML Components,” on page 77.
■ An application can access MXML and ActionScript components in the directories
included in the ActionScript classpath. The component search order in the classpath is
based on the order of the directories listed in the classpath.
■ An ActionScript component in a subdirectory of a directory included in the classpath
must define a fully qualified package name that is relative to the location of the classpath
directory. For example, if you define a custom component in the file
dir1/dir2/myControls/PieChart.as, and dir1 is included in the ActionScript classpath, its
fully qualified package name must be dir1.dir2.myControls.
■ The <mx:Script> tag in the main MXML file, and in dependent MXML component
files, can reference components located in the ActionScript classpath.
66 Compiling Components
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
For example, you can create a component for use by a single application. In that case, you
store it in the directory structure of the application, usually in a subdirectory under the
directory that contains the main file of the application. The component is then compiled with
the entire application into the resultant SWF file.
You can also create a component that is shared among multiple applications as an MXML or
ActionScript file. In that case, store the component in a location that is included in the
ActionScript classpath of the application. When Flex compiles the application, it also
compiles the components included in the application’s ActionScript classpath.
You specify the directory location of the shared components by using one of the following
methods:
Flex Builder Open the Project Properties dialog box, and then select Flex Build Path to set
the ActionScript classpath.
Command-line compiler Use the source-path option to the mxmlc compiler to specify
the directory location of your shared MXML and ActionScript files.
68 Compiling Components
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Distributing a component as an ActionScript file
When you distribute a component defined as an ActionScript file, you can store it within the
same directory structure as your application files, or in a directory specified in the
ActionScript classpath.
The MXML tag name for a custom component consists of two parts: the namespace prefix
and the tag name. The namespace prefix tells Flex where to look for the file that implements
the custom component. The tag name corresponds to the filename of the component, in this
case MySimpleFormatter.as. Therefore, a file MySimpleFormatter.as defines a component
with the tag name of <namespace:MySimpleFormatter>.
The main application MXML file defines the namespace prefix used to reference the
component in the <mx:Application> tag. When you deploy your formatter as an
ActionScript file, you refer to it in one of the following ways:
■ If you store the formatter component in the same directory as the application file, or in a
directory that the ActionScript classpath (not a subdirectory) specifies, you define the
formatter by using an empty package statement, as the following example shows:
package
{
//Import base Formatter class.
import mx.formatters.Formatter
You can refer to it as the following example shows. In this example, the local namespace
(*) is mapped to the prefix MyComp.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="*">
<MyComp:MySimpleFormatter/>
</mx:Application>
If the same file exists in the ActionScript classpath directory and the application directory,
Flex uses the file in the application directory.
■ If you store the formatter component in a subdirectory of the directory that contains the
application file, you specify that directory as part of the package statement, as the
following example shows:
package myComponents.formatters
{
//Import base Formatter class
<MyComp:MySimpleFormatter/>
</mx:Application>
If multiple files with the same name exist under an ActionScript classpath subdirectory
and the application subdirectory, Flex uses the file under the application subdirectory.
■ If you store the formatter component in a subdirectory of the ActionScript classpath
directory, you specify that subdirectory as part of the package statement, as the following
example shows:
package flexSharedRoot.custom.components
{
//Import base Formatter class.
import mx.formatters.Formatter
You then use a namespace that specifies the subdirectory. The following code declares a
component that is in the flexSharedRoot/custom/components directory:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="flexSharedRoot.custom.components.*"/>
<MyComp:MySimpleFormatter/>
</mx:Application>
If the same file exists in the ActionScript classpath directory and the application directory,
Flex uses the file in the application file directory.
70 Compiling Components
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Distributing a component as a SWC file
To create a SWC file, use the compc utility in the flex_install_dir/bin directory. The compc
utility generates a SWC file from MXML component source files and/or ActionScript
component source files.
In this example, you create a SWC file for a custom formatter component that you defined by
using the following package and class definition:
package myComponents.formatters
{
//Import base Formatter class.
import mx.formatters.Formatter
In this example, you use the following options of the compc compiler:
In your main application file, you specify the component’s namespace, as the following
example shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.formatters.*">
<MyComp:MyFormatter/>
</mx:Application>
When you distribute SWC files, ensure that the corresponding ActionScript file is not in the
directory structure of the application or in the ActionScript classpath. Otherwise, Flex might
use the ActionScript file, rather than the SWC file.
When you use mxmlc to compile the main application, ensure that the c:\flex\mainApp
directory is included in the library path, otherwise mxmlc cannot locate the SWC file.
For more information about SWC files, see Chapter 9, “Using the Flex Compilers,” in
Building and Deploying Flex Applications, and Chapter 10, “Building Projects,” in Using Flex
Builder.
72 Compiling Components
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Distributing components as MXML and
ActionScript files
You can deploy your components as MXML and ActionScript files by copying them to the
/WEB-INF/flex/user_classes directory, or to a directory included in the ActionScript
classpath. You set the ActionScript classpath by using the <source-path> tag in the flex-
config.xml file.
For more information, see Chapter 15, “Deploying Flex Applications,” in Building and
Deploying Flex Applications.
74 Compiling Components
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
2
PART 2
75
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
CHAPTER 7
Contents
About MXML components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Scoping in custom components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Applying styles to your custom component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
77
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
For example, Flex supplies a ComboBox control that you can use as part of a form that
collects address information from a customer. You can use a ComboBox to let the user select
the State portion of the address from a list of the 50 states in the U.S. In an application that
has multiple locations where a user can enter an address, it would be tedious to create and
initialize multiple ComboBox controls with the information about all 50 states.
Instead, you create an MXML component that contains a ComboBox control with all 50
states defined within it. Then, wherever you must add a state selector to your application, you
use your custom MXML component.
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:dataProvider>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
<!-- Add all other states. -->
</mx:dataProvider>
</mx:ComboBox>
As part of its implementation, a custom MXML component can reference another custom
MXML component.
<MyComp:StateComboBox/>
</mx:Application>
In this example, the main application file includes a new namespace definition of
xmlns:MyComp="*" as part of the <mx:Application> tag. This namespace definition
specifies the location of the MXML component. In this case, it specifies that the component
is in the same directory as the main application file or, if you are using LiveCycle Data
Services ES, in the WEB-INF/flex/user-classes directory.
As a best practice, store your components in a subdirectory. For example, you can write this
file to the myComponents directory, a subdirectory of your main application directory. For
more information on the namespace, see Chapter 2, “Developing Applications in MXML,” in
Flex Developer’s Guide.
<mx:Script>
<![CDATA[
import flash.events.Event;
}
]]>
</mx:Script>
</mx:Application>
<mx:FormItem label="NameField">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="Street">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
The following application file references the AddressForm component in the <AddressForm>
tag:
<?xml version="1.0"?>
<!-- mxml/MyApplicationAddressForm.mxml-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="*" >
<MyComp:AddressForm/>
</mx:Application>
The restriction on child tags refers to the child tags that correspond to visual
components. Visual components are subclasses of the UIComponent component. You
can always insert tags for nonvisual components, such as ActionScript blocks, styles,
effects, formatters, validators, and other types of nonvisual components, regardless of
how you define your custom component.
<mx:Form xmlns:mx="http://www.adobe.com/2006/mxml"/>
This component defines no children of the Form container, therefore, you can add children
when you use it in another MXML file, as the following example shows:
<?xml version="1.0"?>
<!-- mxml/MainEmptyForm.mxml-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="*">
<MyComp:EmptyForm>
<mx:FormItem label="Name">
<mx:TextInput/>
</mx:FormItem>
</MyComp:EmptyForm>
</mx:Application>
The AddressForm.mxml file specifies the Form container as its root tag. Because you define a
container as the root tag of the MXML component, you are creating a subclass of that
container, and you can reference all of the properties and methods of the root tag when using
your MXML component. Therefore, in the main application, you can reference all of the
properties of the Form container in the MXML tag that corresponds to your custom
component, or in any ActionScript code in the main application. However, you cannot
reference properties of the children of the Form container.
<mx:Script>
<![CDATA[
import mx.events.ScrollEvent;
<MyComp:AddressForm horizontalPageScrollSize="25"
scroll="handleScrollEvent(event);"/>
</mx:Application>
To configure the children of a custom MXML component, you define new properties in the
MXML component, and then use those new properties to pass configuration information to
the component children. For more information, see Chapter 8, “Creating Advanced MXML
Components,” on page 91.
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
close="handleCloseEvent(event);">
<mx:Script>
<![CDATA[
import flash.events.Event;
<mx:dataProvider>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:dataProvider>
</mx:ComboBox>
This example defines an event listener for the ComboBox control that updates the
stateIndex property when the ComboBox control closes.
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
openDuration="1000"
fontSize="15">
<mx:dataProvider>
<mx:Array>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:ComboBox>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
styleName="myCBStyle">
<mx:Style>
.myCBStyle {
openDuration : 1000;
fontSize : 15;
}
</mx:Style>
<mx:dataProvider>
<mx:Array>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:ComboBox>
NO TE
You cannot define a type selector in an MXML component. If you define a type selector,
a compiler error occurs.
Application developers can apply additional styles to the component. For example, if your
component defines styles for the open duration and font size, application developers can still
specify font color or other styles. The following example uses
StateComboBoxWithStyleProps.mxml in an application and specifies the font color style for
the control:
<?xml version="1.0"?>
<!-- mxml/MainStyleWithPropsAddColor.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
<MyComp:StateComboBoxWithStyleProps color="red"/>
</mx:Application>
<MyComp:StateComboBoxWithStyleProps openDuration="1000"/>
</mx:Application>
When you specify styles as tag attributes, those styles override any conflicting styles set in the
definition of the MXML component.
You can use a class selector to define styles. Often you use a class selector to apply styles to
specific instances of a control, as the following example shows:
<?xml version="1.0"?>
<!-- mxml/MainStyleOverrideUsingClassSel.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
<mx:Style>
.myStateComboBox {
openDuration : 1000;
}
</mx:Style>
<MyComp:StateComboBoxWithStyleProps styleName="myStateComboBox"/>
<mx:ComboBox>
...
</mx:ComboBox>
</mx:Application>
In this example, you use the styleName property in the tag definition of an MXML
component to apply styles to a specific instance of the MXML component. However, those
styles are not applied to the ComboBox control defined in the main application file, nor
would they be applied to any other instances of StateComboBox.mxml unless you also specify
the styleName property as part of defining those instances of the MXML component.
When you specify any styles by using a class selector, those styles override all styles that you set
by using a class selector in the MXML file. Those styles do not override styles that you set by
using tag properties in the MXML file.
<mx:Style>
StateComboBoxWithStyleProps {
openDuration : 1000;
}
</mx:Style>
<MyComp:StateComboBoxWithStyleProps/>
</mx:Application>
In this example, the type selector specifies the openDuration style for all instances of the
StateComboBox control in the application. When you specify any styles by using a type
selector, those styles override all styles that you set by using a class selector in the MXML file.
Those styles do not override styles that you set by using tag properties in the MXML file.
<mx:Style>
ComboBox {
openDuration: 1000;
fontSize: 15;
color: red;
}
</mx:Style>
<MyComp:StateComboBoxWithStyleProps/>
<mx:ComboBox/>
</mx:Application>
In this example, all ComboBox controls and all StateComboBox.mxml controls have an
openDuration of 1000 ms, fontSize of 15 points, and red text.
<mx:Style>
ComboBox {
color: red;
openDuration: 1000;
fontSize: 15;
}
StateComboBoxWithStyleProps {
color: green;
}
</mx:Style>
<MyComp:StateComboBoxWithStyleProps/>
<mx:ComboBox/>
</mx:Application>
In this example, the StateComboBox control uses green text, and the values for the fontSize
and openDuration styles specified in the type selector for the ComboBox control.
CHAPTER 8
Contents
About reusable MXML components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Adding custom properties and methods to a component . . . . . . . . . . . . . . . . . . . . . . 92
Working with events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
About interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .114
91
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
With loosely coupled components, you typically define properties of the component to pass
information to it. These properties, defined by using variables or setter and getter methods,
specify the data type of the parameter value. For more information about defining component
properties, see “Adding custom properties and methods to a component” on page 92.
The best practice for defining components that return information back to the main
application is to design the component to dispatch an event that contains the return data. In
that way, the main application can define an event listener to handle the event and take the
appropriate action. For more information on dispatching events, see “Working with events”
on page 107.
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="setNameLength();">
<mx:Script>
<![CDATA[
<MyComp:StateComboBoxPropAS shortNames="true"/>
</mx:Application>
The following example modifies the component to add a method that lets you change the
display of the state name at run time. This public method takes a single argument that
specifies the value of the shortNames property:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxPropMethod.mxml -->
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="setNameLength();">
<mx:Script>
<![CDATA[
</mx:Application>
All properties defined by using the <mx:String>, <mx:Number>, and <mx:Boolean> tags are
public. This means that the component user can access these properties.
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="setNameLength();">
<mx:Script>
<![CDATA[
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
// Set method.
public function set shortNames(val:Boolean):void {
// Call method to set the dataProvider
// based on the name length.
__shortNames = val;
if (__shortNames) {
this.dataProvider=stateArrayShort; }
else {
this.dataProvider=stateArrayLong; }
}
// Get method.
public function get shortNames():Boolean{
return __shortNames;
}
]]>
</mx:Script>
</mx:ComboBox>
In this example, you create a StateComboBoxGetSet.mxml control that takes a shortNames
property defined by using ActionScript setter and getter methods. One advantage to using
setter and getter methods to define a property is that the component can recognize changes to
the property at run time. For example, you can give your users the option of displaying short
state names or long state names from the application. The setter method modifies the
component at run time in response to the user’s selection.
</mx:Application>
In this example, selecting the button toggles the display format of the state name between the
short and long formats.
]]>
</mx:Script>
For more information on the [Inspectable] metadata tag, see Chapter 5, “Using Metadata
Tags in Custom Components,” on page 45.
Data binding is usually triggered whenever the value of the source property changes.
Properties that you define in your custom controls can also take advantage of data binding.
You can automatically use any property defined by using an MXML tag, such as
<mx:Boolean>, and any ActionScript property defined as a variable or defined by using setter
and getter methods as the destination of a binding expression.
For example, “Defining properties by using setters and getters” on page 96 defined the
shortNames property of StateComboBoxGetSet.mxml by using setter and getter methods.
With no modification to that component, you can use shortNames as the destination of a
binding expression, as the following example shows:
<MyComp:StateComboBoxSetGet shortNames="{some_prop}"/>
However, you can also write your component to use the shortNames property as the source of
a binding expression, as the following example shows for the nex component
StateComboBoxGetSetBinding.mxml:
<?xml version="1.0"?>
<!-- mxmlAdvanced/MainPropSetGetBinding.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
<mx:Button click="myStateCB.shortNames=!myStateCB.shortNames;"/>
</mx:Application>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import flash.events.Event;
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.
3. Add a call to the dispatchEvent() method to dispatch the event when you define the
event name in the [Bindable] metadata tag.
For more information on using the [Bindable] tag, see “Bindable metadata tag” on page 51.
<mx:TextArea id="myTAMain"/>
<MyComp:StateComboBoxDirectRef/>
</mx:Application>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
close="handleCloseEvent(event);">
<mx:Script>
<![CDATA[
import flash.events.Event;
import mx.core.Application;
<mx:dataProvider>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:dataProvider>
</mx:ComboBox>
In the previous example, you use the close event of the ComboBox control to write the
selectedIndex directly to the TextArea control in the main application. You must cast the
value of selectedIndex to a String because the text property of the TextArea control is of
type String.
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
close="handleCloseEvent(event);">
<mx:Script>
<![CDATA[
import flash.events.Event;
<mx:dataProvider>
<mx:Array>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:Array>
</mx:dataProvider>
</mx:ComboBox>
Although these examples work, they require that the TextArea control has a predefined id
property, and that MXML component knows that id. In this case, custom component is an
example of a tightly coupled component. That is, the component is written for a specific
application and application structure, and it not easily reused in another application.
</mx:Application>
The custom component does not have to know anything about the main application, other
than that it writes its results back to a TextArea control, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/StateComboBoxPassRefToTA.mxml -->
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
close="handleCloseEvent(event);">
<mx:Script>
<![CDATA[
import flash.events.Event;
import mx.controls.TextArea;
<mx:dataProvider>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:dataProvider>
</mx:ComboBox>
In this example, you use the Flex data binding syntax to pass the reference to the TextArea
control to your custom component. Now, you can use StateComboBoxPassRefToTA.mxml
anywhere in an application. The only requirement is that the calling component must pass a
reference to a TextArea control to the component.
</mx:Application>
In the definition of DestinationComp.mxml, you define the caller property, and specify as
its data type the name of the file of the calling MXML file, as the following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/DestinationComp.mxml -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
// Define variable to reference calling file.
[Bindable]
public var caller:CallingComponent;
]]>
</mx:Script>
<mx:Script>
<![CDATA[
import flash.events.Event;
</mx:Application>
In this example, if the MXML component dispatches a close event, the event listener in the
calling MXML file handles it.
Alternatively, you could define the event listener within the StateComboBox.mxml
component, as the following example shows:
<?xml version="1.0"?>
<!-- StateComboBox.mxml -->
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
close="handleCloseEvent(event);">
<mx:Script>
<![CDATA[
import flash.events.Event;
<mx:dataProvider>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:dataProvider>
</mx:ComboBox>
The setter method dispatches a new event type, called enableChanged, when the value of the
enableTA variable changes. The [Event] metadata tag identifies the event to the MXML
compiler so that the file referencing the component can use the new property. For more
information on using the [Event] metadata keyword, see Chapter 5, “Using Metadata Tags
in Custom Components,” on page 45.
The syntax for the [Event] metadata tag is as follows:
<mx:Metadata>
[Event(name="eventName", type="eventType")]
</mx:Metadata>
<mx:Metadata>
[Event(name="enableChanged", type="flash.events.Event")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import flash.events.Event;
<mx:Script>
<![CDATA[
import flash.events.Event;
import myComponents.TextAreaEnabled;
</mx:Application>
If you do not use the [Event] metadata tag in the custom component file to define the
enableChanged event, the MXML compiler generates an error message when you reference
the event name in an MXML file. Any component can register an event listener for the event
in ActionScript using the addEventListener() method, even if you omit the [Event]
metadata tag.
You can also create and dispatch events that use an event object of a type other than that
defined by the Event class. For example, you might want to create an event object that
contains new properties so that you can pass those properties back to the referencing file. To
do so, you create a subclass of the Event class to define your new event object. For information
on creating custom event classes, see Chapter 4, “Creating Custom Events,” on page 35.
<mx:Metadata>
[Event(name="close", type="flash.events.Event")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import flash.events.Event;
// Redispatch event.
private function handleCloseEventInternal(eventObj:Event):void {
dispatchEvent(eventObj);
}
]]>
</mx:Script>
<mx:FormItem label="Name">
<mx:TextInput id="name1" />
</mx:FormItem>
<mx:FormItem label="Street">
<mx:TextInput id="street" />
</mx:FormItem>
<mx:Script>
<![CDATA[
import flash.events.Event;
<MyComp:AddressForm mouseDown="handleMouseDown(event);"
close="handleCloseEvent(event);"/>
</mx:Application>
About interfaces
Interfaces are a type of class that you design to act as an outline for your components. When
you write an interface, you provide only the names of public methods rather than any
implementation. For example, if you define two methods in an interface and then implement
that interface, the implementing class must provide implementations of those two methods.
Interfaces in ActionScript can only declare methods and properties by using setter and getter
methods; they cannot specify constants. The benefit of interfaces is that you can define a
contract that all classes that implement that interface must follow. Also, if your class
implements an interface, instances of that class can also be cast to that interface.
A class that implements the SuperBox interface uses the implements attribute to point to its
interface and must provide an implementation of the methods. The following example of a
custom ComboBox component implements the SuperBox interface:
<?xml version="1.0"?>
<!-- StateComboBox.mxml -->
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
implements="SuperBox">
<mx:Script>
<![CDATA[
public function selectSuperItem():String {
return "Super Item was selected";
}
public function removeSuperItem():Boolean {
return true;
}
public function addSuperItem():Boolean {
return true;
}
]]>
</mx:Script>
<mx:dataProvider>
<mx:String>AK</mx:String>
<mx:String>AL</mx:String>
</mx:dataProvider>
</mx:ComboBox>
You can implement multiple interfaces by separating them with commas, as the following
example shows:
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
implements="SuperBox, SuperBorder, SuperData">
All methods that you declare in an interface are considered public. If you define an interface
and then implement that interface, but do not implement all of its methods, the MXML
compiler throws an error.
These events are all defined by the UIComponent class, and inherited by all of its subclasses.
If you create an MXML component that is not a subclass of UIComponent, you cannot take
advantage of these events. You can instead implement the IMXMLObject interface in your
MXML component, and then implement the IMXMLObject.initialized() method, as the
following example shows:
<?xml version="1.0"?>
<!-- mxmlAdvanced/myComponents/ObjectComp.mxml -->
<mx:Object xmlns:mx="http://www.adobe.com/2006/mxml"
implements="mx.core.IMXMLObject">
<mx:Script>
<![CDATA[
<mx:Number id="y"/>
<mx:Number id="z"/>
<mx:Number id="x"/>
</mx:Object>
<mx:Script>
<![CDATA[
</mx:Application>
Because Flex calls the IMXMLObject.initialized() method after it initializes the properties
of the component, the trace() function in the implementation of the
IMXMLObject.initialized() method outputs the following:
initialized, x = 1
PART 3
Creating ActionScript
Components 3
This part describes how to create custom Adobe Flex components in
ActionScript.
The following topics are included:
Chapter 9: Creating Simple Visual Components in ActionScript 121
Chapter 10: Creating Advanced Visual Components in
ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Chapter 11: Creating Custom Style Properties . . . . . . . . . . . . . . . . 185
Chapter 12: Creating Template Components . . . . . . . . . . . . . . . . . 197
119
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
CHAPTER 9
Contents
About ActionScript components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Adding properties and methods to a component . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Defining events in ActionScript components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141
Applying styles to custom components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
121
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Flex components are implemented as a class hierarchy in ActionScript. Each component in
your application is an instance of an ActionScript class. The following example shows just a
portion of this hierarchy:
UIComponent
VBox
NO TE
This example shows a portion of the class hierarchy. For a complete description of the
class hierarchy, see the Adobe Flex Language Reference.
All Flex visual components are derived from the ActionScript UIComponent class. To create
your own components, you can create a subclass from the UIComponent class, or from any of
its subclasses.
The class you choose to use as the superclass of your custom component depends on what you
are trying to accomplish. For example, you might require a custom button control. You could
create a subclass of the UIComponent class, then recreate all of the functionality built into the
Flex Button class. A better and faster way to create your custom button component is to create
a subclass of the Flex Button class, and then modify it in your custom class.
This topic describes how to create simple ActionScript components. Simple components are
subclasses of existing Flex components that modify the behavior of the component, or add
new functionality to it. For example, you might add a new event type to a Button control, or
modify the default styles or skins of a DataGrid control.
You can also create advanced ActionScript components. Advanced ActionScript components
might have one of the following requirements:
■ Modify the appearance of a control or the layout functionality of a container
■ Encapsulate one or more components into a composite component
■ Subclass UIComponent to create components
For information on creating advanced ActionScript components, see Chapter 10, “Creating
Advanced Visual Components in ActionScript,” on page 149.
// Constructor
public function DeleteTextArea() {
// Call super().
super();
<MyComp:DeleteTextArea/>
</mx:Application>
Your class must be specified as public for you to be able to access it by using an MXML
tag.
In this example, you first define the MyComp namespace to specify the location of your custom
component. You then reference the component as an MXML tag by using the namespace
prefix.
You can specify any inherited properties of the superclass in MXML, as the following example
shows:
<?xml version="1.0"?>
<!-- as/MainDeleteTextAreaProps.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
</mx:Application>
You do not have to change the name of your custom component when you create a subclass of
a Flex class. In the previous example, you could have named your custom component
TextArea, and written it to the TextArea.as file in the myComponents directory, as the
following example shows:
package myComponents
{
import mx.controls.TextArea;
import flash.events.KeyboardEvent;
You can now use your custom TextArea control, and the standard TextArea control, in an
application. To differentiate between the two controls, you use the namespace prefix, as the
following example shows:
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*" >
<MyComp:TextArea/>
<mx:TextArea/>
</mx:Application>
To create a component that takes tag attributes in MXML, you define a public variable with
the same name as the tag attribute in your class definition:
public class MyCustomComponent extends TextArea {
You can also use public getter and setter methods to define a property, as the following
example shows:
public class MyCustomComponent extends TextArea {
You can define and initialize a private variable, as the following example shows:
private var _prop2:Number=5;
When you specify a value to the property in MXML, Flex automatically calls the setter
method. If you do not set the property in MXML, Flex sets it to its initial value, if you
specified one, or to the type’s default value, which is NaN for a variable of type Number.
// as/myComponents/TextAreaFontControl.as
import mx.controls.TextArea;
import flash.events.KeyboardEvent;
import flash.events.Event;
<MyComp:TextAreaFontControl id="myTAFS"
minFontSize="8"
maxFontSize="50"/>
<mx:Button
label="Get Font Size"
click="myTA.text=String(myTAFS.getStyle('fontSize'));"/>
<mx:TextArea id="myTA"/>
</mx:Application>
<MyComp:TextAreaDefaultProp>Hello</MyComp:TextAreaDefaultProp>
</mx:Application>
<MyComp:defaultText>Hello</MyComp:defaultText>
</MyComp:TextAreaDefaultProp>
You can also use the [Inspectable] metadata tag with setter and getter methods. For more
information, see Chapter 5, “Using Metadata Tags in Custom Components,” on page 45.
The current value of the HSlider control appears in the Text control when you stop moving
the slider. To get continuous updates as you move the slider, set the HSlider.liveDragging
property to true.
<MyComp:TextAreaFontControl id="myTA"
maxFontSize="{Number(myTI.text)}"/>
</mx:Application>
In this example, any value that the user enters into the TextInput control is automatically
copied to the maxFontSize property.
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.
If you omit the event name from the [Bindable] metadata tag, Flex automatically dispatches
an event named propertyChange when the property changes to trigger the data binding. If
the property value remains the same on a write, Flex does not dispatch the event or update the
property.
}
}
In this example, the setter updates the value of the property, and then dispatches an event to
trigger an update of any data binding destination. The name of the event is not restricted. You
can use this component in an application, as the following example shows:
<?xml version="1.0"?>
<!-- as/MainTextAreaFontControlBindingSource.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*">
<MyComp:TextAreaFontControlBinding id="myTA"
maxFontSize="{Number(myTI.text)}"/>
</mx:Application>
// Call super.addChild().
super.addChild(child);
return child;
}
}
}
Notice that the method implementation calls the super.addChild() method. The call to
super.addChild() causes Flex to invoke the superclass’s addChild() method to perform the
operation. Your new functionality to open the Alert box occurs after the super.addChild()
method.
You might have to use super() to call the base class method before your code, after your
code, or not at all. The location is determined by your requirements. To add functionality to
the method, you call super() before your code. To replace the base class method, you do not
call super() at all.
<mx:Script>
<![CDATA[
import mx.controls.Button;
<MyComp:HBoxWithAlert id="myHBox">
</MyComp:HBoxWithAlert>
</mx:Application>
<mx:TextInput id="myInput"/>
<mx:TextInput id="myOutput"/>
</MyComps:MyPanel>
Notice that the value of the id property for the two TextInput controls matches the variable
names of the properties defined in the MyPanel component. Therefore, Flex initializes the
inherited properties with the TextInput controls that you defined in MXML. This technique
for initializing properties can be referred to as code behind.
<MyComps:MyPanelComponent id="myP"/>
</mx:Application>
If the value of the id property of a TextInput control does not match an inherited property
name, Flex creates a property of the component, where the id property defines the name of
the new property.
To support initialization from MXML, an inherited property must have the following
characteristics:
■ The inherited property must be public.
If you try to initialize a non-public inherited property, the Flex compiler issues an error.
■ The inherited property must be writable.
If you try to initialize a constant, or a property defined by a getter method without a
corresponding setter method, the Flex compiler issues an error.
■ The data type of the value that you specify to the inherited property must by compatible
with the data type of the property.
If you try to initialize a property with a value of an incompatible data type, the Flex
compiler issues an error.
<mx:Script>
<![CDATA[
import flash.events.Event;
]]>
</mx:Script>
<MyComp:MyButton
click="handleClick(event);"
creationComplete="handleCreationComplete(event);"/>
</mx:Application>
Your custom components can also define new events based on the requirements of your
components. For example, the section “Using data binding with custom properties”
on page 132 showed how to define a custom event so that properties of your component can
work with the Flex data binding mechanism.
This section describes how to handle events within a custom component and how to create
events for it.
Even though you define event listeners for the events in the component itself, your
application can also register listeners for those events. The event listeners defined within
the component execute before any listeners defined in the application.
The example used the creationComplete event to access the default fontSize property of
the component. You could not access this property in the constructor itself because Flex does
not define it until after the component is created. For more information on the initialization
order of a component, see Chapter 10, “Creating Advanced Visual Components in
ActionScript,” on page 149.
// Dispatch event.
dispatchEvent(new Event("enableChanged"));
}
The eventObj argument is the event object that describes the event.
If you want an MXML component to be able to register a listener for the event, you must
make the event known to the Flex compiler by using the [Event] metadata tag. For each
public event that your custom component dispatches, you add an [Event] metadata keyword
before the class definition that defines that event; for example:
[Event(name="enableChanged", type="flash.events.Event")]
public class ModalText extends TextArea {
...
}
You can then handle the event in MXML, as the following example shows:
<?xml version="1.0"?>
<!-- as/MainModalTextEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComps="myComponents.*">
<mx:Script>
<![CDATA[
import flash.events.Event;
<MyComps:ModalTextEvent id="myMT"
enableChanged="handleEnableChanged(event);"/>
<mx:Button click="myMT.enableInput(true);"/>
<mx:TextArea id="myTA"/>
</mx:Application>
<MyComps:BlueButton label="Submit"/>
</mx:Application>
Setting the styles in constructor does not prevent users of the component from changing the
style. For example, the user could still set their own value for the color style, as the following
example shows:
<?xml version="1.0"?>
<!-- as/MainBlueButtonRed.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComps="myComponents.*">
</mx:Application>
CHAPTER 10
Contents
About creating advanced components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Implementing the component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Making components accessible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Adding version numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Best practices when designing a component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Example: Creating a composite component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
149
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
You usually create a component as a subclass of an existing class. For example, to create a
component that is based on the Button control, you create a subclass of the
mx.controls.Button class. To make your own component, you create a subclass of the
mx.core.UIComponent class.
UIComponent Description
method
commitProperties() Commits any changes to component properties, either to make the
changes occur at the same time, or to ensure that properties are set in
a specific order.
For more information, see “Implementing the commitProperties()
method” on page 160.
createChildren() Creates any child components of the component. For example, the
ComboBox control contains a TextInput control and a Button control
as child components.
For more information, see “Implementing the createChildren() method”
on page 159.
layoutChrome() Defines the border area around the container for subclasses of the
Container class.
For more information, see “Implementing the layoutChrome() method”
on page 168.
measure() Sets the default size and default minimum size of the component.
For more information, see “Implementing the measure() method”
on page 164.
updateDisplayList() Sizes and positions the children of the component on the screen based
on all previous property and style settings, and draws any skins or
graphic elements used by the component. The parent container for the
component determines the size of the component itself.
For more information, see “Implementing the updateDisplayList()
method” on page 168.
When a component calls an invalidation method, it signals to Flex that the component must
be updated. When multiple components call invalidation methods, Flex coordinates updates
so that they all occur together during the next screen update.
Typically, component users do not call the invalidation methods directly. Instead, they are
called by the component’s setter methods, or by any other methods of a component class as
necessary. For more information and examples, see “Implementing the commitProperties()
method” on page 160.
The following steps show what occurs when you execute the code to create the Button
control, and add the control to the Box container:
1. You call the component’s constructor, as the following code shows:
// Create a Button control.
var b:Button = new Button()
2. You configure the component by setting its properties, as the following code shows:
// Configure the button control.
b.label = "Submit";
6. After the last render event occurs, Flex performs the following actions:
a. Makes the component visible by setting the visible property to true.
b. Dispatches the creationComplete event on the component. The component is sized
and processed for layout. This event is only dispatched once when the component is
created.
c. Dispatches the updateComplete event on the component. Flex dispatches additional
updateComplete events whenever the layout, position, size, or other visual
characteristic of the component changes and the component is updated for display.
Most of the work for configuring a component occurs when you add the component to a
container by using the addChild() method. That is because until you add the component to
a container, Flex cannot determine its size, set inheriting style properties, or draw it on the
screen.
You can also define your application in MXML, as the following example shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Box>
<mx:Button label="Submit"/>
</mx:Box>
</mx:Application>
The sequence of steps that Flex executes when creating a component in MXML are equivalent
to the steps described for ActionScript.
About interfaces
Flex uses interfaces to divide the basic functionality of components into discrete elements so
that they can be implemented piece by piece. For example, to make your component
focusable, it must implement the IFocusable interface; to let it participate in the layout
process, it must implement ILayoutClient interface.
To simplify the use of interfaces, the UIComponent class implements all of the interfaces
defined in the following table, except for the IFocusManagerComponent and
IToolTipManagerClient interfaces. However, many subclasses of UIComponent implement
the IFocusManagerComponent and IToolTipManagerClient interfaces.
Therefore, if you create a subclass of the class or subclass of UIComponent, you do not have
to implement these interfaces. But, if you create a component that is not a subclass of
UIComponent, and you want to use that component in Flex, you might have to implement
one or more of these interfaces.
N OTE
For Flex 2, Adobe recommends that all of your components extend the UIComponent
class or a class that extends UIComponent.
Interface Use
IChildList Indicates the number of children in a container.
IUIComponent Defines the basic set of APIs that you must implement
in order to be a child of layout containers and lists.
You must define your ActionScript custom components within a package. The package
reflects the directory location of your component within the directory structure of your
application.
The class definition of your component must be prefixed by the public keyword. A file that
contains a class definition can have one, and only one, public class definition, although it can
have additional internal class definitions. Place any internal class definitions at the bottom of
your source file below the closing curly brace of the package definition.
Notice in this example that the createChildren() method calls the addChild() method to
add the child component. You must call the addChild() method for each child object.
After you create a child component, you can use properties of the child component to define
its characteristics. In this example, you create the Button and TextArea controls, initialize
them, and register event listeners for them. You could also apply skins to the child
components. For a complete example, see “Example: Creating a composite component”
on page 174.
As you can see in this example, the setter method modifies the property, calls the
invalidateProperties() and invalidateDisplayList() methods, then returns. The
setter itself does not perform any calculations based on the new property value. This design
lets the setter method return quickly, and leaves any processing of the new value to the
commitProperties() method.
In a subclass of an existing component, you might implement the measure() method only if
you are performing an action that requires modification to the default sizing rules defined in
the superclass. Therefore, to set a new default size, or perform calculations at run time to
determine component sizing rules, implement the measure() method.
You set the following properties in the measure() method to specify the default size:
The measure() method only sets the default size of the component. In the
updateDisplayList() method, the parent container of the component passes to it its actual
size, which may be different than the default size.
measuredWidth=100;
measuredMinWidth=50;
measuredHeight=50;
measuredMinHeight=25;
}
}
}
The following application uses this button in an application:
<?xml version="1.0"?>
<!-- asAdvanced/MainBlueButton.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*" >
<mx:VBox>
<MyComp:BlueButton/>
<mx:Button/>
</mx:VBox>
</mx:Application>
In the absence of any other sizing constraints on the button, the VBox container uses the
default size and default minimum size of the button to calculate its size at run time. For
information on the rules for sizing a component, see Chapter 15, “Introducing Containers,”
in Flex Developer’s Guide.
<mx:VBox>
<MyComp:BlueButton width="50%"/>
<mx:Button/>
</mx:VBox>
</mx:Application>
In this example, you specify that the width of the button is 50% of the width of the VBox
container. When 50% of the width if the container is smaller than the minimum width of the
button, the button uses its minimum width.
// The default size is the size of the text plus a 10 pixel margin.
override protected function measure():void {
super.measure();
</mx:Application>
Typically, you use the RectangularBorder class to define the border area of a container. For
example, you can create the RectangularBorder object, and add it as a child of the component
in your override of the createChildren() method.
When you create a subclass of the Container class, you can use the createChildren()
method to create the content children of the container; the content children are the child
components that appear within the container. You then use updateDisplayList() to
position the content children.
You typically use the layoutChrome() method to define and position the border area of the
container, and any additional elements that you want to appear in the border area. For
example, the Panel container uses the layoutChrome() method to define the title area of the
panel container, including the title text and close button.
The primary reason for dividing the handling of the content area of a container from its
border area is to handle the situation when the Container.autoLayout property is set to
false. When the autoLayout property is set to true, measurement and layout of the
container and of its children are done whenever the position or size of a container child
changes. The default value is true.
When the autoLayout property is set to false, measurement and layout are done only once,
when children are added to or removed from the container. However, Flex executes the
layoutChrome() method in both cases. Therefore, the container can still update its border
area even when the autoLayout property is set to false.
super.updateDisplayList(unscaledWidth, unscaledHeight);
<MyComp:BottomUpVBox>
<mx:Label text="Label 1"/>
<mx:Button label="Button 1"/>
</MyComp:BottomUpVBox>
</mx:Application>
super.updateDisplayList(unscaledWidth, unscaledHeight);
For example, the following line enables accessibility for the MyButton component:
mx.accessibility.MyButton.enableAccessibility();
For additional information about accessibility, see Chapter 39, “Creating Accessible
Applications,” in Flex Developer’s Guide.
Flex does not use or interpret the value of the version property.
If you create many components as part of a component package, you can include the version
number in an external file. That way, you update the version number in only one place. For
example, the following code imports the contents of an external file that stores the version
number in one place:
include "../myPackage/ComponentVersion.as"
The contents of the ComponentVersion.as file are identical to the previous variable
declaration, as the following example shows:
static var version:String = "1.0.0.42";
You can handle an event dispatched by a child of a composite component in the component.
In this example, the event listener for the Button control’s click event is defined in the class
definition to toggle the editable property of the TextArea control.
<mx:Script>
<![CDATA[
import flash.events.Event;
function handleText(eventObj:Event)
{
...
}
]]>
</mx:Script>
<MyComp:ModalText change="handleText(event);"/>
</mx:Application>
<MyComp:ModalText textPlacement="left"/>
</mx:Application>
You can handle the placementChanged event to determine when the
ModalText.textPlacement property is modified, as the following example shows:
<?xml version="1.0"?>
<!-- asAdvanced/MainModalTextEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*" >
<mx:Script>
<![CDATA[
import flash.events.Event;
</mx:Application>
[Embed(source="Modal2.swf", symbol="blueCircle")]
public var modeOverSkinName:Class;
[Embed(source="Modal2.swf", symbol="greenSquare")]
public var modeDownSkinName:Class;
if (bTextChanged) {
bTextChanged = false;
text_mc.text = _text;
invalidateDisplayList();
}
}
[Bindable(event="textChanged")]
public function get text():String {
return text_mc.text;
}
Troubleshooting
This section describes some common problems and their solutions when you create
components for Flex in Flash.
I get an error “don't know how to parse…” when I try to use the component from MXML.
This means that the compiler could not find the SWC file, or the contents of the SWC file
did not list the component. Ensure that the SWC file is in a directory that Flex searches, and
ensure that your xmlns property is pointing to the right place. Try moving the SWC file to
the same directory as the MXML file and setting the namespace to "*" as the following
example shows:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*">
For more information, see Chapter 9, “Using the Flex Compilers,” in Building and Deploying
Flex Applications.
I get an error “xxx is not a valid attribute…” when I try to use the component from MXML.
Ensure that the attribute is spelled correctly. Also ensure that it is not private.
I don't get any errors, but nothing appears.
Verify that the component was instantiated. One way to do this is to put a Button control and
a TextArea control in the MXML application and set the text property to the ID for the
component when the button is clicked; for example:
<!-- This verifies whether a component was instantiated. -->
<zz:mycomponent id="foo"/>
<mx:TextArea id="output"/>
<mx:Button label="Print Output" click="output.text = foo.id;"/>
public class B {
static function bar():Number {
return mx.example.A.foo();
}
It is possible that there is another class or SWC file that overrides your custom class or the
symbols used in your component. Ensure that there are no naming conflicts.
Troubleshooting 183
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
CHAPTER 11
Contents
About styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Example: Creating style properties. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
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 from parent containers to their children, 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. Also, you can override individual
properties for each control at a local, document, or global level, giving you great flexibility in
controlling the appearance of your applications.
For more information, see Chapter 20, “Using Styles and Themes,” in Flex Developer’s Guide.
185
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
About inheritance in Cascading Style Sheets
When you implement a style property in an ActionScript component, that property is
automatically inherited by any subclasses of your class, just as methods and properties are
inherited. This type of inheritance is called object-oriented inheritance.
Some style properties also support Cascading Style Sheet (CSS ) inheritance. CSS inheritance
means that if you set the value of a style property on a parent container, a child of that
container inherits the value of the property when your application runs. For example, if you
define the fontFamily style as Times for a Panel container, all children of that container use
Times for fontFamily, unless they override that property.
In general, color and text styles support CSS inheritance, regardless of whether they are set by
using CSS or style properties. All other styles do not support CSS inheritance, unless
otherwise noted.
If you set a style on a parent that does not support CSS inheritance, such as textDecoration,
only the parent container uses that value, and not its children. There is an exception to the
rules of CSS inheritance. If you use the global type selector in a CSS style definition, Flex
applies those style properties to all controls, regardless of whether the properties are
inheritable.
For more information about style inheritance, see Chapter 20, “Using Styles and Themes,” in
Flex Developer’s Guide.
<mx:Style>
TextArea {backgroundColor: "0x0000FF"}
</mx:Style>
<mx:TextArea/>
</mx:Application>
You can also import an external CSS file, as the following example shows:
<mx:Style source="myStyle.css"/>
super.styleChanged(styleProp);
The styleChanged() method first calls superclass’s styleChanged() method to let the
superclass handle the style change.
After the superclass gets a call to handle the style change, your component can detect that the
user set the backgroundColor style, and handle it. By handling the style change after the
superclass makes the change, you can override the way the superclass handles the style.
Notice that the method calls the invalidateDisplayList() method, which causes Flex to
execute the component’s updateDisplayList() method at the next screen update. Although
you can detect style changes in the styleChanged() method, you still use the
updateDisplayList() method to draw the component on the screen. For more information,
see “Defining a style property” on page 191.
super.updateDisplayList(unscaledWidth, unscaledHeight);
<!-- By default, use the style defined by the CSS type selector. -->
<MyComp:StyledRectangle id="mySR1"/>
<!-- By default, use the style defined by the CSS type selector. -->
<MyComp:StyledRectangle id="mySR2"/>
<!-- Change the default style by using the setStyle() method. -->
<mx:Button label="Set gradient"
click="mySR2.setStyle('fillColors', [0x000000, 0xFFFFFF]);"/>
</mx:Application>
In this example, the CSS type selector for the StyledRectangle component sets the initial
values of the fillColors property to #FF00FF and #00FFFF. For the second StyledRectangle
components, you use the click event of a Button control to change the fillColor style by
using the setStyle() method. The third component sets the style property by using an
MXML tag attribute.
For more information, see Chapter 5, “Using Metadata Tags in Custom Components,” on
page 45.
2. Override the styleChanged() method to detect changes to the property.
3. Override updateDisplayList() method to incorporate the style into the component
display.
4. Define a static initializer to set the default value of the style property.
For more information, see “Setting default style values” on page 194.
// Constructor
public function StyledRectangle() {
super();
}
super.styleChanged(styleProp);
}
}
}
}
<MyComp:StyledRectangle/>
</mx:Application>
<mx:Style>
StyledRectangle {fillColors: #FF00FF, #00FFFF}
</mx:Style>
<MyComp:StyledRectangle/>
</mx:Application>
For more information on creating skins, see Chapter 22, “Creating Skins,” in Flex Developer’s
Guide.
CHAPTER 12
Creating Template
Components
12
One way to create reusable components is to define them as template components. A template
component defines properties with a general data type that lets the component user specify an
object of a concrete data type when using the component. By using a general data type to
define component properties, you create highly reusable components that can work with
many different types of objects.
This topic describes how to create template components.
Contents
About template components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Implementing a template component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
197
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
The following example shows an application that uses a template component called
MyTemplateComponent:
<?xml version="1.0"?>
<!-- templating/MainTemplateButton.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myComponents.*"
height="700" width="700">
<MyComp:MyTemplateComponent id="myTComp1">
<MyComp:topRow>
<mx:Label text="top component"/>
</MyComp:topRow>
<MyComp:bottomRow>
<mx:Button label="Button 1"/>
<mx:Button label="Button 2"/>
<mx:Button label="Button 3"/>
</MyComp:bottomRow>
</MyComp:MyTemplateComponent>
</mx:Panel>
</mx:Application>
The MyTemplateComponent takes two properties:
■ The topRow property specifies the single Flex component that appears in the top row of
the VBox container.
■ The bottomRow property specifies one or more Flex components that appear along the
bottom row of the VBox container.
The implementation of the MyTemplateComponent consists of a VBox container that
displays its children in two rows. The following image shows the output of this application:
<MyComp:MyTemplateComponent id="myTComp2">
<MyComp:topRow>
<mx:TextArea text="top component"/>
</MyComp:topRow>
<MyComp:bottomRow>
<mx:LinkButton label="Link 1"/>
<mx:LinkButton label="Link 2"/>
<mx:LinkButton label="Link 3"/>
</MyComp:bottomRow>
</MyComp:MyTemplateComponent>
</mx:Panel>
</mx:Application>
In this example, the top component is a TextArea control, and the bottom components are
two LinkButton controls.
<mx:Script>
<![CDATA[
import mx.containers.HBox;
import mx.core.UIComponent;
<mx:Script>
<![CDATA[
import mx.containers.HBox;
import mx.core.UIComponent;
The user of the component can then specify an object of any type to the property. It is your
responsibility in the component implementation to verify that the value passed by the user is
of the correct data type.
The Flex compiler validates that users only assign values of the specified type to the property.
In this example, if the component user sets the topRow property to a value of a type other
than mx.controls.Label, the compiler issues an error message.
In the first example, you can assign a value of any data type to the bottomRow property. Each
array element's getInstance() method is not called until the element is used.
<mx:Script>
<![CDATA[
import mx.containers.HBox;
import mx.core.UIComponent;
[InstanceType("mx.controls.Label")]
public var topRow:IDeferredInstance;
addChild(controlHBox);
}
]]>
</mx:Script>
</mx:VBox>
PART 4
207
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
CHAPTER 13
Contents
Creating a custom formatter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Using the SwitchSymbolFormatter class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Extending a Formatter class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
209
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
Creating a custom formatter
You create a custom formatter by creating a class that extends the mx.formatters.Formatter
base class, or by creating a class that extends one of the standard formatter classes, which all
extend mx.formatters.Formatter. The following example shows the class hierarchy for
formatters:
Formatter
Like standard formatter classes, your custom formatter class must contain a public format()
method that takes a single argument and returns a String that contains the formatted data.
Most of the processing of your custom formatter occurs within the format() method.
Your custom formatter also might let the user specify which pattern formats the data. Where
applicable, the Flex formatters, such as the ZipCodeFormatter, use a formatString property
to pass a format pattern. Some Flex formatters, such as the NumberFormatter and
CurrencyFormatter classes, do not have formatString properties, because they use a set of
properties to configure formatting.
// Constructor
public function SimpleFormatter() {
// Call base class constructor.
super();
}
// Override format().
override public function format(value:Object):String {
// 1. Validate value - must be a nonzero length string.
if( value.length == 0)
{ error="0 Length String";
return ""
}
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myFormatters.*">
<!-- Trigger the formatter while populating a string with data. -->
<mx:TextInput id="myTI" />
</mx:Application>
The namespace declaration in the <mx:Application> tag specifies to use the MyComp prefix
when referencing the formatter, and the location of the formatter’s ActionScript file. That file
is in the myFormatters subdirectory of the application, or in the default classpath of the
application. For more information on deploying your formatters, see Chapter 6, “Compiling
Components,” on page 63.
// Constructor
public function CustomSSFormatter() {
// Call base class constructor.
super();
}
// Override format().
override public function format( value:Object ):String {
// Validate input string value - must be a 9-digit number.
// You must explicitly check if the value is a number.
// The formatter does not do that for you.
if( !value || value.toString().length != 9)
{ error="Invalid String Length";
return ""
}
if( numCharCnt != 9 )
{
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myFormatters.*">
<!-- Trigger the formatter while populating a string with data. -->
<mx:TextInput text="Your SS number is {SSFormat.format('123456789')}"/>
</mx:Application>
// Constructor
public function ExtendedZipCodeFormatter() {
// Call base class constructor.
super();
// Initialize formatString.
formatString = "#####*####";
}
// Override format().
override public function format(value:Object):String {
// 1. If the formatString is our new pattern,
// then validate and format it.
<!-- Trigger the formatter while populating a string with data. -->
<mx:TextInput width="200"
text="Your zipcode number is {ZipCodeFormat.format('123456789')}"/>
</mx:Application>
CHAPTER 14
Contents
Validating data by using custom validators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Example: Validating multiple fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .224
219
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
The following image shows the class hierarchy for validators:
Validator
In the doValidation() method of your validator class, you typically call the base class’s
doValidation() method to perform the verification for a required field. If the user did not
enter a value, the base class issues a validation error stating that the field is required.
The remainder of the doValidation() method contains your custom validation logic.
// Constructor.
public function AgeValidator() {
// Call base class constructor.
super();
}
return results;
}
}
}
This example first defines a public constructor that calls super() to invoke the constructor of
its base class. The base class can perform the check to ensure that data was entered into a
required field, if you set the required property of the validator to true.
Notice that the second argument of the constructor for the ValidationResult class is null. You
use this argument to specify a subfield, if any, of the object being validated that caused the
error. When you are validating a single field, you can omit this argument. For an example that
validates multiple fields, see “Example: Validating multiple fields” on page 224.
You can use this validator in your Flex application, as the following example shows:
<?xml version="1.0" ?>
<!-- validators/MainAgeValidator.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:MyComp="myValidators.*">
<MyComp:AgeValidator id="ageV"
required="true"
source="{birthYear}"
property="text" />
<mx:Form >
<mx:FormItem label="Enter birth year: ">
<mx:TextInput id="birthYear"/>
</mx:FormItem>
<mx:FormItem label="Enter birth year: ">
<mx:Button label="Submit"/>
</mx:FormItem>
</mx:Form>
</mx:Application>
The package statement for your custom validator specifies that you should deploy it in a
directory called myValidators. In the previous example, you place it in the subdirectory of
the directory that contains your Flex application. Therefore, the namespace definition in your
Flex application is xmlns:MyComp="myValidators.*". For more information on
deployment, see Chapter 6, “Compiling Components,” on page 63.
<mx:Model id="person">
<name>
<custName>
<first>{firstInput.text}</first>
<middle>{middleInput.text}</middle>
<last>{lastInput.text}</last>
</custName>
</name>
</mx:Model>
<mx:TextInput id="firstInput"/>
<mx:TextInput id="middleInput"/>
<mx:TextInput id="lastInput"/>
<MyComp:NameValidator id="nameVal"
source="{person}" property="custName"
listener="{firstInput}"/>
</mx:Application>
This validator examines three input fields. You specify firstInput as the validation listener.
Therefore, when a validation error occurs, Flex shows a validation error message on the first
TextInput control.
return results;
}
}
}
In this example, because you are using a single validator to validate three subfields of the
Object passed to the validator, you include the optional second argument to the constructor
for the ValidationResult class to specify the subfield that caused the validation error. This
inclusion permits Flex to identify the input component that caused the error, and to highlight
that component in the application.
return results;
}
}
}
Notice that you remove the return statement from the body of the if statements so that the
method contains only a single return statemen. This modification allows you to detect three
different validation errors at once.
CHAPTER 15
Creating Effects 15
Behaviors let you add animation and motion to your application when some user or
programmatic action occurs, where 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. For example, you can
use behaviors to cause a dialog box to bounce slightly when it receives focus, or to slowly fade
in when it becomes visible.
Adobe Flex supplies a number of standard effects that you can use in your application.
However, you also can define custom effects for your specific application needs. This topic
describes how to create custom effects.
For information on the standard effects, see Chapter 19, “Using Behaviors,” in Flex Developer’s
Guide.
Contents
About creating a custom effect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
About tween effects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .239
Writing an effect for a transition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .242
Defining a custom effect trigger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
229
Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta 1 Flex 3 Beta
About creating a custom effect
Flex implements effects by using an architecture in which each effect is represented by two
classes: a factory class and an instance class. Therefore, to implement a custom effect, you
create two classes: the factory class and the instance class.
You create a factory class by creating a subclass of the mx.effects.Effect class, or by creating a
subclass of one of the subclasses of the mx.effects.Effect class. You create an instance class by
creating a subclass of the mx.effects.EffectInstance class, or a subclass of one of the subclasses
of the mx.effects.EffectInstance class.
The following image shows the class hierarchy for effects:
Effect
Factory classes
EffectInstance
Instance classes
By convention, the name of a factory class is the name of the effect, such as Zoom or Fade.
Instance class The instance class implements the effect logic. When an effect trigger
occurs, or when you call the play() method to invoke an effect, the factory class creates an
object of the instance class to perform the effect on the target. When the effect ends, Flex
destroys the instance object. If the effect has multiple target components, the factory class
creates multiple instance objects, one per target.
By convention, the name of an instance class is the name of the effect with the suffix Instance,
such as ZoomInstance or FadeInstance.
Additional methods and properties (Optional) Define any additional methods and
properties that the user requires to configure the
effect.
Additional methods and properties (Optional) Define any additional methods and
properties. These typically correspond to the public
properties and methods from the factory class, and
any additional properties and methods that you
require to implement the effect.
// Define constructor.
public function MySoundInstance(targetObj:Object) {
super(targetObj);
}
</mx:Application>
To make your effects more robust, you often design them to let the user pass parameters to
them. The example in this section modifies the sound effect from the previous section to take
a parameter that specifies the MP3 file to play:
package myEffects
{
// MySoundParam.as
import mx.effects.Effect;
import mx.effects.EffectInstance;
import mx.effects.IEffectInstance;
// Define constructor.
public function MySoundParamInstance(targetObj:Object) {
super(targetObj);
}
<MyComps:MySoundParam id="mySoundEffect"
soundMP3="http://localhost:8100/flex/assets/sample.mp3"/>
</mx:Application>
This section describes how to create a tween effect. However, Flex supplies the
AnimateProperty class that you can use to create a tween effect for a single property of the
target component. For more information, see Chapter 19, “Using Behaviors,” in Flex
Developer’s Guide.
<MyComp:Rotation id="Rotate90"
angleFrom="0" angleTo="360"
duration="1000"/>
<mx:Image source="@Embed(source='../assets/myImage.jpg')"
mouseDownEffect="{Rotate90}"/>
</mx:Application>
In this example, you use the effect to rotate an image when the user clicks it.
In this example, the two Blur filters define the properties of the effect.
2. If the effect does not define the start values of the effect, the effect determines the values
from the EffectInstance.propertyChanges property passed to the effect instance. Flex
sets the propertyChanges property by using information from the current settings of the
component, as defined by the current view state. For more information on the
propertyChanges property, see “How Flex initializes the propertyChanges property”
on page 244.
In the example in step 1, notice that the Move and Resize effects do not define start values.
Therefore, Flex determines the start values from the current size and position of the effect
targets in the current view state, and passes that information to each effect instance by
using the propertyChanges property.
3. If the effect does not define the end values of the effect, the effect determines the values
from the Effectinstance.propertyChanges property passed to the effect instance. Flex
sets the propertyChanges property by using information about the component, as defined
by the destination view state. For more information on the propertyChanges property,
see “How Flex initializes the propertyChanges property” on page 244.
In the example in rule 1, Flex determines the end values of the Move and Resize effects
from the size and position of the effect targets in the destination view state. In some cases,
the destination view state defines those values. If the destination view state does not define
the values, Flex determines them from the setting of the base view state, and passes that
information to each effect instance by using the propertyChanges property.
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.
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
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:
{x:00, y:00, width:100, height:100}
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 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:
{x:100, y:100, width:200, height:200}
In the body of the Effectinstance.play() method, you can examine the information in
the propertyChanges property to configure the effect.
The following steps describe the actions that occur when you change view states. Notice that,
Flex initializes propertyChanges.start as part of step 4, and initializes
propertyChanges.end as part of step 7:
<!-- 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:Parallel>
<mx:Move duration="400"/>
<mx:Resize duration="400"/>
</mx:Parallel>
<MyComp:RotationTrans filter="move"/>
</mx:Sequence>
</mx:Transition>
</mx:transitions>
<!-- Define the Canvas container holdig the three Panel containers.-->
<mx:Canvas id="pm" width="100%" height="100%" >
<mx:Panel id="p1" title="One"
<mx:Metadata>
<!-- Define the metadata for the events and effect triggers. -->
[Event(name="darken", type="flash.events.Event")]
[Event(name="brighten", type="flash.events.Event")]
[Effect(name="darkenEffect", event="darken")]
[Effect(name="brightenEffect", event="brighten")]
</mx:Metadata>
<mx:Script>
<![CDATA[
import flash.events.Event;
if (_bright)
dispatchEvent(new Event("brighten"));
else
dispatchEvent(new Event("darken"));
}
</mx:Button>
When you declare an event in the form [Event(name="eventName",
type="package.eventType")], you can also create a corresponding effect, in the form
[Effect(name="eventnameEffect", event="eventname")]. As in the previous example,
in the <mx:Metadata> tag, you insert the metadata statements that define the two new events,
darken and brighten, and the new effect triggers, darkenEffect and brightenEffect, to
the Flex compiler.
For more information on using metadata, see Chapter 5, “Using Metadata Tags in Custom
Components,” on page 45.
<!-- Define two fade effects for darkening and brightening target. -->
<mx:Fade id="FadeOut" duration="1000" alphaFrom="1.00" alphaTo=".20"/>
<mx:Fade id="FadeIn" duration="1000" alphaFrom=".20" alphaTo="1.00"/>
</mx:Application>
where event is the Event object dispatched by the event that triggered the effect.
For example, a user might create an instance of an effect, but not provide all of the
configuration information that is required to play the effect. Although you might be able to
assign default values to all properties within the definition of the effect class, in some cases you
might have to determine the default values at run time.
In this method, you can examine the Event object and the effect target to calculate values at
run time. For more information on how to create a custom event and an effect trigger, see
“Defining a custom effect trigger” on page 249. As part of that example, you can add
properties to the Event object passed to the dispatchEvent() method. You can then access
that Event object, and its additional properties, from the initEffect() method.
By overriding the initEffect() method, you can also access the target property of the
Event object to reference the target component of the effect. For example, if you must
determine the current x and y coordinates of the component, or its current height and width,
you can access them from your override of the initEffect() method.
Index
253
Flex 3 Beta 1
deploying components 23 IDeferredInstance interface 201
dispatchEvent() method 144 images, Embed metadata keyword 49
import statement 27
Inspectable metadata keyword 49
E instance class 230
Effect metadata keyword 49 InstanceType metadata keyword 58
effects instantiation, troubleshooting custom components
custom 230 183
custom effect trigger 249 interfaces
defining custom 235 about 114, 156
for transitions 242 IMXMLObject interface 116
tween effects 239
Embed metadata keyword 49
enableAccessibility() method 173 K
Event class, creating a subclass 38 keywords, metadata 49
Event metadata keyword 49, 55, 59
events
about 35 L
adding 144 layoutChrome() method 168
custom 109 life cycle, component instantiation 152
defining in ActionScript components 141
dispatching custom events 38
Event metadata keyword 49, 55, 59 M
Event metadata tag 40 measure() method 164
from composite components 112 metadata keywords
handling 107 available 49
NonCommittingChangeEvent metadata keyword Bindable 49
59 custom components 47
extending classes 16 Embed 49
extending graphical components 174 Event 55, 59
NonCommittingChangeEvent 59
Style 59, 61, 191
F syntax 47
faceless components, definition 21 tags 49
factory class 230 using 47
formatters metadata tags
error handling 212 about 46
extending 216 Event 40
formatting, data methods
custom 210 defining 32
ZIP codes 213 overrides 138
MXML
ActionScript classes and 15
G custom components 19
getters 30, 96 custom properties and methods 92
multiple files 77
MXML components
I about 77
IconFile metadata keyword 49 creating 78
254
Flex 3 Beta 1
reusable 91 for metadata 49
See also specific tag names
template components
N about 197
NonCommittingChangeEvent metadata keyword 50, data types 199
59 transitions 242
troubleshooting 182
tween effects 239
P type selector 89
package statement 25
performance, RSLs 23, 68
postal codes, formatting 213
U
properties UIComponent methods 150
as getters and setters 30 updateDisplayList() method 168
as variables 30
commitProperties() method 161
getter and setters 128 V
getters and setters 96 validation, multiple fields example 224
inspectable 98 validators 220
MXML 95 VBox layout, overriding 170
versioning 173
visual components 149
R
runtime shared libraries (RSLs), definition 23, 68
S
scope
about 34
custom components 83
screen readers, accessibility in custom components 173
setters, defining for custom components 30, 96
skins, style property 195
startup time, RSLs 23, 68
static constants 42
Style metadata keyword 50, 59, 61, 191
styles
about 185
custom components 84, 145
setting 186
setting defaults 194
Style metadata keyword 50, 59, 61, 191
super keyword 33
SWC files, distributing components as 67
syntax, for metadata statements 47
T
tags
255
Flex 3 Beta 1
256