|
|
||||||||
| Ultrashock Tutorials > Flash MX 2004 > Developing a Simple Application | ||||||||
|
||||||||
|
|
Developing a Simple Application Using Forms and MVC |
|
||||||
PrefaceWhen UltraShock asked me to write an introductory tutorial on Forms and Screens in FlashMX 2004 Professional (hereafter F04Pro), I thought "Sounds great! Slap a few components on a couple of forms, add some behaviours, and it's done!". But the more I worked with forms, and the more I thought through the tutorial I wanted to write, the less I liked that idea. It seemed to me that despite all of the drag'n'drop code for dummies that forms supported, the whole concept wasn't really made for beginners. I mean, why would they only put Forms in F04 Pro if it was aimed at newbies? So, valiantly fighting against the various frustrations that cropped up (not least of which was the initial dearth of documentation), I set out to write a tutorial that showed this new feature as I saw it: A promising new model for building robust MVC applications that maybe isn't quite ready for prime time. (I'm sooo heroic!) This incarnation of the tutorial was a whole lot trickier to write than what I originally signed up for, but hopefully the work pays off by providing the right people with the right information. My fingers are crossed (which will make typing the rest of this tutorial insanely difficult). IntroductionThis tutorial is going to focus on using forms and screens to develop a Rich Internet Application in F04Pro using the MVC design pattern. It will guide you through developing a simple address book application - without a single line of code in the FLA (tell me that's not 1337). In order to keep this tutorial succinct, the end product is pretty light on features (it doesn't even save). To get the most out of this tutorial, you will need a basic understanding of Object Oriented Programming in ActionScript 2. Dave Yang has written an excellent tutorial on this topic for UltraShock if you need to get up to speed on this. I have also written a series of posts about it on my blog . You'll also want to read up on the MVC design pattern before proceeding, if you aren't already familiar with it. About FormsSo what the heck are forms, and why do you care? Forms and screens represent a new state-based metaphor for application development in FlashMX 2004 Pro. They don't really do anything that you couldn't have done using movieclips and timelines in MX, but they do make developing state-based applications simpler, and more self-evident. In form based development, each form lives in a hierarchy of forms, at the top of which is the root form. This hierarchy is navigated in code using dot syntax, such as "_root.application.form1". This should sound familiar, as it's very similar to how MovieClips work. Each form represents a single state of the application, and its visibility can be toggled on and off as required. The visual elements of child forms are overlaid on its parent when it is visible, and in many ways this lets the interface act in a very similar manner to inheritance in programming, where the "sub form" (child) builds on (or even overwrites) the interface of its "super form" (parent). You can see this in action in the screenshot below.
Forms also have the benefit of letting us cleanly separate the three parts of an MVC application. The view is represented by interface components sitting on the stage of a form, the controller can be an AS2 class bound to the form, and the model can be created as a separate data class. Best of all, we can create a forms-based application without a single line of code in the FLA, using only external class definitions in .as files, and compiled UI components. So where's the catch?Unfortunately, as with so many things in Flash 2004, Forms don't quite seem "complete", and they're still poorly documented in some respects (though that is improving). They seem to be lacking some essential functionality, some of which we will be adding in order to make this tutorial work. They're also despairingly slow, both to work with and to compile, so get used to seeing the image below if you're working on larger projects. The documentation is coming, the community will no doubt extend the Form class to add the functionality it requires (heck, I'm starting that with this tutorial), and hopefully the compile speed will improve with an update to Flash one of these days. I'm sure things will work out well, so let's get down to business! Planning
Setting Up The Project
Now, add all of these files to your project: Open the Project panel, and click the plus icon. Y ou can now select all of the files you just created (except the project file), and click Open to add them to the project. They will be shown in the Project panel as in the image to the right. The Model: Creating the Data ClassWe're going to create a very simple data class to act as our model for the application. Our needs are pretty basic:
Double click on ObjectArray in the project panel to open it, then enter the following code. Read the comments for descriptions of what each method does.
class ObjectArray extends Array {
Check the code for errors ( Tools -> Check Syntax ), save the file, and close it. We'll use an instance of the ObjectArray as our model when we create the controller. The View: Creating the interface
Double click on AddressBook.fla in the project panel to open the Flash Form Application . The first thing you'll notice is screens panel on the left, showing the form hierarchy. The second thing you'll notice is that there is no timeline. Don't panic, it's still there if you need it, but we're not going to touch it. Right now, you should have two forms showing in the screens panel: the root form called application , and a subform called form1 . Rename the root form addressBook , and the subform contactList . Click the plus sign at the top of the panel to create a new subform, and rename it contactEdit . Your screens panel should now look like the image to the right. The root addressBook form handles the global aspects of our application. Its stage will contain any elements that are present throughout the application, and it will be bound to a class that handles the top level application tasks. Similarly, the two subforms each represent a state of the application (listing contacts, and editing a contact), and will contain the interface elements (on their stage) and the programming logic (in the class they are bound to) that is within the context of that state. Click to select each form in turn to edit it, and add interface elements as described below. Right clicking on each of the subforms and selecting Hide Screen will reduce the clutter, and make this task easier.
And that's it for the view. We don't have to write any code - all the code that we need is already present in the UI components. So now all we need to do is glue the model to the view with a bit of business logic -- on to the controller! The Controller: Hell Breaks Loose!Now we're all ready to write the logic that ties our model to our view. Our controller is going to comprise a class bound to each form that defines the business logic for that form. To avoid making this tutorial overlong, I've tried to minimize discussion of the actual code used by commenting it effectively in-line, so pay close attention to the code comments! You're going to love this part (assuming you're a masochist)! Seeing as how we already have AddressBook.fla open, we may as well create the associations between our forms, and the classes that will control them. Click on the addressBook form in the screens panel to select it. In the properties inspector, you will notice a property called Class name - set its value to AddressBookForm . This will bind the addressBook form to the AddressBookForm class we will be defining inside AddressBookForm.as . Select the contactList form and set its class name to ContactListForm , then select contactEdit and set its class name to ContactEditForm . GForm: Pure Band-Aid GoodnessIn an ideal world, we would jump into coding a set of classes that extend mx.screens.Form directly, and they would marry happily to everything we've done so far and we'd be finished. BUT... this is not an ideal world, and mx.screens.Form has a couple of major deficiencies we need to fix first. Normally, when you define classes to bind to forms they inherit directly from mx.screens.Form (the built in Form class). However, in my brief time working with forms, I have identified two major issues with the built-in Form class that prevent me from using them as I would like to:
Double click on GForm.as in the project panel to open it, then copy the code below, paste it into GForm.as , and save. /* ContactListForm: List in carefullyThis class provides the grey matter for the contact list form (bet you hadn't guessed that). It really only needs to do two things:
Study the code below, paying attention to the comments, then copy and paste it into ContactListForm.as and save. dynamic class ContactListForm extends GForm {
// declare the dataProvider property, it's contents will be passed to
// me by the addressBook form.
private var dataProvider:Object;
// declare our UI elements:
private var contactList_dg:mx.controls.DataGrid;
private var delete_btn:Button;
private var addNew_btn:Button;
private var edit_btn:Button;
// function to set up our UI:
function initUI():Void {
// set up buttons - we'll use the lazy way,
ContactEditForm: Edit thisThe ContactEditForm class has to perform 2 additional tasks:
For the first task, we'll simply define a public method called edit that addressBook can pass item and isNew parameters to (calling methods of forms lower in the hierarchy is perfectly fine since they belong, in effect, to the parent form). The second is self-explanatory: Have a look at the code below, then copy it into ContactEditForm and save. class ContactEditForm extends GForm {
// declare our dataProvider object and isNew properties:
private var dataProvider:Object;
private var isNew:Boolean;
// declare our UI objects:
private var name_ti:mx.controls.TextInput;
private var phone_ti:mx.controls.TextInput;
private var email_ti:mx.controls.TextInput;
private var notes_ta:mx.controls.TextArea;
private var save_btn:Button;
private var reset_btn:Button;
private var cancel_btn:Button;
// function to set up our UI:
function initUI():Void {
// set up buttons:
save_btn.onRelease = function() { this._parent.save(); }
reset_btn.onRelease = function() { this._parent.reset(); }
cancel_btn.onRelease = function() { this._parent.cancel(); }
}
// edit method, called by the addressBook form:
function edit(p_item,p_new):Void {
dataProvider = p_item; // the item object to edit
isNew = p_new; // indicates if the item is new
reset(); // fill the interface fields
}
// reset method, populates the interface fields
// with data from the dataProvider
function reset():Void {
name_ti.text = dataProvider.name;
phone_ti.text = dataProvider.phone;
email_ti.text = dataProvider.email;
notes_ta.text = dataProvider.notes;
}
// cancel method, tells the addressBook form that
// we want to return to the list
function cancel():Void {
// broadcast cancelEdit event:
dispatchEvent({type:"cancelEdit",target:this});
}
// save method, compiles data from interface, and
|
| - discuss this tutorial - |