FLARM and Dependency Injection

I’ve been taking a look at the latest FLAR Manager code with a view to implementing the histogram bias generation for adaptive thresholding I’ve written about previously. Now Eric’s separated out the threshold algorithm, that’s been made easier to achieve without worrying about future changes to the code base.

Eric’s implemented a nice dependency injection method where you declare the class name of the algorithm you plan to use in the config XML and the manager uses flash.utils.getDefinitionByName() to create it. As long as you implement the interface class, everything should work.

The one downside is that you need to define an object of the class you intend to use somewhere in the manager or the class won’t get included in the swf and you’ll get a runtime error when you try and create it.

It would be nice if you could remove any knowledge of the threshold class implementations from the manager source and just use configuration.

I knew Spring would need to do something like this which lead me to this. I decided to try implementing the resource bundle solution.

Here’s what I did:

  • create a locale/en_US folder in my project
  • create a classreferences.properties file in that folder
  • put the following lines in that .properties file:

#locale/en_US/classreferences.properties
Class1 = ClassReference("com.transmote.flar.utils.threshold.DrunkWalkThresholdAdapter") Class2 = ClassReference("com.transmote.flar.utils.threshold.HistogramThresholdAdapter") Class3 = ClassReference("com.transmote.flar.utils.threshold.DrunkWalkHistoThresholdAdapter") Class4 = ClassReference("com.transmote.flar.utils.threshold.IntegralImageThresholdAdapter")
(basically all the threshold adapters)

  • add -source-path locale/{locale} to my compiler additional options (locale defaults to en_US)
  • add the following to FLARManager.as at the Class level:
  • [ResourceBundle("classreferences")]
    private var _classReferences:ResourceBundle;

and now I can swap in whatever adapter I want in the xml config and it gets picked up. I like this solution because it keeps the FLARManager ignorant of the various adapters that are available – as long as you update the resource file, it’ll work – no need to include the adapter classes or create dummy variables for each of them.

The downside is, you’re creating a bigger swf file as you’re including classes you won’t use and you have to do more initial setup.

I’ll post the histogram based class I came up with next.

Advertisements

Learning Flex – Lesson 16, part II Skinning Components

Each component has several “skins” to describe the look of that component in different situations. As an example, a Button has upSkin for it’s default appearance, overSkin for how it appears with the mouse pointer over it, downSkin for when it’s pressed and disabledSkin for when it’s disabled (it also has a corresponding set of 4 for when it’s selected). The available skins for a component are enumerated in the Adobe documentation.

There are three types of skins:

  • Graphical Skins – these are image files that define the appearance of the skin (jpeg, gif or png)
  • Programmable Skins – ActionScript or MXML classes that define a skin using the Flash Drawing API. A single class can define multiple skins.
  • Stateful Skins – programmatic skins that use view states where each state corresponds to a skin of the component.

Graphical Skins

These can be applied inline:

<mx:Button upSkin="@Embed('../assets/buttonUp.gif')"/>

within a Style tag:

<mx:Style>
Button{
overSkin: Embed ("../assets/buttonOver.gif");
}
</mx:Style>

and within ActionScript:

[Embed("../assets/buttonDown.gif")]
public var buttonDwnSkin:Class;


myButton.setStyle("downSkin" , buttonDwnSkin);

Programmatic Skins

You can create programmatic skins either in MXML or ActionScript and define a class per skin or a single class for multiple skins. Using the Flash Player drawing API allows you more flexibility in your design.

The first step is to choose the base class you want to extend for you skin. The main choices are:

  • ProgrammaticSkin – this implements the IFlexDisplayObject, ILayoutClient & IStyleable interfaces. It’s the the most lightweight super class for a skin.
  • Border – this extends ProgrammaticSkin and adds support for the borderMetrics property. This would be used to implement a skin with a border that does not require a background image.
  • RectangularBorder – this extends Border and adds support for the backgroundImage style.

The majority of the work for the class is in overriding the updateDisplayList() method. If you choose one of the border classes, you will also need to override the getter method for the borderMetrics property to return your values.

The name property will provide the current skin name to be rendered. Use graphics.clear() to remove any prior elements, a fill method (beginFill(), beginGradientFill() or beginShaderFill() ) to specify the fill that subsequent graphics calls will use, one or more of the draw methods followed by endFill() to see the graphics displayed.

To use a programmatic skin, you need to provide the created class name. To apply it inline:

<mx:Button overSkin="{MyComponents.MyButtonSkin}"/>

within a Style tag:

<mx:Style>
Button{
upSkin:ClassReference("MyComponents.MyButtonSkin");
}
</mx:Style>

and within ActionScript:

myButton.setStyle("upSkin",MyComponents.MyButtonSkin);

Stateful Skins

