|
Not only does Flex have built-in support for properties and events, it includes a higher-level abstraction language (MXML) for laying out and configuring components, which greatly simplifies the development process. You can even create new components directly in MXML, although that's more commonly done using ActionScript. This article shows you how to create components in Flex and how clean the resulting applications that use those components can be.
You'll see that ActionScript is quite similar to Java in many ways, but I hope you'll also see that ActionScript includes time-saving features that don't appear in Java.
Although you can write all your Flex code by hand and compile it using mxmlc (the free command-line compiler), it's much easier to use Adobe Flex Builder which is built on top of Eclipse and has command completion, context help, built-in debugging and more. Some of the examples in this article use Adobe AIR, Adobe beta software that allows you to create desktop applications that access files and other aspects of your local machine (rather than being limited to the web sandbox). You can download a beta of Flex Builder including AIR support from Adobe Labs. (You can also build these examples using the command-line compiler).
Requirements
To complete this tutorial you will need to install the following software:
Flex Builder 3 beta (with built-in support for Adobe AIR)
Download
Prerequisite knowledge
To benefit most from this article, you should have a working knowledge of MXML and ActionScript.
MXML components
The easiest way to create a component is using MXML. First, to create a new application: from the Flex Builder menu, choose File > New > Flex Project, and fill out the rest of the wizard queries. Next, within Flex builder again, select File > New > MXML Component. This produces a wizard that guides you through the process, including the choice of a base component to inherit from. I chose "Button" and called my new component "RedButton." The result is a file called RedButton.mxml (the name of the file determines the name of the component) containing the following:
package ProgrammedLearning {
import mx.containers.Accordion;
import mx.containers.VBox;
import mx.controls.TextArea;
import mx.controls.Alert;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
import flash.net.FileFilter;
import flash.events.Event;
public class ExercisePresenter extends Accordion {
public var dataDirectory:String;
public var chapter:String;
public var fileName:String;
private var file:File = File.documentsDirectory;
private var pathsResolved:Boolean = false;
// Called when properties are set:
protected override function commitProperties():void {
super.commitProperties();
// Prevent multiple calls:
if(!pathsResolved) {
pathsResolved = true;
resolvePaths([dataDirectory, chapter, fileName]);
}
}
private function resolvePaths(paths:Array):void {
for each(var path:String in paths) {
var successfullyResolved:File = file; // Store as far as we've gotten
file = file.resolve(path);
if(file.exists)
continue;
else { // Files installed elsewhere
var exFilter:FileFilter = new FileFilter("Exercise", "Exercise*.txt");
file = successfullyResolved;
file.browseForOpen("File Not Found; Select File to Open", [exFilter]);
file.addEventListener(Event.SELECT, parseFile);
}
return; // Wait for user to choose new path
}
parseFile();
}
private function parseFile(event:Event=null): void {
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
var str:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
var entries:Array = [];
// Each entry is delimited by a '.' at the start of a line:
for each(var s:String in str.split(new RegExp("\\n\\.", "s")))
if(s.length > 0)
entries.push(s);
for each(s in entries) {
// Split on first newline:
// (Could do this with a regular expression, too!)
var brk:uint = s.indexOf("\n");
var tag:String = s.substring(0, brk);
var contents:String = s.substr(brk);
// Strip leading newlines:
while(contents.charAt(0) == '\n')
contents = contents.substr(1);
switch(tag.charAt(0)) {
case 'e':
addStep("Exercise", contents);
break;
case 'h':
addStep("Hint " + tag.substr(1), contents);
break;
case 's':
addStep("Hint solution " + tag.substr(1), contents);
break
case 'f':
addStep("Completed solution", contents);
break;
default:
}
}
}
public function addStep(label:String, contents:String):void {
// Create a new "fold" in the Accordion:
var vbox:VBox = new VBox();
vbox.percentHeight = vbox.percentWidth = 100;
vbox.label = label;
var text:TextArea = new TextArea();
text.percentHeight = text.percentWidth = 100;
text.text = contents;
vbox.addChild(text);
addChild(vbox); // Add to self (Accordion object)
}
}
}
The dataDirectory, chapter, and fileName field