Style Programming

23 07 2008

Consider a scenario in which the requirement is just to create a Window with a Panel that can resize itself by clicking on the button +/- that is located in the top-right corner of the panel. One click should minimize the panel’s height to 20 pixels, and a subsequent one should maximize to 100 pixels. How efficiently do you write the code?

There are many ways to do so.

First method:- With the usage of packages

package
{
	import mx.containers.Panel;

	public class UpDownPanel extends Panel
	{
		private  var isPanelMinimized:Boolean;//whether panel is minimised or maximized

		public function UpDownPanel()
		{
			super();
		}

		//getter & setter for the states
		public function get minimized():Boolean{
			return isPanelMinimized;
		}
		public function set minimized(state:Boolean):void{
			isPanelMinimized=state;
		}
		//resizing function
		public function resizeMe():void{
			if (minimized){
				minimized=false;
				height=maxHeight;
			} else {
				minimized=true;
				height=minHeight;
			}
		}
	}
}

And the mxml is…

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:customPanel="*">

	<customPanel:UpDownPanel id="minmaxPanel" title="Height adjuster"
		width="100%" height="100" headerHeight="20" minHeight="20" maxHeight="100"/>

	<mx:HBox width="100%" horizontalAlign="right" paddingRight="2">
		<mx:Label id="minButton" text="-"
			fontSize="16" fontWeight="bold"
			width="20" height="17"
			click="resizePanel(minmaxPanel)"/>
	</mx:HBox>

	<mx:Script>
		<![CDATA[
			private function resizePanel(value:UpDownPanel):void{
				if (value.minimized){
					minButton.text="-";
					value.resizeMe();
               } else {
					minButton.text="+";
					value.resizeMe();
               }
			}
		]]>
	</mx:Script>

</mx:Application>

Good amount of coding, isn’t it?

Second method:- Simple with a few lines of code only!

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

	<mx:Panel id="minmaxPanel" title="Height adjuster"
		width="100%" height="100" headerHeight="20"
		layout="absolute"/>

	<mx:HBox width="100%" horizontalAlign="right" paddingRight="2">
		<mx:Label id="minButton" text="-"
			fontSize="16" fontWeight="bold"
			width="20" height="17"
			click="{if (minButton.text=='+')
					{
						minButton.text='-';
						minmaxPanel.height=100;
					}else
					{
						minButton.text='+';
						minmaxPanel.height=20;
					}
				   }"/>
	</mx:HBox>

</mx:Application>

That was a nice piece….read the rest too.

Third method:- Using states.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns="*">

	<mx:states>
		<mx:State name="minimized">
			<mx:SetProperty target="{minmaxPanel}" name="height" value="20"/>
			<mx:SetProperty target="{minButton}" name="text" value="+"/>
			<mx:SetEventHandler target="{minButton}" name="click" handler="{this.currentState = ''}"/>
		</mx:State>
	</mx:states>

	<mx:Panel id="minmaxPanel" title="Height adjuster"
		width="100%" height="100" headerHeight="20"
		layout="absolute"/>

	<mx:HBox width="100%" horizontalAlign="right" paddingRight="2">
		<mx:Label id="minButton" text="-"
			fontSize="16" fontWeight="bold"
			width="20" height="17"
			click="{this.currentState = 'minimized'}"/>
	</mx:HBox>

</mx:Application>

What if more controls are there on each state?

Fourth method:- with dynamic classes.

package
{
	import mx.containers.Panel;

	public dynamic class UpDownPanel extends Panel
	{
	}
}

And the mxml is…

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:customPanel="*">

	<customPanel:UpDownPanel id="minmaxPanel" title="Height adjuster"
		width="100%" height="100" headerHeight="20" minHeight="20" maxHeight="100"/>

	<mx:HBox width="100%" horizontalAlign="right" paddingRight="2">
		<mx:Label id="minButton" text="-"
			fontSize="16" fontWeight="bold"
			width="20" height="17"
			click="resizePanel(minmaxPanel)"/>
	</mx:HBox>

	<mx:Script>
		<![CDATA[
			private function resizePanel(value:UpDownPanel):void{
				if (value.minimized){
					minButton.text="-";
					value.minimized = false;
					value.height = value.maxHeight;
               } else {
					minButton.text="+";
					value.minimized = true;
					value.height = value.minHeight;
               }
			}
		]]>
	</mx:Script>

</mx:Application>

Now, that piece of code is extensible, right? Wondering what is dynamic classes? Look here.

Fifth method:- A proper MXML with scripting.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns="*">

	<mx:Component className="UpDownPanel">
		<mx:Panel>
			<mx:Script>
				<![CDATA[
					[Bindable]
					public var isMinimised:Boolean = false;
				]]>
			</mx:Script>
		</mx:Panel>
	</mx:Component>

	<UpDownPanel id="minmaxPanel" title="Height adjuster"
		isMinimised = "false"
		width="100%" headerHeight="20" minHeight="20" maxHeight="100"
		height="{minmaxPanel.isMinimised?minmaxPanel.minHeight:minmaxPanel.maxHeight}"/>

	<mx:HBox width="100%" horizontalAlign="right" paddingRight="2">
		<mx:Label id="minButton" text="-"
			fontSize="16" fontWeight="bold"
			width="20" height="17"
			click="{minmaxPanel.isMinimised=!minmaxPanel.isMinimised}"/>
	</mx:HBox>

