Writing Flex 2 Components

I’ve gone back and forth over this, trying to decide how complex to make this blog entry. The truth is, writing components in Flex 2 is pretty easy. What I was deciding between is whether or not to start with a component that does not use skins and then build up to adding skins.

I decided that skins are pretty easy (for us non-artists) so we’ll make a component, “from scratch” skins and all.

You can see a running example by clicking here
. Some of the gauges are connected, meaning that changing values in one changes others. The ones labeled “interactive” respond to the mouse. Yours to explore.

First, a few words about components. The Flex class, UIComponent, is the base for all components. This example component will extend UIComponent directly – hence my use of the term “from scratch”. Using UIComponent makes sure that the component fits into the Flex framework and plays well with the other components.

Being part of the Flex framework insures that the component is created properly and receives events at the right time. For example, when the component is created its constructor is called, but that’s not the time to make any children (the skins – needle, frame, and cover). When it is time for the children to be created, the Flex framework invokes the component’s createChildren() method. But that’s not when the component is visualized (or rendered). For that, the Flex framework invokes the component’s updateDisplayList() method.

I’m going to use the overly simple Gauge component as the example. It is simple because there is the logic to make the gauge work plus three skins. In general, that’s how components are: there is a class for the component and then skins to visualize the component. You can have many classes which make up the component, and indeed some of the Flex components do that. For the sake of brevity, I’ve limited this to a single class file.

programmatic.jpg red_dial.jpg graphic.jpg

You can think of a component like this: a core class to give the component its function (positioning the needle of the gauge and responding to events), a skin class to give the component its look, and styles to influence the skin.

The Gauge component has a class called gauge.Gauge (in the gauge package) and default skin class, gauge.skins.programmatic.GaugeSkin. There are also alternative skins in this example, too: gauge.skins.alternatives.SquareFrameSkin as well as graphic skins as PNG files.

I’m not going to get into a lot of the code; you can download that and read the comments. I am going to try to point out the important parts here.

Download file You will need either the Flex 2 SDK or Flex Builder 2 to use these files. You do not need Flex Data Services.

The Gauge

The Gauge is very simple: there is the face or frame, a needle, and a cover for the needle. These are the skins. The Gauge has properties, too: minimum, maximum, and value influence the position of the needle. The Gauge also dispatches a “gaugeClick” event when the mouse is clicked on the frame somewhere.

Since the Gauge is going to follow the Flex framework, some functions need to be written:

createChildren() is where the skins are created since they are actually children of the component.

measure() is called when the Flex framework wants to know the component’s dimensions.

updateDisplayList() is called when it is time to visualize the component.

In addition to functions, specifications for the styles and events the Gauge requires are also given.

Styles and Events

Before the definition of a class, you can specify that styles the class can use. This is done with the [Style] metadata. These specifications tell the compiler that it is OK for a certain name=value pair to used with the class.

createChildren

The Gauge is given the opportunity to create any child objects it needs. For example, you could add a Text component to display the current value. Or if you are writing a slider, you would want to create the thumb. The same is true for the Gauge which has its frame, needle, and needle cover. Creating the skins is pretty straightforward. Here is how the frame is created:

When you specify the skin for a component, you specify the Class of the skin, not a specific instance. This is true for graphic skins as well as programmatic skins. The gauge has some variables which hold the names of the classes and these names are intialized by the styles of the same name.

For example, to create the frame skin:

var skin:Class = Class(getStyle("frameSkin"));
var newSkin:IFlexDisplayObject = new skin();

newSkin.name = "frameSkin";
newSkin.styleName = this;

addChild(newSkin);

First the class of the skin is obtained using getStyle(). Then an instance of the skin is created using the new operator. The newSkin is given a name (which, for programmatic skins, tells it what to do), and its style is set to be that of the Gauge component itself. This is an important point. The skins need to get style information and it is easier for the Flex coder to put the style onto the component itself:

<Gauge backgroundColor="blue" ... />

The Gauge doesn’t care about its background color, but the frame skin does. By setting the styleName of the skin to be the component, invoking getStyle() from within the skin’s code will fetch the style from the Gauge instance.

Finally, the skin is added as a child of the Gauge.

updateDisplayList

The updateDisplayList function is one you get very familiar with. It is where “it all happens” so to speak. Many of the other functions in a component go toward setting up properties or making things that get used in updateDisplayList().

For the Gauge, updateDisplayList() is basically:

  1. Get the skins drawn.
  2. Rotating the needle.

Getting the skins drawn is really: sizing them (the frame for example, needs to be made the size of the Gauge to cover the area occupied by the control) and positioning them (the needle should be placed in the center of the control, the cover should go over the needle).

The Gauge’s needle needs to be spun so that it points to a value between the minimum and maximum values. That’s also a job done in updateDisplayList().

Properties

The remainder of the Gauge class is devoted to the properties, such as minimum, maximum, and value. You might think that when you set a value you go ahead and make the corresponding visual change. Not so.

The properties are initially set well before the visual aspect of the component is created. For example, if you have the value of the Gauge set to 30 but there is no needle skin created to spin to 30, then you obviously cannot change the visuals.

Normally properties simply set an internal variable and then set a flag. They also call an invalidate procedure. For instance, when the value of the Gauge is changed, you know the display list has to be updated, so invalidateDisplayList() is called. This sets a flag to the Flex framework to call the updateDisplayList() method at the proper time. In other words, when a property that affects the display is changed, it flags the change by calling invalidateDisplayList(). If a property affects the component size, invalidateSize() should be called. The Flex framework then only needs to call the update functions once.

