1 Step RoboPDF, ActiveEdit, ActiveTest, Authorware, Blue Sky Software, Blue Sky, Breeze, Breezo, Captivate, Central,
ColdFusion, Contribute, Database Explorer, Director, Dreamweaver, Fireworks, Flash, FlashCast, FlashHelp, Flash Lite,
FlashPaper, Flex, Flex Builder, Fontographer, FreeHand, Generator, HomeSite, JRun, MacRecorder, Macromedia, MXML,
RoboEngine, RoboHelp, RoboInfo, RoboPDF, Roundtrip, Roundtrip HTML, Shockwave, SoundEdit, Studio MX, UltraDev,
and WebHelp are either registered trademarks or trademarks of Macromedia, Inc. and may be registered in the United States or
in other jurisdictions including internationally. Other product names, logos, designs, titles, words, or phrases mentioned within
this publication may be trademarks, service marks, or trade names of Macromedia, Inc. or other entities and may be registered in
certain jurisdictions including internationally.
Third-Party Information
This guide contains links to third-party websites that are not under the control of Macromedia, and Macromedia is not
responsible for the content on any linked site. If you access a third-party website mentioned in this guide, then you do so at your
own risk. Macromedia provides these links only as a convenience, and the inclusion of the link does not imply that Macromedia
endorses or accepts any responsibility for the content on those third-party sites.
This article describes the details of creating advanced components for use in Macromedia Flex
applications. The majority of the work is in writing the ActionScript class file, which derives from
Flex existing classes, and adding your own custom functionality.
For an additional article on creating Flex components, including examples, see
Most new controls extend an existing class. If you want to create a component that is based on the
Button control, for example, you can subclass the mx.controls.Button class. However, if you want
to invent your own component, you will likely extend either the mx.core.UIComponent or
mx.core.UIObject class. Choosing one of these base classes is discussed later, but Macromedia
recommends that most custom components extend the UIComponent class rather than the
UIObject class.
Use the following general process for creating a new Flex component in Flash:
1 If necessary, create symbols for skins or icons in Flash.
2 Create an ActionScript class file.
a Extend one of the base classes (UIObject or UIComponent) or another component.
b Specify properties that the user can set using an MXML tag property.
c Embed graphics and skins.
d Implement the init() method.
5
Page 6
e Implement the createChildren() method.
f Implement the commitProperties() method.
g Implement the measure() method.
h Implement the layoutChildren() method.
i Implement the draw() method.
j Add properties, methods, styles, events, and other metadata.
3 Compile a SWC file using compc.
The ordering of methods that you implement in this process mirrors that in the component
instantiation life cycle. By understanding which methods are called and in what order, you can
better understand how you write a component’s class file. For more information, see “About the
component instantiation life cycle” on page 8.
Each of the steps in this process is described in more detail in the remainder of this document.
Writing the component’s ActionScript code
A component’s ActionScript class extends another class, adds methods, adds getters and setters,
and defines events and event handlers for the component. When you extend an existing
component class, you can inherit from only one class. ActionScript 2.0 does not allow multiple
inheritance.
To edit ActionScript class files, you can use any text editor or an Integrated Development
Environment (IDE).
Simple example of a class file
The following is a simple example of a class file called MyComponent.as. This example contains a
minimal set of imports, methods, and declarations for a component that inherits from the
UIObject class.
//Import packages.
import mx.core.UIComponent;
class MyComponent extends UIComponent {
// Define an empty constructor.
function MyComponent() {
}
// Override the init method, and call the parent’s init method.
function init():Void {
super.init();
// Call invalidate() to display graphics.
invalidate();
}
}
Selecting a parent class
Most components share some common behavior and functionality. Flex includes two base classes
to supply this commonality: UIObject and UIComponent. By extending these classes, your
components have a basic set of methods, properties, and events.
6Creating Advanced Components
Page 7
Note: Macromedia recommends that you base your components on the UIComponent class rather
than the UIObject class. The UIComponent class provides more built-in functionality, but maintains
the flexibility of extending the UIObject class.
UIObject and UIComponent are the base classes of the component architecture. Understanding
the principles at work in these two classes is important for building components.
The following table briefly describes the two base classes:
ClassExtendsDescription
mx.core.UIComponent
mx.core.UIObject
UIObjectUIComponent is the base class for all Flex components. It can
participate in tabbing, accept low-level events such as keyboard
and mouse input, and be disabled so it does not receive mouse
and keyboard input.
The UIComponent class lets you perform the following tasks:
• Create focus navigation
• Enable and disable components
• Resize components
Macromedia recommends using the UIComponent class rather
than the UIObject class as the base class for your custom
components.
MovieClip UIObject is the base class for all graphical objects. It can have
shape, draw itself, and be invisible.
The UIObject class lets you perform the following tasks:
• Edit styles
• Handle events
• Resize by scaling
Macromedia does not recommend using the UIObject class
rather than the UIComponent class as the base class for your
custom components.
About the UIObject and UIComponent classes
Components based on version 2 of the Macromedia Component Architecture descend from the
UIObject class, which wraps the MovieClip class. The MovieClip class is the base class for the
classes in Flash that can draw on the screen. By providing a wrapper around its methods and
properties, Flex makes the UIObject syntax more intuitive and improves the conceptual
management of representing graphic objects.
The UIObject (mx.core.UIObject) class hides the mouse handling and frame handling in the
MovieClip class. The UIObject class also defines the styles, skins, and event aspects of the
component architecture. The UIObject class and its subclasses broadcast their events just before
drawing. If you are familiar with Flash, this event is analogous to the
enterFrame() MovieClip
event. The UIObject class posts events to its listeners just before drawing when loading and
unloading, and when its layout changes (
move, resize).
A UIObject class or UIObject subclass resizes itself by scaling. When you change its size using the
setSize() method, the new dimensions are passed to the _width and _height properties of the
MovieClip class, which scale the subclass.
Writing the component’s ActionScript code7
Page 8
The UIComponent (mx.core.UIComponent) class is a subclass of the UIObject class. It defines
high-level behaviors that are specific to a graphical object. The UIComponent class handles enduser interactions (such as clicking and focus) and component enabling and disabling. The
UIComponent class inherits all the methods, properties, and events of the UIObject class.
Note: UIComponent also handles dragging, but you should not override the startDrag() method
when defining custom components.
Extending other classes
To make component construction easier, you can extend a subclass for any class in the component
architecture; you do not need to extend the UIObject or UIComponent class directly. For
example, if you want to create a component that behaves almost the same as a Button component
does, you can extend the Button class instead of recreating all the functionality of the Button class
from the base classes. If you extend any other component’s class, you extend these base classes by
default, because all components are subclasses of the UIComponent class, which is a subclass of
the UIObject class.
However, if you only want to modify a Button’s behavior, it is simpler to extend the Button class
as a custom MXML component. For more information, see Developing Flex Applications.
About the component instantiation life cycle
When you instantiate a new component, Flex calls a number of methods, and those methods call
other methods that you can override. Instantiating a new component in your application triggers
the following method calls by Flex:
1 Constructor
2 init()
3 createChildren()
4 commitProperties()
5 measure()
6 layoutChildren()
7 draw()
Each of the
commitProperties(), measure(), layoutChildren(), and draw() methods has a
corresponding invalidate method. For more information, see “About invalidation” on page 17.
The remaining sections describe each of these methods. For the purposes of initialization, you do
not need to add any explicit calls to these methods, because Flex initiates each call.
Writing the constructor
Generally, component constructors should be empty so that the object can be customized with its
properties interface. For example, the following code shows a constructor for MyComponent:
function MyComponent() {
}
In this example, when a new component is instantiated, Flex calls the MyComponent()
constructor.
You do not generally set properties in the constructor because the properties can be overridden by
later method calls. For more information, see “Implementing the init() method” on page 9.
8Creating Advanced Components
Page 9
Each class can contain only one constructor method; overloaded constructor methods are not
supported in ActionScript 2.0.
Implementing the init() method
Flash calls the
should call the superclass’s
init() method when the class is created. At a minimum, the init() method
init() method. The width and height of the component are not set
until after this method is called.
function init(Void):Void {
super.init();
invalidate();
}
Note: Do not create child objects in the
properties.
init() method. You should use it only for setting up initial
This init() method calls the invalidate() method. The invalidate() method signals to Flex
that just the visuals for the object have changed, but the size and position of subobjects have not
changed. The
invalidate() method calls the draw() method.
Implementing the createChildren() method
Components implement the
createChildren() method to create subobjects (such as other
components) in the component. Rather than calling the subobject’s constructor in the
createChildren() method, you call the createClassObject() method to instantiate a
subobject of your component.
The
createClassObject() method has the following signature:
createClassObject() method, you must know what those children are (for example,
ObjectThe name of the class.
StringThe name of the instance.
NumberThe depth for the instance.
ObjectThe object that contains the initialization properties.
a border or a button that you always need), because you must specify the name and type of the
object, plus any initialization parameters in the call to
createClassObject().
The following example calls the createClassObject() method to create a new Label object for
use inside a component:
createClassObject(Label, "label_mc", 1); // Create a label in the holder
You set properties in the call to the createClassObject() method by adding them as part of the
initObject argument. The following example sets the value of the label property:
At the end of the createChildren() method, call the necessary invalidate methods
(
invalidate(), invalidateSize(), or invalidateLayout()) to refresh the screen. For more
information, see “About invalidation” on page 17.
Implementing the commitProperties() method
Flex calls the
variables that are used by the
commitProperties() method before it calls the measure() method. It lets you set
measure() method after the constructor has finished and MXML
attributes have been applied.
Flex only calls the
commitProperties() method after it calls the invalidateProperties()
method.
For example, the ViewStack container uses the
performance. When you set the
ViewStack.selectedIndex property, the ViewStack container
does not display a new page right away. Instead, it privately stores a
commitProperties() method to maximize
pendingSelectedIndex
property. When it is time for Flash Player to update the screen, Flex calls the
commitProperties(), measure(), layoutChildren(), and draw() methods. In the
commitProperties() method, the ViewStack container checks to see whether the
pendingSelectedIndex property is set, and it updates the selected index at that time.
You use the
commitProperties() method to delay processing so that Flash Player avoids doing
computationally expensive, redundant work. For example, if a script changes the
ViewStack.selectedIndex property 15 times, you would want to minimize the number of
times the display of the ViewStack container updates when the
selectedIndex property changes.
By using the commitProperties() method, you can update the pendingSelectedIndex
property 15 times, and then do the rendering only once.
This is most useful for properties that are computationally expensive to update. If setting a
property is inexpensive, you can avoid using the
commitProperties() method.
Implementing the measure() method
Generally, Flex calls the
measure() method only once, when the component is instantiated. The
component’s container sets the initial size and Flex calculates the preferred minimum and
maximum sizes. You can use the
measure() method to explicitly set the size of the component,
although Macromedia does not recommend doing this when developing components.
10Creating Advanced Components
Page 11
You can set the following properties in the measure() method. Flex calculates the values of these
properties, but you can override them in the
measure() method:
• _measuredMinWidth
• _measuredMaxWidth
• _measuredMinHeight
• _measuredMaxHeight
• _measuredPreferredWidth
• _measuredPreferredHeight
The properties define limits for when the object is resized. These measured properties are used for
layout in containers if your component doesn’t explicitly set a
preferredHeight attribute.
Controls calculate the values of these based on runtime properties. For example, the Button
control’s
_measuredPreferredWidth property.
Note: Although you can let Flex determine these values for you, your application startup time will
decrease if you set them yourself.
measure() method examines how wide its label is in order to compute the value of the
By default, Flex sets the values of _measuredPreferredWidth and _measuredPreferredHeight
to the values of the current height and width, but you should override them. The following
example of the
measure() method from the Label component sets a default width and height if
the label text field is empty:
function measure(Void):Void {
var myTF = _getTextFormat();
var txt = text;
preferredWidth or
if (txt == undefined || txt.length < 2) {
txt = "Wj";
}
var textExt = myTF.getTextExtent2(txt);
var textW = textExt.width + 4;
var textH = textExt.height + 4;
draw() method displays objects on the screen. Whenever the component needs to draw an
interface element, it calls a
draw() method. You use the draw() method to create or modify
elements that are subject to change.
Everything is made visible in the
until its
draw() method is called. Any graphical assets that you bring in for the purposes of
draw() method. A border does not actually call the drawing API
measuring are invisible until the draw() method is called.
Do not call the
draw() method directly. Instead, call one of the invalidation methods, which then
calls the draw() method. Flex also calls the draw() method from the redraw() method.
However, Flex calls the
call an invalidation method if you want Flex to invoke the
redraw() method only if the object is invalidated, so you should actually
draw() or redraw() method. If you
do not call an invalidation method, the component remains invisible unless you set its visibility
property to
Flex also calls the
12Creating Advanced Components
true in MXML. For more information, see “About invalidation” on page 17.
draw() method after the layoutChildren() method.
Page 13
Inside the draw() method, you can use calls to the Flash drawing API, defined by the MovieClip
class, to draw borders, rules, and other graphical elements. You can also call the
which removes the visible objects. In general, to set lengths in the
this.layoutWidth and this.layoutHeight properties instead of width and height. For more
draw() method, you should use
clear() method,
information on the drawing API, see the MovieClip class in Flex ActionScript Language Reference.
The following example clears the component and then draws a border around the component:
function draw():Void {
clear();
if (bTextChanged) {
bTextChanged = false;
text_mc.text = text;
}
// Draw a border around everything.
drawRect(0, 0, this.layoutWidth, this.layoutHeight);
}
Defining getters and setters
Getters and setters provide visibility to component properties and control access to those
properties by other objects.
To define getter and setter methods, precede the method name with
get or set, followed by a
space and the property name. Macromedia recommends that you use initial capital letters for the
second word and each word that follows. For example:
public function get initialColorStyle(): Number
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 getter and setter variables with two underscores (__). In
addition, Macromedia recommends that you declare the variable as private.
The following example shows the declaration of
__initialColor, and getter and setter methods
that get and set the value of this property:
...
private var __initialColor:Color = 42;
...
public function get initialColor():Number {
return __initialColor;
}
public function set initialColor(newColor:Number) {
__initialColor = newColor;
}
You commonly use getters and setters in conjunction with metadata keywords to define properties
that are visible, bindable, and have other properties.
Defining MXML Properties
Your custom components are usable in MXML files. For example, if you define a component in
the class called MyComponent in the ActionScript file MyComponent.as, you can reference it in
MXML as the following example shows:
To make your components reusable in MXML, you can set component properties using tag
attributes. For example, you might want to allow the user to pass a value to your component, as
the following example shows:
<MyComponent prop1="3" />
To create components that take tag attributes in MXML, you define a variable with the same
name in your class definition:
class MyComponent extends UIComponent {
var prop1:Number;
...
}
Flex automatically initializes prop1 based on the value set in the MXML tag.
You can also add metadata to the variable definition. For example, if you are using Flex Builder,
you can insert the Inspectable metadata tag to define the property as user-editable (or inspectable),
as the following example shows:
[Inspectable(defaultValue="0")]
var prop1:Number;
You might also want to generate an event when the property is modified. For example, if you use
data binding, you can broadcast an event when the property is modified so that Flex can update
anything bound to the property. The following example causes Flex to broadcast an event named
changeProp1 when the property is modified:
[ChangeEvent("changeProp1")]
var prop1:Number;
You can also instruct your component to generate an event when a getter or setter method is
called, as the following example shows:
[ChangeEvent("change")]
function get selectedDate():Date
In most cases, you set the change event on the getter function, and dispatch the event on the
setter function using the
dispatchEvent() method. For more information on dispatching
events, see “Dispatching events” on page 15.
For more information on using metadata, see the chapter ‘Creating ActionScript Components’ in
Developing Flex Applications.
Embedding assets
Some components use new skins or other graphical assets to define the look of the component. In
these cases, you must embed the assets in the component. The source of the asset can be a file
such as a JPEG or you can extract symbols from SWF files.
To embed assets that your component uses, use the
Embed metadata keyword. You precede a
variable declaration with the Embed statement. The variable then contains a reference to the
embedded asset, which you use in the class.
The following example embeds two assets, arrowImageLarge and arrowImageSmall:
[Embed(source="arrowImageLarge.jpg")]
var largeArrow:String;
[Embed(source="arrowImageSmall.jpg")]
var smallArrow:String;
14Creating Advanced Components
Page 15
You add these keywords anywhere inside the class definition. For more information on
embedding assets, see Developing Flex Applications.
To create a SWF file from which you embed assets, create a new FLA file and insert new symbols.
For each symbol, select Export for ActionScript or place the symbols on the stage before saving
the file as a SWF file.
Handling events
The event model is a dispatcher-listener model based on the DOM Level 3 proposal for event
architectures. Every component in the architecture emits events in a standard format, as defined
by the convention. Those events vary across components, depending on the functionality that the
component provides.
Components generate and dispatch events and consume (listen to) other events. An object that
wants to know about another object’s events registers with that object. When an event occurs, the
object dispatches the event to all registered listeners by calling a method requested during
registration. To receive multiple events from the same object, you must register for each event.
Although every component can define unique events, events are inherited from the core classes of
the architecture, mx.core.UIObject and mx.core.UIComponent. These classes define low-level
component events, such as
draw, resize, move, load, and others that are fundamental to all
components. Subclasses of these classes inherit and broadcast these events.
Dispatching events
In the body of your component’s ActionScript class file, you broadcast events using the
dispatchEvent() method. The dispatchEvent() method has the following signature:
dispatchEvent(eventObj)
The eventObj argument is the event object that describes the event. You can explicitly build an
event object before dispatching the event, as the following example shows:
var eventObj = new Object();
eventObj.type = "myEvent";
dispatchEvent(eventObj);
You can also use the following shortcut syntax that sets the value of the type property for the
event object and dispatches the event in a single line:
dispatchEvent({type:"myEvent"});
The event object has an implicit property, target, that is a reference to the object that triggered
the event.
For each event that your custom component dispatches, you add an
Event metadata keyword
defining that event; for example:
[Event("myEvent")]
You add these keywords immediately before the class definition. If you do not identify an event in
the class file with the
Event metadata keyword, the compiler ignores the event during
compilation, and Flex ignores this event triggered by the component during runtime.
Writing the component’s ActionScript code15
Page 16
For example, you define a component called ModalText as the following example shows:
[Event("myEvent")]
class ModalText extends UIComponent {
...
}
Within the body of your class definition, you then use the dispatchEvent() method to dispatch
myEvent. You can then handle the event in MXML as the following example shows:
text_mc.editable = false;
} else if (evt.type = "click") {
text_mc.editable = !text_mc.editable;
}
}
By default, Flex calls the handleEvent() method of a component whenever it generates an event.
16Creating Advanced Components
Page 17
About invalidation
Macromedia recommends that a component not update itself immediately in most cases, but
instead save a copy of the new property value, set a flag indicating what changed, and call one of
the invalidation methods.
The following are the invalidation methods:
invalidateSize() Indicates that one of the _measured properties have changed. This results in a
call to the
_measured properties, it calls the layoutChildren() method.
invalidateLayout() Indicates that the position and/or size of one of the subobjects have
changed, but the
layoutChildren() method. If you change a subobject in the layoutChildren() method, call
the
invalidate() Indicates that just the visuals for the object have changed, but the size and position
of subobjects have not changed. This method calls the
method from your implementation of the
invalidateProperties() Indicates that you have changed properties. This method calls the
commitProperties() method.
You should call the
measure() method. If the measure() method changes the value of one of the
_measured properties have not been affected. This results in a call to the
invalidate() method.
draw() method. You typically call this
init() method.
invalidateSize() method infrequently, because it measures and redraws
everything on the screen, and this can be a computationally expensive action. Sometimes you
need to call more than one of these methods to force a layout, even though the computed sizes
did not change.
You must call an invalidation method at least once during the instantiation of your component.
The most common place for you to do this is in the
createChildren() or layoutChildren()
method.
Compiling components
When you finish writing the ActionScript classes and designing the embedded assets that
comprise your component, you compile it into a SWC file using the compc utility.
The following example compiles the MyComponent component into the MyComponent.swc
file:
compc –root .. –o MyComponent.swc MyComponent.as
After you generate a SWC file, you can use it in your Flex applications by copying it to the
flex_app_root/WEB-INF/flex/user_classes directory. You can also copy SWC files to a directory
specified by the
top level of the user_classes directory or the directory specified by the <lib-path> element. You
cannot store SWC files in subdirectories.
For more information on using the compc utility, see Developing Flex Applications.
<lib-path> child tag in the flex-config.xml file. SWC files must be stored at the
Compiling components17
Page 18
Making components accessible
A growing requirement for web content is that it should be accessible to people who have
disabilities. Visually impaired people can use the visual content in Flash applications by means of
screen reader software, which provides an audio description of the material on the screen.
When you create a component, you can include ActionScript that enables the component and a
screen reader to communicate. Then, when developers use your component to build an
application in Flash, they use the Accessibility panel to configure each component instance.
Flash MX 2004 includes the following accessibility features:
• Custom focus navigation
• Custom keyboard shortcuts
• Screen-based documents and the screen authoring environment
• An Accessibility class
To enable accessibility in your component, add the following line to your component’s class file:
For example, the following line enables accessibility for the MyButton component:
mx.accessibility.MyButton.enableAccessibility();
When developers add the MyButton component to an application, they can use the Accessibility
panel to make it available to screen readers.
Adding versioning
When releasing components, you should define a version number. This lets developers know
whether they should upgrade, and helps with technical support issues. When you set a
component’s version number, use the static variable
static var version:String = "1.0.0.42";
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";
version, as the following example shows:
Best practices when designing a component
Use the following practices when you design a component:
• Keep the file size as small as possible.
• Make your component as reusable as possible by generalizing functionality.
• Use the Border class rather than graphical elements to draw borders around objects.
• Use tag-based skinning.
18Creating Advanced Components
Page 19
• Assume an initial state. Because style properties are on the object, you can set initial settings for
styles and properties so your initialization code does not have to set them when the object is
constructed, unless the user overrides the default state.
• When defining the symbol, do not select the Export in First Frame option unless it is
absolutely necessary. Flash loads the component just before it is used in your Flash application,
so if you select this option, Flash preloads the component in the first frame of its parent. The
reason you typically do not preload the component in the first frame is for considerations on
the web: the component loads before your preloader begins, defeating the purpose of the
preloader.
• Always implement an init() method and call the super.init() method, but otherwise keep
the component as lightweight as possible.
• Use the invalidate() and invalidateStyle() methods to invoke the draw() method
instead of calling the
draw() method explicitly.
Using the ModalText example
The following code example implements the class definition for the ModalText component. The
ModalText component is a text input whose default is the noneditable mode, but you can switch
to editable mode by clicking its button.
Save the following code to the file ModalText.as, and then compile it into a SWC file using the
compc utility.
// ModalText sends a "change" event when the text of the child TextInput
control changes, a "textChanged" event when you set the text property of
ModalText, and a "placementChanged" event when you change the labelPlacement
property of ModalText.
/*** a) Extend UIComponent. ***/
class ModalText extends UIComponent {n
/*** b) Implement init(). ***/
function init():Void {
super.init();
invalidate();
}
/*** c) Implement createChildren(). ***/
// Declare two children member variables.
var text_mc:TextInput;
var mode_mc:SimpleButton;
/*** d) Embed new skins used by the SimpleButton component. You can create a
SWF file that contains symbols with the names ModalUpSkin, ModalOverSkin,
and ModalDownSkin. ***/
[Embed(source="Modal2.swf", symbol="ModalUpSkin")]
var modeUpSkinName:String;
Using the ModalText example19
Page 20
[Embed(source="Modal2.swf", symbol="ModalOverSkin")]
var modeOverSkinName:String;
[Embed(source="Modal2.swf", symbol="ModalDownSkin")]
var modeDownSkinName:String;
// Note that we test for the existence of the children before creating them.
// This is optional, but we do this so a subclass can create a different
// child instead.
function createChildren():Void {
/*** e) Implement the measure() method. ***/
// The default width is the size of the text plus the button.
// The height is dictated by the button.
function measure():Void {
/*** f) Implement the layoutChildren() method. ***/
// Place the button depending on labelPlacement and fit the text in the
// remaining area.
function layoutChildren() {
text_mc.setSize(width - mode_mc.width, height);
if (labelPlacement == "left") {
mode_mc.move(width - mode_mc.width, 0);
text_mc.move(0, 0);
}
else {
mode_mc.move(0, 0);
text_mc.move(mode_mc.width, 0);
}
}
/*** g) Implement the draw() method. ***/
// Set flags when things change so we only do what we have to.
private var bTextChanged:Boolean = true;
// Set text if it changed, and draw a border.
function draw():Void {
clear();
if (bTextChanged) {
bTextChanged = false;
text_mc.text = text;
}
20Creating Advanced Components
Page 21
// Draw a simple border around everything.
lineStyle(1,0x000000,100);
drawRect(0, 0, width, height);
}
/*** h) Add methods, properties, and metadata. ***/
// The general pattern for properties is to specify a private
// holder variable.
private var __labelPlacement:String = "left";
// Create a getter/setter pair so you know when it changes.
[ChangeEvent("placementChanged")]
[Inspectable(defaultValue="left", enumeration="left, right")]
function set labelPlacement(p:String) {
// Store the new value.
__labelPlacement = p;
// Add invalidateSize(), invalidateLayout(), or invalidate(), depending on
// what changed. You may call more than one if you need to.
invalidateLayout();
dispatchEvent({type:"placementChanged"});
}
function get labelPlacement():String {
return __labelPlacement;
}
private var __text:String = "ModalText";
[ChangeEvent("textChanged")]
[Inspectable(defaultValue="ModalText")]
function set text(t:String) {
Note that to trigger the event, you have to modify the ModalText.text property directly; entering
text into the TextInput control does not trigger the event.
Troubleshooting
This section describes some common problems and their solutions when creating 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
directory as the MXML file and setting the namespace to "*" as the following example shows:
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 be sure that it is not private.
I don't get any errors, but nothing shows up.
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
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" />
I tried the verification test and I got nothing or "undefined" in the output.
This means that one of your dependent classes was either not loaded or was loaded too late. Print
various classes to the output to see whether they are being created. Any components created with
the
your component symbol.
The component is instantiated properly but does not show up (#1).
In some cases, helper classes are not ready by the time your component requires them. Flex adds
classes to the application in the order that they need to be initialized (base classes, and then child
classes). However, if you have a static method that gets called as part of the initialization of a class,
and that static method has class dependencies, Flex does not know to place that dependent class
before the other class, because it does not know when that method is going to be called.
xmlns property is pointing to the right place. Try moving the SWC file to the same
.text property to the ID for the
createClassObject() method as subcomponents of your component must be placed in
22Creating Advanced Components
Page 23
One possible remedy is to add a static variable dependency to the class definition. Flex knows that
all static variable dependencies must be ready before the class is initialized, so it orders the class
loading correctly.
The following example adds a static variable to tell the linker that class A must be initialized
before class B:
class mx.example.A {
static function foo():Number {
return 5;
}
}
class mx.example.B {
static function bar():Number {
return mx.example.A.foo();
}
static var z = B.bar();
// Dependency
static var ADependency:mx.example.A = mx.example.A;
}
The component is instantiated properly but does not show up (#2)
Verify that the
nonzero. If they are zero, ensure that you implemented the
_measuredPreferredWidth and _measuredPreferredHeight properties are
measure() method correctly.
.
Sometimes you have to ensure that subobjects are created in order to get the correct
measurements.
You can also check the values of the
code might have set those values to zero. If so, set a breakpoint in the setters for the
height, preferredWidth, and preferredHeight properties to see what is setting them.
You can also verify that the
_visible property is an internal property used by Flash Player. If visible=true and
_visible=false, ensure that your component called the invalidate() method in its
measure() or layoutChildren() methods.
visible property and the _visible property are set to true. The
The system does not call the
must call the
invalidate() method at least once, because their layout changes as they are given
preferredWidth and preferredHeight properties. Other
width,
invalidate() method unless you explicitly do so. All components
their correct size during the layout process.
The component is instantiated properly but does not show up (#3).
It is possible that there is another class or SWC file that overrides your custom class or the
symbols used in your component. Check the ActionScript classes and SWC files in the
flex_app_root/WEB-INF/flex/user_classes directory to ensure that there are no naming conflicts.
Troubleshooting23
Page 24
24Creating Advanced Components
Loading...
+ hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.