Flex components such as Button, Slider etc can use stateful skins. They have a style property that is defined for several skin states (for Button it’s skin, for Slider, thumbSkin). By defining a custom skin class based on UIComponent, you can define view states corresponding to some or all of the possible skins and specify graphics for them. This gives you the ability to use transitions to animate the state changes.

You use a stateful skin in the same way as a programmatic skin –  by assigning the class name to the relevant style property (skin for Button etc).

You can make your own custom style properties by making a call to getStyle() within updateDisplayList() and supplying the name of your style.  You should wrap this call with isValidStyleValue() to check if the property exists before you try to use it and declare a default value in the class constructor.

Learning Flex – Lesson 16, Customizing the Look & Feel of a Flex Application

I’ve written a couple of posts previously looking at some aspects of this lesson but this a more detailed exploration.

There are two key ways to change the appearance of a Flex app – styles and skins.

Style properties allow you to change such elements as font size, background color and text alignment. Skins are graphical elements (either provided as files or created with ActionScript) that change the appearance of a component (eg button shape).

Applying Styles

Flex styles are based on the web standard CSS (Cascading Style Sheets). There are several levels a style may be applied at:

You may specify a single style on a particular component, use a CSS Class selector to set several styles together or use a type selector to specify that all components of a particular type should use the provided style values.

A style may be applied to a component directly in its MXML definition by adding the style name as a property and specifying it’s value such as

<mx:Label id="mLabel" text="My Label" fontWeight="bold"/>

to display a bold label. The setStyle() method can also be used to achieve the same effect – mLabel.setStyle("fontWeight","bold")

Note that when using setStyle() and specifying colors, the prefix 0x is used to indicate a hexadecimal value (and quotes are not required around them). When specified in a tag or CSS attribute, the prefix # may be used instead.

setStyle() is an expensive run time operation so it’s use should be limited.