Properties, by convention, are set and get methods that store into variables beginning with an underscore. For example, the set function for maximum sets the variable, _maximum. These are called “backing variables”.

Skins

You saw that the skins are created in the createChildren() method of the Gauge. But what exactly are “skins” anyway? Skins are object that fit into the Flex framework in manner similar to that of components. A skin is added to a component as one of its children. Skins normally do not have children of their own for several reasons.

  • Skins are intended to be “lightweight” because they are called upon frequently.
  • Skins are normally extending the mx.skins.ProgrammaticSkin or mx.skins.Border classes. These classes do not inherit from UIComponent and thus do not support children.

You are not restricted to using ProgrammaticSkin or Border as the base classes for your skins. You can use UIComponent if you like. Just remember that the more complex the base class the more work has to be done to render the skin.

Skin Types

There are two types of skins: Programmatic and Graphic. This demonstration of the Gauge shows how to use both.

Programmatic skins are completely code-based. You use ActionScript to make the graphics. The drawing API available in the Flash Player makes it easy to draw lines and shapes (circles, rectangles, rounded rectangles, etc.) and fill them with either a solid color or gradients of color. Your artistic ability is the only limiting factor.

If you look at the gauge.skins.programmatic.GaugeSkin class you’ll spot the following:

  • public class GaugeSkin extends Border GaugeSkin extends Border which has the potential for a background image.
  • switch( name ) in the updateDisplayList() method. Many programmatic skin classes actually draw many skins. For instance, a Button has a number of skins: when it is up, when the mouse is over it, when the mouse is press down over it, etc. You could use a different class for each skin, but since the skins are so similar, a single class is used to draw them all. In the GaugeSkin, the needle, frame, and cover are all simple in appearance, but since there is nothing else different between them, it makes since to put the ‘skins’ into a single class.

You should also note that the GaugeSkin class is pretty simple. The updateDisplayList() method is where all the work is done and that is mostly getting the styles set up correctly.

For example, if the GaugeSkin is drawing the frameSkin (name == “frameSkin”), then the backgroundColor, backgroundAlpha, borderColor, borderAlpha, and borderThickness styles have to retrieved from the component. Those styles that have not been set are given default values.

Drawing the Skin

Drawing the skin uses the Graphics object. The frameSkin is drawn with the following statements:

g.clear();
g.lineStyle( borderSize, borderColor, borderAlpha );
g.beginFill( bgColor, bgAlpha );
g.drawEllipse(x,y,w,h);
g.endFill();

First the graphic surface is cleared; failure to do that will make your skin look like someone scribbled all over it. The line style and fill colors are set next. Notice they are set from the styles. An ellipse is drawn – it will have a border of the line style and be filled with the given color. The fill is ended because you can have many drawing commands all being filled.

Graphic Skins

A graphic skin is an image, either a PNG (my favorite), JPG, or GIF. Making a graphic skin is pretty easy:

  1. Start your favorite graphic editor. Fireworks 8 for instance.
  2. Decide how big the component should be. Say 100×100 pixels.
  3. Draw something in that space and save the image. It is best to use either PNG or GIF because you can have transparent areas.
  4. Specify the graphic as the skin. You can do this in several ways:
    • Right in the tag: <mx:GaugeSkin faceSkin=”@Embed(‘myface.png’)” … />
    • As part of a style: SampleStyle { faceSkin: Embed(“myface.png”) }

Notice how much code in the Gauge class was changed to make use of graphic skins: none! And that’s the way it should be. A user of your components should be able to switch between programmatic and graphical skins in a style sheet.

I believe using styles is far easier than coding things in-line. Styles are quick to make, find, and change. Quick enough for development, too, so there’s really no excuse not to use them.

Extending the Gauge

That’s really all there is to making a component: setting styles and properties, calculating values, drawing skins. This particular component, the Gauge, is mildly interesting. But suppose you wanted to have 2 needles? Do you need to write a new component?

double_needle.jpg

The answer is no IF you’ve written your original component with extensibility in mind.

Take a look at the DoubleGauge class:

  • public class DoubleGauge extends Gauge The class extends Gauge, getting the benefit of all of its styles and functions.
  • protected var secondNeedleSkin The object which holds the skin for the second needle. This class is designed to allow the second needle to have its own skin, not reuse the needleSkin of the Gauge class.
  • var angle:Number = calculateAngleFromValue(_secondValue); in updateDisplayList(). The calculateAngleFromValue function was written to allow an inherited class access to the same rotation calculation. If this function were not present – meaning the calculation were done in the Gauge updateDisplayListMethod() – you would have to write it all over again.

That’s really all there is to making a Gauge with two needles. You can go ahead and make a Gauge with as many needles as you need.

Summary

I hope you find writing components in Flex 2 easy. Obviously this sample component was not very complex, but it did touch upon all the things which are necessary in a component:

  • How the component fits into the Flex framework by providing the right functions.
  • How to specify styles and how to get the skins to make use of the styles
  • How to specify events, dispatch them, and handle them.
  • How to write a skin class – all you need to do is make it pretty.
  • How to use a graphic skin – notice that there were no code changes to use it.
  • How to extend a skin and make use of its protected functions – good code reuse.

Good luck with your components. I can’t wait to see what you all come up with.