Flash builder 4 Zend-based sitecounter

December 27th, 2010

Introduction

This is a simple example how to create a connection from a Flex movie to a Mysql database using the Zendframework. To develop this project it is best to have a PHP server installed on your computer. I am using MAMP, which is for Mac. Once we have the server installed we create a database and a table for the application. I have named the database “test” and then created the table using a php file. Just execute the file within the server environment and the table will be created automatically.

The PHP part

Here is described how to create a Flex project with PHP and Zend. So I will not further go into details regarding that. Instead I will focus on the Flex file and the PHP file we need in addition and which contains all the functions. When we create our project, which we name “AS3SiteCounter”, we will have a working folder with the name “AS3SiteCounter-debug”, which contains all the files as shown here. The file we focus on first is in the services folder. The name, which you will find in that folder is probably different at the time the project was created. So rename this file to “SitecounterService.php”. Next we will look at the functions we need for our sitecounter.

We need at least two functions, 1. to add all visitor counts and 2. to add only the unique counts. So the first function is shown here:

	public function addAllData()
	{
  		$link = mysql_connect('localhost', 'root', 'root');
		if(!$link)
		{
			$message = "Could not connect!";
		}
		$link = mysql_select_db('test');
		if(!$link)
		{
			$message = "Could not connect to database!";
		}
   		$query = "SELECT `allcounts` FROM `sitecounter`";
		$result = mysql_query($query);
		$row = mysql_fetch_array($result);
		$counts = $row['allcounts'];
		$newcount = $counts + 1;
		$query = "UPDATE `sitecounter` SET `allcounts` = '$newcount'";
		$result = mysql_query($query);
		if(!$result)
		{
			$message = "Could not add data!";
		}
		else
		{
			$message = $row['allcounts'];
		}
		return $message;
	}

We first need to connect to the host and the database. Then we select the row from the table and define the row variable. The number of counts is held by the $counts variable. We add 1 to it and update the table. Then we return the updated number in form of the variable $message. The other function “addUniqueData()” is very similar. We need, however, a third function, which just returns the number of unique visitor counts without adding a new count. All the functions could have been condensed or shortened, however, for the purpose of simplicity I left it this way. The whole class script is shown here.

The MXML file

When we create the project in Flash builder we have of course a MXML file. As you could see from the movie, we have a pie chart within a panel. So this is what we create first. We just create an instance of the pie chart and give it an id of chart.

	<s:Panel title="Page counts (Flash builder 4)" 
	borderAlpha="0" backgroundColor="0xF9F5F1" 
			 width="450" height="450">
		<s:layout>
			<s:VerticalLayout paddingTop="20"/>
		</s:layout>
		<mx:PieChart id="chart"/>
	</s:Panel>

NOTE: Before adding a pie chart I used two Label components to develop this application to see all the messages.

When you test this movie all you will see is the panel but no pie. That is, because we have no data for the pie. We need to create a php file instead of the html file, which holds the movie. We need to set a cookie at the beginning of the page, for a change we use a php cookie to mark visitors who have opened the site.

<?php
if (isset($_COOKIE['user']))
{
	$myCookie = 'true';
}
else
{
	$myCookie = 'false';
}

$expire=time()+3600;
setcookie('user', 'FLSitecounter', $expire);

We ask if there is a cookie with the name user. Later we create a cookie with the name user and let it expire in 1 hour. If the cookie is valid the variable $myCookie will be “true”. We use a String here instead of a Boolean. Now we need to make another change and add flashvars. We add this line

flashvars.myCookie = '$myCookie';

after

var flashvars = {};

This allows us to retrieve the $myCookie value using flashvars. Now it is time to go back to the Flex movie script. When the movie opens we want two tasks accomplished, 1. check for unique visitors and 2. add every visit to have all the site visits recorded. So in th opening we add an initializer.

initialize="application1_initializeHandler(event)">

In this function we catch the flashvars value.

protected function application1_initializeHandler(event:FlexEvent):void
{
	myBoolean = this.parameters.myCookie as String;
	sendRequest('_unique')
}

And we create a function sendRequest with a String parameter to send a request to the server. In order to do that we need a RemoteObject component pointing to gateway.php, which is a connection to the Zend AMF service and pointing to the SitecounterService class of our php script in the services folder. We also create a CallResponder object, which makes it possible returning the call.