</mx:Application>

Finally it was simple, right?

Which of these methods do you think is good in terms of performance/stability/readability/etc? Or if you have another way of doing it, do post it in comments!
Also there are advantages/disadvantages for each method. For example, while using states, it may not become manageable if there are lots of controls in each of the state. Like wise if you can find any, please put it in comments.





ActionScript 3: Dynamic Classes – Part 2

23 07 2008

Well, after a long break, part 2 of dynamic classes. If you want to refresh see Part 1
Continuing to that… read on:

At the time of writing this, subclasses of dynamic classes are not dynamic by default. Due to this, you may run into an ugly run-time error: Error #1056.

Imagine a sealed class, ClassSealed, that extends a dynamic class, ClassDynamic. If you create an object as ClassDynamic myObject = new ClassSealed(), an attempt to add a propery to myObject will produce a runtime error because the variable myObject points to a sealed object.

Try out.
Create a new action script class. Enter Check_Dynamic_Sealed as the class name. Punch in these lines of code:

package {
	import flash.display.Sprite;

	public class Check_Dynamic_Sealed extends Sprite
	{
		public function Check_Dynamic_Sealed()
		{
		}
	}
}

Next, create a new class called ClassDynamic & punch in these lines of code:

package
{
	public dynamic class ClassDynamic
	{
		public function ClassDynamic()
		{
		}
	}
}

Now, instantiate and test the dynamic nature of the class ClassDynamic by adding the constructor in Check_Dynamic_Sealed class, like,

public function Check_Dynamic_Sealed()
{
	var myClassDynamic:ClassDynamic = new ClassDynamic();
	myClassDynamic.favoriteScripting = "ActionScript 3";
	trace("Favorite Scripting = "+myClassDynamic.favoriteScripting);
}

Run this application in the debug mode, and sure enough it’ll print

Favorite Scripting = ActionScript 3, on the console output window.

Create one more sealed class called ClassSealed inherited from the dynamic ClassDynamic:

package
{
	public class ClassSealed extends ClassDynamic
	{
		public function ClassSealed()
		{
			super();
		}
	}
}

Now, instantiate and test the Check_Dynamic_Sealed class using these lines of code:

public function AS_Only_Project()
{
	var myClassSealed:ClassDynamic = new ClassSealed();
	myClassSealed.favoriteScripting = "ActionScript 3";
	trace("Favorite Scripting = "+myClassDynamic.favoriteScripting);
}

Good news is it compiles without any warnings or errors & the bad news is you will get an error saying,

ReferenceError: Error #1056: Cannot create property favoriteScripting on ClassSealed.
	at Check_Dynamic_Sealed()

Now even if you try to instantiate your sealed class as follows:

var myClassSealed:ClassDynamic = new ClassSealed() as ClassDynamic;

the same error occurs.

View another example.

Quoting the words of Yakov Fain, “If you need to add new functionality to one of the existing standard Flex components (buttons, comboboxes and the like), do not bother extending them and creating new classes. Just create one simple empty subclass with the keyword dynamic and instantiate and add new properties on the fly as needed.”





ActionScript 3: Dynamic Classes

23 06 2008

If you’ve created an object from a particular class, you can use only properties and methods that were defined in this class. For example,

class Example{
	String variable_name;
}

You can only manipulate with the variable_name property, like,

Example ex = new Example();
ex.variable_name = “This is a String”;

And for the purpose of tracing/printing-out output etc, you use ex.variable_name.

ActionScript calls such classes sealed, but with the help of dynamic classes, we can programmatically add new properties and behavior to classes during the run-time. Just add the keyword dynamic to the class definition, like,

dynamic class Example {
	var variable_name:String;
}

Now let’s add dynamically one variable new_variable and the function newFunction() to the object of type Example, like,

Example ex = new Example();
ex.variable_name = "This is a String";
ex.age = 30;
ex.newFunction = function () {
	trace (ex.variable_name, ex.age);
}
ex.newFunction(); //outputs -> This is a String 30

Do remember that you do not have complete freedom though, you can dynamically add only public properties and methods. Of course, nothing comes for free and sealed classes are a bit more efficient in terms of memory consumption, because they do not need to create a hash table to store the properties and methods that are unknown during compilation. Another obvious restriction is that dynamically added functions can’t access private members of the dynamic class.

In AS3, any function can be attached to a dynamically created property of a dynamic object, for example

function someFunction():Number {…}

var myObject:SomeObject = new SomeObject();
myObject.calc = someFunction; //add the calc property and attach the function someFunction()
var myVar = myObject.someFunction();

The delete operator destroys the property of an object and makes it eligible for garbage collection:

delete someFunction();
myVar = myObject.someFunction() // generates an error

Some of the Flex classes were defined as dynamic, i.e. Object, Array, MovieClip, NetConnection, TextField, and others.

This is how a dynamic class is used in AS3. Part 2

courtesy: http://flexblog.faratasystems.com/