The Flex language reference will tell you what styles are available for a particular component and will also specify CSS inheritance. If yes, this indicates that if the parent of this component has a value specified for the style, the child component will use the same value unless it has its own value specified. (For example, if you have a Label in a HBox, it will inherit the HBox color (text color) unless it has its own color value set.

Setting Styles with CSS

The <mx:Style> tag can be used to define local styles using CSS based syntax. Flex supports CSS class selectors which define a set of properties as a single class that can then be used by specifying the class name for a component’s styleName property.

<mx:Style>
.myStyle{
color:#FF00FF
selectionColor:#00FF00
}
</mx:Style>

<mx:ComboBox styleName=”myStyle”/>

You may also use CSS type selectors which define a set of styles to be applied to all instances of a component type.

<mx:Style>
ComboBox{
color:#FF00FF
selectionColor:#00FF00
}
</mx:Style>

<mx:ComboBox id="myBox1"/>
<mx:ComboBox id="myBox2"/>

Both myBox1 and myBox2 will have the same color and selectionColor.

Note that Flex does not support ID selectors.

Flex will support traditional CSS style formatting for the properties it supports (ie all lowercase with hyphen to separate words such as background-color) within a Style tag but for attributes that are specific to Flex and all attributes outside of Style tags, the camel case form of the name is required (eg backgroundColor). This is because the hyphen is not a valid character for XML attributes and MXML tags must be valid XML.

CSS properties that require multiple values are specified using a comma separated list of values. It’s important to note that those properties must have at least two values (even if they are the same) to avoid an error as a single value will not map correctly to an array.

You may also use mx:Style to specify an external CSS file to compile into the app using the source attribute. This should always be placed within the file containing the Application tag  – setting style imports in child documents can give rise to unexpected results.

Run Time CSS

The disadvantage of specifying an external file to load in this way is that it is compiled into the application and thus any changes to the CSS require the app to be re-compiled. By loading the CSS at run time, this situation can be avoided and different CSS files could be loaded depending on data provided so if for example, you had a collage sports app, you could brand your app with the team colors of where your users login from.

Flex can’t deal directly with a CSS file but the compiler can convert that to a SWF which it can use. To do this in FlashDevelop, right click the CSS file, select “always compile”, go to project properties and specify the output filename you want to use and compile (don’t forget to switch back to your regular app when you’re done).

Once you have your CSS SWF, just use

StyleManager.loadStyleDeclarations("myCSSFile.swf")

to load it. A second optional parameter is update a boolean (which defaults to true). If set, this forces an update of all the styles in the application. If you’re loading several CSS SWF files, you should set this to false for all but the last one to reduce the overhead of this operation.

you may also use

StyleManager.unloadStyleDeclarations("myCSSFile.swf")

to unload a CSS. This also has an optional update parameter with the same effect.

It’s possible to have several levels of style in play, the rule being that if a style is defined in multiple places, the last one loaded is the one used.

Learning Flex – Lesson 15, part II Deep Linking

Deep linking allows the URL to represent different states in a Flex app by using named anchors (the parameters that follow # in a URL that are traditionally used to navigate to different places within a HTML page). The portion of the URL after the ‘#’ is referred to  as a fragment. Each time the fragment is changed, the previous fragment is stored in the browser’s history allowing the user to make use of the back and forwards buttons. These URLs can also be bookmarked and used to get directly to the desired state.

In Flex 3, deep linking is implemented via the BrowserManager class. This provides support for reading and writing to the fragment as well as the browser’s title. It will also provide notification to your app when the fragment changes in the browser. The URLUtils class offers tools to help convert between an object of name value pairs and fragment strings.

It’s important to note that HistoryManager also uses the BrowserManager and will cause interference if it’s active so the two techniques should not be combined (set historyManagementEnabled="false" in the Application tag).

To implement deep linking, start by creating an init method to be called on creationComplete. This should create a property to reference the BrowserManager like so:

private var browserMgr:IBrowserManager = BrowserManager.getInstance();

Call the init() method on this property and provide two Strings as parameters; the first is the initial URL fragment (which is usually the empty string), the second is the desired browser title.

Next, add an eventListener() for the property, listening for the BrowserChangeEvent.BROWSER_URL_CHANGE event and specify an event handler method that will parse the URL.

You should define an update URL method that gets called when the navigation state changes. This method needs to create an Object and add the relevant state data using name,value pairs (object.name = value). The URLUtil.ObjectToString() method is then used to convert the Object to a String fragment that can be provided for the URL using the setFragment() method of your BrowserManager property.

The parse URL method (event handler) should use URLUtil.StringToObject() to translate the fragment attribute of the BrowserManager property into an Object like so:

var o:Object = URLUtil.StringToObject(browserMgr.fragment);

This method may get called before all the display objects are created so it’s a good idea to check if data is non null before proceeding. If it is null, use the callLater() method to call the method again in the next Flash cycle (as you won’t have the event this time round, you’ll want to default that parameter to null in the method specification). Otherwise, the Object data can be retrieved and used to update the navigation state.

Take care to ensure that relevant bounds checking etc is performed on the fragment values to prevent issues from the user hacking the URL data in the address bar of the browser.

Another point you may need to consider is potential race conditions between the parse method updating the navigation state (if this has asynchronous aspects) and further changes to the URL.

You can use the setTitle() method of your BrowserManager property to update the title displayed on the browser to reflect state changes.

There are also alternative 3rd party solutions available for deep linking – SWFAddress and URLKit

Learning Flex – Lesson 15, Implementing History Management

Using history management, a user can navigate through an application using the browsers back and forward operations as they would at a regular website.

Flex automatically supports this behavior for any navigation container. The property used to specify this is the boolean historyManagementEnabled. It’s true by default for Accordion and TabNavigator but false for ViewStack.

It works by saving the state of navigation as the user moves within the app (note only the container state is saved, not that of any components within it) and when the browsers back or forward buttons are selected, the HistoryManager loads the relevant state.

History management uses an invisible HTML frame into the browser window. The state of the container is encoded into the URL parameters for this frame. A javascript called history.js located in this frame decodes the parameters and sends the relevant information to the HistoryManager class in Flex.

By default, Flex Builder will create a HTML template for a swf with history management capabilities, Flash Develop will not. You can manually edit the created HTML file using the templates found under your SDK \templates\html-templates directory. If you want to change this default behavior, copy one of the templates from your SDK to your Flash Develop \projects\140 ActionScript 3 - Flex 3 Project\bin directory.

Note that history management will not work in IE when running a Flex app from a local file due to security constraints. It will work once deployed to a server and Firefox will show the correct behavior in both cases.

History management can be added to any custom component by following the steps below:

  • specify the custom component implements IHistoryManagerClient
  • implement loadState(), saveState() and toString() to satisfy the interface
  • call the static methods of the HistoryManager class to register() the custom component and save() when the navigation state changes.

To specify a class implements an interface in ActionScript, you would add implements interface (where interface is the interface class name) to the end of your custom class name definition eg public class MyClass implements IHistoryManagerClient. In MXML, you add an implements attribute to the end of your container tag eg <mx:HorizontalList ... implements="IHistoryManagerClient">

On creation complete, you should use HistoryManager.register(this) to register the component. At this point you must also call HistoryManager.save() to initialize the state.

If the component is a subclass of UIComponent, it will already have a toString() method. The saveState() method should return an Object that contains name,value pairs that represent the navigation state. As the URL size is limited, this data should be kept to a minimum. You would normally save something like the selected index for the container.

The loadState(state:Object) method is activated when the user clicks the forward or back buttons on the browser. The history manager passes in the Object created by the saveState() method for the container to use in deciding what navigation state to display. This object should be checked for null in case the user clicks the back button when there is no history to go back to.

HistoryManager.Save() should be called any time the component changes it’s navigation state so the history manager can keep track of what state the component is in.