<fx:Declarations>
<s:RemoteObject id="dataService"  endpoint="gateway.php" 
	source="SitecounterService" destination="SitecounterService"/>
<s:CallResponder id="dataResponder" 
result="dataResponder_resultHandler(event)"/>

But first let’s have a look at the sendRequest function, where the call is sent out.

private function sendRequest(_dataRequest:String):void
{
	dataRequest = _dataRequest;
	if(dataRequest == '_unique')
	{
		if(myBoolean == "false")
		{
			dataResponder.token = dataService.addUniqueData();
		}
		else
		{
			dataResponder.token = dataService.getUniqueData();
		}
	}
	if(dataRequest == '_all')
	{
		dataResponder.token = dataService.addAllData();
	}
}

Depending on the dataRequest and the $myCookie value from flashvars we call the functions in the SitecounterService class. Then we wait for the response (result) from the server, which is handled in this listener function.

protected function dataResponder_resultHandler(event:ResultEvent):void
{
	myResult = event.result as String;
	if(dataRequest == '_unique')
	{
		unikCounts = int(myResult);
		sendRequest('_all');
	}

Here we store the value for unique counts in a variable unikCounts, which is bound. Then we send the next request to count all visits. When that respnse is coming back from the server we create the pie chart.

		if(dataRequest == '_all')
		{
			allMyCounts = int(myResult);
					
			var series:PieSeries = new PieSeries();
			series.field="number";
			series.labelField="descript";
			series.explodeRadius=.02;
			series.setStyle("labelPosition", "inside");

			chart.visible=true;
			chart.dataProvider=salesData;
			chart.width=440;
			chart.height=440;
			chart.series=[series];
			contentGroup.addElement(chart)
		}

However, we also need to create a data model to provide a DataProvider. We use the Model object and create an XML file as DataProvider where we store the variables with the counts. We convert the data to an ArrayCollection. The variables need to be bound variables.

<fx:Model id="numDistribution">
	<counts>
		<row>
			<descript>Unique counts: {unikCounts}</descript>
			<number>{unikCounts}</number>
		</row>
		<row>
			<descript>All counts: {allMyCounts}</descript>
			<number>{allMyCounts}</number>
		</row>
	</counts>
</fx:Model> 
<s:ArrayCollection id="salesData" source="{numDistribution.row}"/>

And this is basically all. Check here to see the complete script. When we test the movie we will see that all counts increase but unique counts only as long as the cookie is not placed. We now need to upload the files to the server. How that is done is described here.

Flash builder: Zend data service files to server

June 13th, 2010

Recently, I wanted to learn how to use the Zend framework with Flash builder. I found a (**)tutorial, which explains the use of Zend with MAMP. I created all those files and the database and it worked. Now I wanted to upload these files to the server. However, this does not work without changes.

I uploaded the folder “ZendFramework” to the server. I created a folder flashbuilder to where I uploaded all the flash movie files. I changed the script “ClientsService.php”, which is located in the services folder. These are the database variables, which have to be changed to the new database names except for the port and the table name.

  • var $username = “root”;
  • var $password = “root”;
  • var $server = “localhost”;
  • var $port = “3306”;//no change
  • var $databasename = “fb4″;
  • var $tablename = “clients”;// no change
  • This is all, which needs to be done in this file. We don’t need to make any changes in “gateway.php”. We need to change the amf_config.ini file. Originally on the harddrive the file looked like this:

    [zend]
    ;set the absolute location path of webroot directory, example:
    ;Windows: C:\apache\www
    ;MAC/UNIX: /user/apache/www
    webroot =/Applications/MAMP/htdocs
    
    ;set the absolute location path of zend installation directory, example:
    ;Windows: C:\apache\PHPFrameworks\ZendFramework\library
    ;MAC/UNIX: /user/apache/PHPFrameworks/ZendFramework/library
    ;zend_path =
    
    [zendamf]
    amf.production = false
    amf.directories[]=FlexZend-debug/services

    We change the webroot variable to

    webroot = /home/content/x/y/z/xyzaaa30/html

    You find this path by creating a php info file:

    <?php phpinfo(); ?>

    and opening the file in your browser. The “DOCUMENT_ROOT” value in the table is what you are looking for. The next path we need to change is the path to the ClientsService.php file for Zend to find. So change to something like this.

    amf.directories[]=flashbuilder/FlexZend/services

    In my case the folder with all the flash files is “FlexZend”, since I exported the release built from Flash builder. Now you can test your application and it should work.

    (**) The former link has been replaced by a new link because of a bad web site.

    New Flash Loader methods

    May 9th, 2010

    I recently had an annoying problem, when I wanted to unload a movie from a Loader object. The childmovie had a Timer running, which influenced a textfield in the parent movie, as it was set up. When the child movie was unloaded using myLoader.unload() the Timer continued and even objects of that movie were not null although the movie was clearly unloaded and a new movie was loaded. Flash player 10 has a feature, which prevents this and stops all actions from unloaded movies. Instead of myLoader.unload(), we use myLoader.unloadAndStop().

    A feature introduced with CS5 (player 10.1) is the uncaughtErrorEvents property, which is triggered when an error occurs. This avoids using the try..catch method.

    Flash CS5 output messages: AS3Trace

    May 1st, 2010

    Flash CS5 is out. I downloaded it, installed it and tested it using some of my movies created with CS4. A larger movie I have been working on for some time…. CRASHED! Well, that happened often with new Flash versions especially on a Mac. Then I tested one small movie and I got a large out put, which I did not understand. Now I just made a new very simple movie and experienced the same thing. Then I just deleted everything and tested a basically empty movie and got this output, which I could not explain. So I googled and there was only one – really great – pre CS5 blog, which shed light into this. So I searched for a mm.cfg file and found it where in the blog it was described.

    • Windows; C:\Documents and Settings\username\mm.cfg
    • OSX; /Library/Application Support/Macromedia/mm.cfg
    • Linux; home/username/mm.cfg

    To eliminate all the output traces one needs to set AS3Trace=1 to AS3Trace=0. Close and restart Flash and the output traces will disappear. Also the large movie, which originally crashed was now working properly. However, this feature is as described in the blog a great feature. So have the mm.cfg bookmarked and make use of the feature as described in the blog whenever necessary.

    Adding CheckBox instances to a DataGrid column

    February 11th, 2010

    Once in a while somebody wants to add an icon or more often a component in the DataGrid component. This seemed to be easier with AS2 components and there are some tutorials. However, this is different with AS3 components. Adobe has a nice article about manipulating the DataGrid. One of the tutorials on that site shows how to add images to the DataGrid using the UILoader component. In the following we want to add CheckBox instances to cells of one column.

    Extending the CheckBox class – implementing the ICellRenderer interface

    I will show two ways, but the aim is different. In the first part we add a CheckBox and clicking a DataGrid row will select the CheckBox as shown in this movie. We first create a Documnent class where we add the DataGrid. We associate a CellRenderer to the row, where we want to show CheckBox instances. Clicking another row will select the CheckBox in that row and unselect the previous CheckBox.

    _check.cellRenderer = SpriteCellRenderer_1;
    

    We then write the class SpriteCellRenderer_1. This class extends the CheckBox class and implements the ICellRenderer class. We need to add some functions to this class, which basically stay empty. This is because the ICellRenderer interface has certain properties and methods. Some of these overlap with the CheckBox class but some not and those are the ones we add. If you test movie at this stage you will see CheckBox instances added but without label. So in the constructor of this class just add this line

    label = "Check it out";
    

    and that is all.

    Using the CheckBox in the DataGrid to select items for a shopping cart

    That was quite simple, however, there is no real functionality of the CheckBox. In the next example we select CheckBox instances and the items associated with them will be added to a shopping cart list. The Document class is very similar as previously except for some important differences, which I will explain. We extend the Document class to a new Abstract class, which we have to write. This is because we need to communicate from outside the Document class. I have documented this in a separate blog article. Another change is of course that data which we receive from the CheckBox selection will be monitored and stored in an array, which is the listener function when a row is pressed.

    So now let’s have a look at the SpriteCellRenderer class, which is equivalent to the SpriteCellRenderer_1 class from the previous movie. The SpriteCellRenderer class this time extends the Sprite class and also implements the ICellRenderer interface. Our strategy is to create a Sprite instance and then using addChild we add a CheckBox instance, which is independent from the DataGrid row MouseEvent. We need to add all the methods from the ICellRenderer interface, since the Sprite class does not share any of those. In order to add the CheckBox to the DataGrid we create a Sprite in the fla and name it “MyIcon”. This Sprite is associated with its own class. If you go back and look at the Document class of this movie you should look at the place where we add items to columns.

    dp.addItem ({no:"1",item:"Apples",price:"$1,50",data:"MyIcon"});
    

    The last part is the “_check” column with “data” as the variable. We place a Sprite instance in the DataGrid by adding this script to the function “set data” in the SpriteCellRenderer class.

    public function set data (value:Object):void
    {
    	_data = value;
    	if (!wasSelected)
    	{
    		var ClassReference:Class = getDefinitionByName(_data.data) as Class;
    		var instance:Object = new ClassReference();
    		addChild (DisplayObject(instance));
    		wasSelected = true;
    	}
    }
    

    The Boolean “wasSelected” is to prevent that every time a DataGrid row is selected more instances are added to the Displaylist. We have now achieved to add an instance of MyIcon to a row of the DataGrid.

    Next we need to add the CheckBox. We do that using the MyIcon class. Go through the script and you see where. The last task is to communicate with the Document class to manipulate which items the user wants to select. If you look at the “MyIcon” class you see that it also extends the Abstract class and so shares properties and methods with the Document class. So we use the the set_Message method to send a message to the Document class. The nice thing here is that when we select the CheckBox we also trigger the DataGrid CLICK event and by using the get_message method know what is the selection status. Finally, we add our selection to an array or delete it again if we decide to unselect it. Check the scripts, which have a lot of additional comments. You can download all files here.

    Flash AS3: PDF attachment with email

    February 1st, 2010

    For Flash

    I recently had to get into email attachments using Flash. So I found the nice alivePDF library, with which one can create PDFs in Flash and Flex. I searched for tutorials and found this. As you can see in this example one can download a PDF file by opening a new browser page. I wanted to convert this to attach the PDF to an email. That was not difficult, although I had to struggle a bit with the PHP file. However, again the problem was that a new page was opened, which I did not like. My goal was to have everything done within the Flex or Flash file as shown below. No email will be sent in this movie to avoid misuse. However, enter an email in the text input and press the save button. You will see that no new window is opened but a message appears.
    To create this movie I followed the example for the Model View Controller for Flash.

    What I have done is I have slightly modifed the PDF.as file and created files in the Model-View-Controller style. You need to download the alivePDF library. Open the PDF.as file in the PDF folder and add the following lines where packages are imported.

    /***********************************************************
    * Classes need to be imported for saving PDF as attachment.
    */
    	import com.flashscriptMVC.AbstractClass;
    	import com.flashscriptMVC.IModel;
    	import com.flashscriptMVC.Model;
    	import com.flashscriptMVC.Controller;
    	import com.flashscriptMVC.Mediator;
    	
    /*********************************************************/
    

    Now we need to modify the save function. I added another parameter for the email and made it null. This does not affect any functionality of other projects, if you have those. Then I initiated a new class, the Mediator class, which serves as a Viewer class, since we cannot use the actual viewer object, which you see in the movie, for this purpose. The modification is shown below. Also we use the Base64 encoded bytearray, since we use that for the attachment later.

    /****************************************
    * The save function is altered for attaching a pdf to an email. 
    * The function has one more parameter.
    *****************************************/
    public function save ( method:String, url:String='', 
    downloadMethod:String='inline', fileName:String='output.pdf', 
    frame:String="_blank", myEmail:String = null ):*
    {
    	dispatcher.dispatchEvent( new ProcessingEvent 
    	( ProcessingEvent.STARTED ) );
    	var started:Number = getTimer();
    	finish();
    	dispatcher.dispatchEvent ( new ProcessingEvent 
    	( ProcessingEvent.COMPLETE, 
    	getTimer() - started ) );
    	buffer.position = 0;
    	var output:* = null;
    			
    	switch (method)
    	{
    		case Method.LOCAL : 
    		output = buffer;
    		break;	
    				
    		case Method.BASE_64 : 
    		output = Base64.encode64 ( buffer );
    					
    /*************************************************************************
    * To send the PDF file as attachment we use the BASE_64 method and send the
    * already converted data to the server. We use the Mediator class as a 
    * Pseudo viewer class, whic communicates then with the controller and model 
    * class and in the end with the SavePDFView object. Like a regular viewer
    * we add eventlisteners.
    */
    
    var model:IModel = new Model();
    var controller:IControlHandler = new Controller(model);
    if(downloadMethod == "attachment")
    {
    	if(myEmail == null)
    	{
    		trace("Don't forget to unnullify the myEmail parameter!")
    		return;
    	}
    	var c:Mediator = new Mediator (model,controller);
    	c.pdfHandler (url, output, fileName, myEmail);
    	model.addEventListener ("serverResponse", c.update);
    	model.addEventListener ("erMSG", c.update);
    						
    /******************************************************************************/
    }
    break;
    

    I am not showing all the classes. You need to be familiar with the Model-View-Controller pattern. However, if you are not, then the only class you need to take care of and modify for your purpose is the SavePDFView.as clas, which is the viewer and the SavePDFMain.as class, which is the Document class of the movie. All other classes don’t need to be modified. Some of the labels and urls used in the movie are written in the xml file savepdf.xml and can be changed there.

    For Flex

    For Flex we can use the same classes except we need to create a MXML file of course and we need to change the Flash viewer class. The MXML file is shown here. It communicates with the former Flash viewer file, which we also need to modify as shown here. All other classes need not be modified.

    We need to look at the php file. I found the script part for the attachment from various sources from the internet and modified them for this script. The first part of the script is the important part. There are the parameters from the Flash movie. As you may remember, the buffer, the actual pdf content, is already Base64 encoded. We create a temporary file and write the contents of the buffer variable into the file. At a later point we delete the file using the unlink() function.

    <?php
    
    $buffer = $_POST['buffer'];
    $name = $_POST['name'];
    $email = $_POST['email'];
    $tempname = tempnam("/tmp", "PDF");
    
    if ( isset ( $buffer )) 
    {
    	$files = fopen( $tempname, 'w' );
    	$data = fwrite( $files, $buffer );
    	fclose( $files );
    }  
    else 
    {
    	fail("An error occured encoding.");
    }
    

    You can download all files here. You can freely modify these files and use or distribute them as long as it is complient with the rules for the alivePDF library. Don’t forget to add the alivepdf library with the modified PDF.as file where an empty org folder is located.

    Changing AS3 Component Styles with As

    December 15th, 2009

    An often reoccurring question is how to change the appearance of Flash components. This appeared easy to do with AS2 components. But actually it is much easier with AS3 components, where you have access to all skins and not only by just clicking on the component but also by using Actionscript. As an example we look at the ComboBox and I will show two ways to change the look of individual instances.

    The first way is to just use the colorTransform method as shown in this movie. You will see two ComboBoxes, cb1 and cb2. cb1 was changed using different parameters. First of all the color was changed using colorTransform. We also change the alpha value of the BaseButton, which is part of the ComboBox and which is the first child: cb1.getChildAt(0). The second child is the TextInput component, which we can get by using instance.textField. The script for the movie you just saw is here. We just put two components on the stage.

    import fl.controls.ComboBox;
    import flash.geom.ColorTransform;
    //
    var _color:ColorTransform = new ColorTransform();
    _color.color = 0x3399CC;
    cb1.transform.colorTransform = _color;
    cb1.getChildAt(0).alpha = 0.5;
    //
    var myTextFormat:TextFormat = new TextFormat();
    myTextFormat.font = "Impact";
    myTextFormat.color = 0x000000;
    myTextFormat.size = 14;
    cb1.textField.setStyle ("textFormat",myTextFormat);
    //
    cb1.addItem ({label:"Apples"});
    cb1.addItem ({label:"Oranges"});
    cb1.addItem ({label:"Banana"});
    cb2.addItem ({label:"Spinach"});
    cb2.addItem ({label:"Salad"});
    cb2.addItem ({label:"Cucumber"});
    


    We also change the TextFormat of the TextInput of cb1 as you can see.

    While this is one simple way of individualizing a component instance there is a much more elegant way. If you open the library of a movie, which has a ComboBox you will see a folder with the Component assets. Open the folder and you will see several folders, one of them named ComboBoxSkins. For our next exercise copy the MovieClip for ComboBox_upSkin, ComboBox_overSkin and ComboBox_downSkin. Give them new names, UpSkinBlue, OverSkinBlue and DownSkinRed. Fill out the form as shown here.Then change the color of the MovieClip as you like. I already did it, if you look at this final movie. To change the style of a ComboBox instance we use the setStyle() method. But how do we know the parameters. It is very simple. Check the Language Reference for the ComboboBox and scroll down to Styles. If it is not open, open it and you see a large number of references. One of them is upSkin, which is the skin for the default ComboBox. Now let’s change the skins using Actionscript.

    import fl.controls.ComboBox;
    //
    var myTextFormat:TextFormat = new TextFormat();
    myTextFormat.font = "Impact";
    myTextFormat.color = 0x003399;
    myTextFormat.size = 14;
    //
    cb1.setStyle("upSkin","UpSkinBlue");
    cb1.setStyle("overSkin", "OverSkinBlue");
    cb1.setStyle("downSkin", "DownSkinRed");
    cb1.textField.setStyle ("textFormat",myTextFormat);
    //
    cb1.addItem({label:"Apples"});
    cb1.addItem({label:"Oranges"});
    cb1.addItem({label:"Banana"});
    cb2.addItem({label:"Spinach"});
    cb2.addItem({label:"Salad"});
    cb2.addItem({label:"Cucumber"});
    


    The script is very similar to the one of the former movie except that we are setting styles. The first parameter is the Style parameter, for instance upSkin. The second parameter is the style we want to apply, in our case the style of the MovieClip UpSkinBlue. Therefore, we add the class name of the MovieClip, which should be the same as the id. And that is all we need to do. If we want to change all instances of the ComboBox then we use the StyleManager class:

    StyleManager.setComponentStyle(ComboBox, "upSkin","UpSkinBlue");
    


    And that concludes this tutorial. Download the files here.

    The Event Pattern: Flash AS3

    November 16th, 2009

    A major problem is the communication between different objects like Sprites and MovieClips, in particular when they are in hidden locations in a movie. While we can use the direct communication using parent, parent.root or something similar, this is not good, because we have a direct dependency. We want to avoid direct dependency and have only very loose contact. Fortunately, in Flash we have the event model, which we can make use of. In the following I show an example how we can make use of it for communication between different objects.


    Our objective is to gather information from different sources and display this information in one and the same textfield. First we make an outline of what we want, which you can see here. We want to process information from different sources and display in one textfield. In the following the classes are shown.

    The AbstractClass class

    To make it simple we create one class with a button, the AddModul class, which triggers the increase of a counter and one class, the DeleteModul class which triggers the decrease of the counter. Those are the classes, which send the information to a receiver class, which has a textfield and will display the result. As you can see from the outline, we have a black box, which processes the information. This box, the AbstractClass class, is a superclass for all the objects. The class is shown here. Basically there is a getter and setter method, which is internal and can only be used by subclasses of the AbstractClass class. The setter method contains a line, which triggers an event. We need, however, an object for the event, which can only be used by the subclasses. This excludes the main timeline and the stage, which can also be accessed by any other object. Therefore, we create a Sprite, myObject, and make it an internal static variable, which means that it can only be accessed by the subclasses and there is only one instance possible. Further, we need to give the event a name, which we do in form of a static constant. Although this name can be used outside of the subclasses, without an object, which will listen to the event, we are safe. Now let’s turn to the DisplayModul class and see how we get the information from one of the other classes.

    The DisplayModul class

    The DisplayModul class codes for a Label component, which displays the result, when one of the buttons is pressed. Other than that there is only the listener for myObject. We can then get the getter method, which contains the new message. Finally, we need to look at the Document class, Main.as, where all the objects are placed on the stage. We can place any of the objects, wherever we want in the movie. As long as they are sublasses of the AbstractClass, we can always send the message. And this concludes the tutorial.

    Passing variable to a child movie with event pattern

    In the same way we can also pass variable values to a child movie. All we do is extend the Documentclass of the parent and child movie to the same Abstract class.

    You can download all files here.

    Composite Pattern: Flash AS3 Menu example

    November 8th, 2009

    If you are serious with Actionscript it is a must to use Design patterns. Why? Because

    • large scripts are broken into smaller reusable pieces,
    • the relation of objects and actions becomes loose, which
    • allows to make changes in a small script instead of having to change a large script.
    • Only the interface is visible to the client.

    There is a nice book “Actionscript 3 Design Patterns”, in which taken from other programming languages various design patterns are described with examples. However, my idea is to keep the scripts even more conceiled by using xml and manipulating text, url’s, file names with an xml file. Go to Model View Controller for Flash, if you want to see the example.

    The other day somebody had a problem with removing children from a menu. So I thought to write some basic scripts using a suitable design pattern for a menu, which makes it very easy to remove children. The reason is simple, because now the movie is organized and can be controlled. The most suitable pattern, which I could think of, is the Composite pattern, which is similar to the Displaylist or the DOM or tree structure. If you want to know more, check Wikipedia for details.

    First we make an outline of the structure of the menu, which you can see here. Even it is a simple menu it is important to see the organization of the final product. The ROOT is the holder of the menu and will be a component. Then we have 5 menuitems, which except for the m4 item has subitems. We create a Component class, which extends Sprite and is the class for items, which have children other than those, which make the design of an object such as a textfield. So we create the MenuItem class, which extends the Component class and associate it with the Sprite for the menuitems. We further create the Composite class, which extends Sprite and is the superclass for the leaf children. Both classes implement the IMenu interface, because there are methods, which both classes share. We create another class, the SubMenuItem class, which extends the Composite class and associate the submenu Sprite with this class. We have basically all classes ready except for the Document class of the movie, which we name Main and extends Sprite. Now we need to write the scripts for the classes.

    The MenuItem class

    We start with this class and you can see the final class here. The Constructor of this class has three parameters, which are inherited from its superclass, the Component class. Those are for an array to hold the information for the children, then a headline and in case we don’t have any further children we need a url. m4 is such a menuitem. We then create a textfield for the headline and we add button events. We want the menitem to have a shadow on mouseover and remove the shadow on mouseout. We also want that the submenuitems be removed when the client wants to access another menuitem. So we create a function “deleteItems”, which we define in the Component class. When we click on the menuitem we want the submenu to appear, which we do by adding submenuitems. The number of the items, their headlines and urls are stored in the array. We then trigger another method, addItems, which is a method of the superclass. This is important, since the instances need to be stored somewhere to be able to remove them later. In case there are no subitems we trigger a method, showItem, which is also a method of the Component superclass. Now we need to have a closer look at the Component class.

    The Component class

    The constructor of this class has three parameters, which we already learned earlier. We have a getter function for each of these parameters, which are also part of the interface, since these functions are shared by the Component and Composite classes. Then we declare several internal functions, which should only be visible to the subclass(es), which in our case is only one, the MenuItem class. There is showItem, where we execute for simple reasons a trace function. We would normally use something like navigateURL. Inside this function we have the setParent(this) function, which serves to memorize this instance of the menuitem. If you look at the setParent function then we have a static variable “previousNode”, which associates with this instance. Then we have the addItems (mySub:Composite) function. This function adds individual submenuitem instances to a Vector with the data type “Composite”, since that is the superclass for the SubMenuItem class. We also have here the setParent function for reasons mentioned above. Next we have the deleteItems() function. This function serves to remove the children of the previous menuitem, when a new menuitem was pressed. And now you can see for what we need “previousNode”. We safely remove the children. We can do that in a more sophisticated way with tweens etc. if we feel to.

    All other classes

    You probably get an idea how this works, so I only place links to the other classes, which are left, the Composite class, the SubMenuItem class, and the IMenu class. However, I will go into more detail for the Main class, which is our Document class.

    Main class

    We want this menu to be flexible and not do any changes in our scripts, when we want to extend the menu. So we use xml for this. You can see the Menu.xml file here. We load the xml file first, which you can see in the beginning of the Document class. Then we extract all the information. First we create the ROOT of the menu, which is of data type Component and will hold all the children. “xmlData.menuitem.length()” will give us the number of menuitems, which we add to the ROOT. “xmlData.menuitem[i].menusubitem.length() will give us the number of subitems for each menuitem. We can extract the headlines and urls and fill an array, which we add as a parameter to each associated menuitem. Then we arrange the menuitems and add them to to the ROOT. And that concludes this tutorial. You can download all files here.