Flex Custom Components
Flex Custom Components Introduction
The Bar Chart Case
Flex Component Basics
Flex Component With Data Provider
Flex Component With Server Side Data Provider
 


Flex Component Basics

Connect with me:  
  Jenkov.com - News

This text covers the basics of how to implement the skeleton of a custom Flex component. There is a small code sample at the end of this text too.

The basic event and render "loop" in Flex consists of two steps:

  1. A user event occurs.
  2. The Flex application is re-rendered (if necessary).

A user event can be a button clicked, text typed into an input field, a browser re-size etc. A re-rendering is a re-drawing of the Flex application.

It is actually wrong to call it a "loop". The events and event processing take place independent of the rendering process. The Flex application rendering takes place no matter if an event occurs or not. A Flex appliation is re-rendered X times per second. That is, if any components in the application signal that they need to be re-rendered. If multiple events occur between two renderings, then the effects of all these events are batched up and rendered during the same rendering sequence. If no events occur between two rendering sequences, the rendering sequence is still executed, though the actual rendering may be optimized away.

The Flex (Flash) runtime doesn't know if it is necessary to re-render the application after a user event. Therefore you have to tell it so, by calling internal invalidation methods. These methods are inherited by your component from the mx.core.UIComponent superclass. During rendering the Flex (Flash) runtime will notice these invalidation method calls, and call some other corresponding methods, also inherited from the mx.core.UIComponent class. This text will describe in more detail how this works.


Implementing a Flex Component by Subclassing UIComponent

To create your own custom GUI components in Flex you extend the ActionScript class mx.core.UIComponent. This class has several protected methods that your component inherits. In this text we will look at the following methods:

  • invalidateSize()
  • invalidateProperties()
  • invalidateDisplayList()

  • commitProperties()
  • measure()
  • layoutChrome()
  • updateDisplayList()

The first 3 invalidation methods should not be implemented (overriden) by your component. Instead these methods should be called by your component internally, in response to user events. In other words, these methods are called during event processing.

In response to these invalidation method calls the Flex (Flash) runtime will call one or more of the 4 last methods. These methods should be implemented by you. Flex calls these methods during rendering. Therefore, multiple invalidation method calls may get collapsed into a single call to any of these 4 last methods.

All seven methods are covered in a bit more detail in the following sections.


User Events and Rendering of Flex Components

When the user of a Flex application takes action, like resizing a window, pressing a button, typing in some text etc. this may result in changes in your custom component. For instance:

User Event --> Change in size       of component
           --> Change in looks      of compnonent
           --> Change in properties of component
           --> Change in children   of component
           --> etc.

The event may change either the size, the properties, or something else like a child of your custom component. Depending on what changes in your component, your component should internally call one of the listed inherited invalidation methods invalidateSize(), invalidateProperties(), or invalidateDisplayList(). Here is the call sequence of that:

User Event --> Change in size       of component
               --> invalidateSize()

           --> Change in properties of component
               --> invalidateProperties()

           --> Change of anything that needs the component
               to be re-rendered
               --> invalidateDisplayList()

Calling one of these invalidation methods triggers calls during the next rendering of your Flex application, to the corresponding inherited methods mentioned in the beginning of this text. Here is how Flex determines what methods to call:

if(invalidateProperties() called) --> commitProperties();

if(invalidateSize() called)       --> measure();

if(invalidateDisplayList())       --> layoutChrome() +
                                      updateDisplayList();

Note: The method invalidateDisplayList() method could get called by the commitProperties() method too, as a result of calculations done there.

Now that you have an overview of the basic event and rendering loop, let's take a look at the four methods you will need to implement in order to implement your custom Flex component. In fact, you don't need to implement all four of them, as you will probably notice once you start implementing your own Flex components.


commitProperties()

The commitProperties() method is the first method called by the Flash runtime when it is ready to start drawing a Flex component.

If the given component has had any changes to any of its properties, like width, height, depth, color, or any other property, commitProperties() is where you do any necessary calculations based on these changed properties. If we did not have this commitProperties() method, you would have to make these calculcalations whenever any of the properties changed, to make sure they were indeed carried out. If more than one property is changed in between redrawing the component, that would lead to unnecessary repetition of these calculations.


layoutChrome()

The layoutChrome() method is used to define borders around your component, if you need this. Borders will be discussed in a later text.


measure()

In this method you calculate the size of the Flex component. This method is used to calculate:

  1. The minimum size of your component.
  2. The default size of your component.

If you set the width and height properties of a component then the measure() method does not get called. There is no need to, when the width is explicitly set. Only if the width is not explicitly set, is it necessary to calculate the size(s) of your component.

Sizing of Flex components will be discussed in more detail in a later text too.


updateDisplayList()

In this method you draw the component on the screen. To have this method called by the Flex runtime, you must have called the inherited method invalidateDisplayList() earlier. Only then is this method called.

Don't put drawing code anywhere else than inside this method, unless you are doing something special with animations, games etc.

The updateDisplayList() method also sets the actual sizes of any child components. This too will be covered in more detail in a later text.


A Flex Component Skeleton

Here is the code for a very simple Flex component. And below the code is how the component looks embedded in a web page. Here is the code:

package chart{

    import mx.core.UIComponent;
    import flash.geom.Matrix;
    import flash.display.GradientType;
    import flash.display.SpreadMethod;
    import flash.display.InterpolationMethod;

    public class Chart1 extends UIComponent {

        internal var _barWidth : Number = 20;

        internal var _value1 : Number = 50;

        public function get value1() : Number {
            return _value1;
        }

        public function set value1(value: Number) : void {
            this._value1 = value;
            invalidateProperties();
            invalidateSize();
            invalidateDisplayList();
        }

        override protected function measure() : void {
            measuredHeight    = _value1;
            measuredMinHeight = _value1;
            measuredWidth     = _barWidth;
            measuredMinWidth  = _barWidth;

        }

        override protected function updateDisplayList(
            unscaledWidth:Number, unscaledHeight:Number):void {

            super.updateDisplayList(unscaledWidth, unscaledHeight);

            graphics.clear();
            graphics.lineStyle(1, 0x000000, 1.0);

            graphics.beginFill(0x00ff00, 1.0);

            graphics.drawRect(0, 0, 20, _value1);

        }
    }
}

And here the component is used in a Flex application in MXML:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:jenkov="chart.*" backgroundColor="#ffffff">

    <mx:Script>

     <![CDATA[
        public function updateChartValue() : void {
            myChart.value1 = new Number(textField.text);
        }
    ]]>

    </mx:Script>


    <mx:Panel width="100%" height="100%"
        title="A Basic Chart Component in a Flex Panel">
        <mx:VBox height="100%">
            <jenkov:Chart1 id="myChart" x="0" y="0" />
            <mx:TextInput id="textField" text="50"/>
            <mx:Button label="Update Chart" click="updateChartValue()"/>
        </mx:VBox>
    </mx:Panel>

</mx:Application>

Below is how the Flex application with the component looks. Try changing the value in the text field, and click the "Update Chart" button. The chart will change its height. See if you can trace yourself through the event processing and the rendering methods of the component in the code above.


NextNext : Component With XML Data Provider

Connect with me:
     
Newsletter - Get all my free tips!