|
Before
you start developing custom components, you should be familiar with basic
ActionScript coding practices.
Using the package statementYou 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. To define the package structure, you include
the package statement
in your class definition, as the following example shows:
package myComponents
{
// Class definition goes here.
}
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, 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, specify
a namespace definition for the component that corresponds to its
directory location and package name, as the following example shows:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:MyComp="myFormatters.*">
<!-- Declare a formatter and specify formatting properties. -->
<MyComp:SimpleFormatter id="upperFormat" formatString="upper"/>
...
</s:Application>
If a formatter class is in a subdirectory of myFormatters, such
as myFormatters/dataFormatters, the package statement is as follows:
package myFormatters.dataFormatters
{
// Formatter class definition goes here.
}
You then specify the namespace definition for the component,
as the following example shows:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:MyComp="myFormatters.dataFormatters.*">
<!-- Declare a formatter and specify formatting properties. -->
<MyComp:SimpleFormatter id="upperFormat" formatString="upper"/>
...
</s:Application>
Using the import statementYou use the import statement to import
any classes that your class requires. Importing adds a reference
to the class so that you can access classes defined by the import.
Classes that you import must be located in the ActionScript source path
for your application.
You import the
classes referenced by your custom component as part of its implementation,
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.*;
// Class definition goes here.
// You can now create an instance of a Container using this syntax:
private var myContainer:Container = new Container();
}
There is a distinct difference between including and importing
in ActionScript. Including is copying lines of code from
one ActionScript file into another. Files that you include must
be located relative to the file performing the include, or use an
absolute path. Importing is adding a reference to a class
file or package so that you can access objects and properties defined
by external classes.
For more information on including and importing, see Using ActionScript.
Using the class statementYou 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.*;
// Class definition goes here.
public class MyButton extends Button {
// Define properties, constructor, and methods.
}
}
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.
Note: The class definition is one of the few ActionScript
constructs that you cannot use in an <fx:Script> block
in an MXML file.
Defining the constructorAn ActionScript
class must define a public constructor method, which initializes an
instance of the class. The constructor has the following characteristics:
No return type.
Should be declared public.
Might have optional arguments.
Cannot have any required arguments if you use it as an MXML
tag.
Calls the super() method to invoke the superclass’
constructor.
You call the super() method within your
constructor to invoke the superclass’ constructor to initialize
the inherited items from the superclass. The super() method
should be the first statement in your constructor; otherwise, the inherited
parts of the superclass might not be properly constructed. In some cases,
you might want to initialize your class first, and then call super().
Note: 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’ 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.*;
// Class definition goes here.
public class MyButton extends Button {
// Public constructor.
public function MyButton()
{
// Call the constructor in the superclass.
super();
}
// Define properties and methods.
}
}
Defining properties as variablesProperties
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 {
// Define private vars.
private var currentFontSize:Number;
// Define public vars.
public var maxFontSize:Number = 15;
public var minFontSize:Number = 5;
}
Users of the class can access the public variables but not the
private variables, as the following example shows:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:MyComp="myControls.*">
<MyComp:MyButton label="Submit" maxFontSize="30"/>
</s:Application>
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.
Note: 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.
Defining properties as getters and settersYou
can define properties for your components by using setter and getter methods.
The advantage of getters and setters is that they isolate the variable from
direct public access so that you can perform the following actions:
Inspect and validate any data written to the property
on a write
Trigger
events that are associated with the property when the property changes
Calculate a return value on a read
Allow a child class to override
To define getter and setter methods, precede the method name
with the keyword get or set,
followed by a space and the property name. The following example
shows the declaration of a public property named initialCount, and
the getter and setter methods that get and set the value of this
property:
// Define internal private variable.
private var _initialCount:uint = 42;
// Define public getter.
public function get initialCount():uint {
return _initialCount;
}
// Define public setter.
public function set initialCount(value:uint):void {
_initialCount = value;
}
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:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:MyComp="myControls.*" >
<MyComp:MyButton label="Submit" initialCount="24"/>
</s:Application>
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 {}
Defining methodsMethods
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:
private function internalMethod():void {
// Method definition
}
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
}
Flex creates an Array called rest for the optional
arguments. Therefore, you can determine the number of arguments
passed to the method by using rest.length, and
access the arguments by using rest[i].
Using the super keyword in a method overrideYou use the super keyword
in a method override to invoke the corresponding method of the superclass.
The super keyword has the following syntax:
super.methodName([arg1, ..., argN])
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.
Note: Although Flex automatically calls the super() method
in a constructor to execute the superclass’ constructor, you must
call super.methodName() in
a method override. Otherwise, the superclass’ 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.
About the scopeScoping 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 <s: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 Using ActionScript.
|
|
|