Accessibility

Table of Contents

Flex Component Basics – Part 1: Coding an Analog Clock

Writing the Component

Data Members and Properties

Data members are variables that you do not expose externally, you mark them private. These variables are critical in controlling the component. Properties, on the other hand, are designed to be changed and give you a way to customize the component.

The clock needs to know the current time, so you use the __currentTime member. The variable is prefixed with double underscores, a convention that denotes that it is a variable. It has get() and set() methods associated with it. The get() and set() methods are called currentTime, so you need to distinguish the variable that holds the value from the functions to get and set the value.

private var __currentTime:Date;
[ChangeEvent("changeTime")]
public function set time(d:Date) : Void
{
__currentTime = d;
invalidate();
dispatchEvent({type:"changeTime"});
}
public function get time() : Date
{
return __currentTime;
}

The ChangeEvent metadata indicates to the Flex compiler that it can use the time get() and set() methods with Flex data binding. Once the time has been specified in the __currentTime variable, the code calls the dispatchEvent function to signal the change. Notice that the dispatchEvent function uses an event type that matches the type named in the ChangeEvent metadata.

Since __current time was set, a flag to an invalidate call is made, which forces the clock to update itself. The draw() method takes care of positioning the hands according to the value of __currentTime.

Flags

One trick you learn when writing components is to avoid doing any real visualization (drawing, changing fonts, colors, and such) until the draw() method is called. The way to do that is to set flags that you can test in the draw() method. The elements with flags set to true process in the draw() method, and then their flags are reset to false. You can see examples of the flags in the code files and in the section on the draw() method.

The init() Method

The init() method is where you first set __currentTime. Depending on how you assign other properties, this may be the only time to set it, so initialize it here.

public function init() : Void
{
	__currentTime = new Date();
	super.init();
}

The createChildren() Method

The createChildren() method is where you create the objects that make up the component elements:

public function createChildren() : Void
{
border_mc = createClassChildAtDepthWithStyles(
	_global.styles.rectBorderClass,
	DepthManager.kBottom, { styleName : this });
	// create the empty movie clips in the order
	// you want them stacked
	createEmptyMovieClip("face_mc",getNextHighestDepth());
	createEmptyMovieClip("hourHand_mc",getNextHighestDepth());
	createEmptyMovieClip("minuteHand_mc",getNextHighestDepth());
	createEmptyMovieClip("secondHand_mc",getNextHighestDepth());
	
	setInterval(this,"tickTock",1000);
	super.createChildren();
}

The createChildren() method creates five elements: a border, the face, and the three hands. You create the border using the RectBorder class, which draws a rectangular border based on the component’s borderStyle setting. Using this class removes all of the work of making a border from your code, plus your borders look like Flex borders.

Create the face and hands with createEmptyMovieClip. Notice that you use getNextHighestDepth to select the depth (z-order) of each element. You can also specify the depth values if you want to reduce the number of function calls your component makes.

The measure() Method

Flex calls the measure() method during its measurement phase, when it asks the size of each component. This helps Flex determine where to put the components on the screen. The measure() method sets two special variables to be the component’s size. Flex only calls the measure() method when the Flex layout phase cannot otherwise determine the component’s size. Through experimentation, I know that 100 pixels by 100 pixels is a nice default size.

public function measure() : Void
{
	_measuredPreferredWidth = 100;
	_measuredPreferredHeight= 100;
}

The layoutChildren() Method

Flex calls the layoutChildren() method to size and position the component’s elements. I made a conscious decision to have each element's (0,0) be the center of the element. Normally a component with a coordinate of (0,0) is in the upper-left corner. I chose the center of the element to make it easier to position and to rotate the hands.

public function layoutChildren()
{
	// position and size the border
	border_mc.move(0, 0);
	border_mc.setSize(layoutWidth, layoutHeight);
	// simply make sure the (0,0) point of all children is centered
	// within the component.
	var cx:Number = layoutWidth/2;
	var cy:Number = layoutHeight/2;

	face_mc._x = cx;
	face_mc._y = cy;
	hourHand_mc._x = cx;
	hourHand_mc._y = cy;
	minuteHand_mc._x = cx;
	minuteHand_mc._y = cy;
	secondHand_mc._x = cx;
	secondHand_mc._y = cy;

	bDrawFace = true;
	bDrawHands = true;

	invalidate();
}

Notice how the border is in the upper left corner and has a (0,0) coordinate—that is the origin of the component. The border expands or shrinks to fit the component using the layoutWidth and layoutHeight variables, which are members of the base UIComponent class. Always keep in mind that layoutWidth and layoutHeight are the actual dimensions of the component, regardless of the scale.

Once Flex determines the center of the component, Flex positions each of the elements so that their origins are in the center.

Next, the code sets two flags: bDrawFace and bDrawHands. These flags are declared as members of the AnalogClock class and are used to indicate which parts to update in the draw() method.

Finally, the code calls the invalidate() method to invoke the draw() method at the proper time. (You never call the draw() method directly—the Flex framework knows when to do it, you just indicate that you want it done using an invalidate function.)

The draw() Method

The draw() method is invoked when you first create the component. You may be wondering why it is necessary to call the invalidate() method within the layoutChildren method. This is because at some later time, another component may re-invoke the layoutChildren() method without invoking the draw() method. This can happen, for example, if the user resizes the Flex application window, which resizes the clock. The Flex component framework calls the layoutChildren() method so that the component has a chance to reshape itself. This often involves redrawing the children components, but it depends on the component. To remedy this, include a call to the invalidate() method to make sure the parts redraw to a new shape.

public function draw() : Void
{
	if( bDrawBorder ) {
		border_mc.draw();
		bDrawBorder = false;
	}
	if( bDrawFace ) {
		drawFace();
		bDrawFace = false;
	}
	if( bDrawHands ) {
		drawHourHand();
		drawMinuteHand();
		drawSecondHand();
		bDrawHands = false;
	}
	if( bRunClock ) {
		setInterval(this,”tickTock”,1000);
		bRunClock = false;
	}
	positionHands();
}

Notice that the draw() method checks each flag and then invokes a function to draw that component. The draw() method then resets the flags to false to avoid redrawing anything.

One of the things the draw() method checks is the bRunClock flag. You need a way to have the component wake up every second (every 1000 milliseconds) and position the hands. The bRunClock flag has an interval timer (function tickTock) that you can call every second.

Testing the Component

At this point, test the component. Create a new Flex application in the same directory and add the following tags:

<mx:Panel title=”Basic Clock”>
<AnalogClock_Basic xmlns=”*” />
<:Panel>

When you run the Flex application your application will look like Figure 1.