Archive for May, 2008

Setting private property values of a cloned ActionScript 3 object

Saturday, May 24th, 2008

Sometimes when cloning an object it is desirable to set a private or read-only property on the clone. Since these properties aren’t writable from outside the class itself, how can their values be changed?

Drawing from the ideas of Grant Skinner’s post on Singletons the same internal class technique can be used to set properties on an object through its constructor, but only if it is instantiated within the class itself, such as through a clone() method.

The following is an example of a simple class that has a clone() method and the clone has a read-only property that is set when it is instantiated:

package
{
	public class Cloner
	{
		/*----------------------------------------------------------------------
		* properties
		*---------------------------------------------------------------------*/
		private var _isClone_:Boolean = false;
 
		/*----------------------------------------------------------------------
		* constructor
		*---------------------------------------------------------------------*/
		public function Cloner( allow:AllowConstructorArguments = null , prop:Boolean = false ) 
		{
		  	if ( allow is AllowConstructorArguments ) 
		  	{
		  		_isClone_ = prop;
		  	}
		}
 
		/*----------------------------------------------------------------------
		* public methods
		*---------------------------------------------------------------------*/
		/**
		* Whether this object was created from the clone method.
		*/
		public function get isClone() : Boolean{ return _isClone_; }
 
		/**
		* Create a clone of this object
		*/
		public function clone() : Cloner
		{
			return new Cloner(new AllowConstructorArguments() , true);
		}
	}
}
 
 
/**
* Internal class for allowing arguments in the constructor if this class is 
* instantiated from within this class.
*/
internal class AllowConstructorArguments{}

Alternatively, if you would not like the constructor to have a long list of parameters. The … (rest) parameter could be used in the constructor, like so:

...
		public function Cloner( ... args:Array ) 
		{
		  	if ( args[0] is AllowConstructorArguments ) 
		  	_secretSwitch = Boolean(args[1]);
		}
...

The class can be tested with the following:

			var c:Cloner = new Cloner();
			var d:Cloner = c.clone();
 
			// outputs: false true
			trace( c.isClone , d.isClone );

Transformational Canvas v1.0

Wednesday, May 14th, 2008

I wanted to create a Flex Canvas-based component that acted like a camera looking down on a tabletop containing objects. Any item added to the canvas would automatically be able to be dragged as a group and individually, while the whole view could be zoomed and rotated. Here is the result:

 

This movie requires Flash Player 9

Download Source Here

This component uses the Draggable Behavior classes described in this post.

By default the canvas center point is the center of the canvas, obtained by retrieving one half of the width and height of the canvas. This way the center point always remains in the center (+/- the x,y center point offsets) of the canvas even if the canvas is resized. However, the center point can be made to remain at a specific x,y coordinate by binding the x,y center point offset to negative one half the width and height of the canvas and adding x and y values of a desired amount. The following example keeps the center point at the x,y coordinates 100,100, even if the canvas is resized:

<ab:TransformationalCanvas
id="tcanvas" 
centerPointOffsetX = "{-(tcanvas.width/2)+100}"
centerPointOffsetY = "{-(tcanvas.height/2)+100}"
>

Also, note that the Transformational Canvas origin x,y (0,0) coordinate is at the center point, not at the upper-lefthand corner. That means that children placed at 0,0 will appear at the center point, not at the upper-lefthand corner.

Please post bugs, questions, etc.

Encapsulating interactive behavior in Flex applications for better code readability

Wednesday, May 7th, 2008

Consider for a moment dragging an element within an application. The steps required for this operation are as follows:

Behavior Description Event to listen for
START DRAGGING… When the mouse button is pressed down over the element. MouseEvent.MOUSE_DOWN
DRAG… While the mouse is moving and the mouse button is pressed down over the element. MouseEvent.MOUSE_MOVE
STOP DRAGGING… When the mouse button is released over the element. MouseEvent.MOUSE_UP
When the mouse is moved outside the stage (e.g. outside the application window). This is necessary because we cannot determine whether the mouse button has been released while the mouse is outside the application window. Event.MOUSE_LEAVE

Adobe Flex’s event model makes it easy to listen for interactive mouse events within an application. A simple operation like a mouse click only requires listening for a MouseEvent.CLICK event being dispatched from the element in question, like so:

element.addEventListener( MouseEvent.CLICK , _element_clickHandler );
...
protected function _element_clickHandler( event:MouseEvent ) : void
{
// handle click on element
}

While handling a mouse click is simple enough to do, more complex interactive behavior such as dragging requires listening to multiple events from both the element in question as well as the stage. Implementing this behavior can clutter your code and not be as clear as it could be, since there is not a dragging event to listen for natively in Flex (Drag and Drop aside).

An alternative is to encapsulate the dragging behavior in a separate class that acts as a proxy for the element and issues its own events that the main application listens for. For example:

var behavior:DraggableBehavior = new DraggableBehavior(element);
element.addEventListener( DraggableBehaviorEvent.DRAGGING , _element_draggingHandler );
...
protected function _element_draggingHandler( event:DraggableBehaviorEvent ) : void
{
// handle dragging of element
}

This moves all the event handling methods and listeners to a separate class file, organizing your code better. It also creates an event that more accurately reflects what operation is going on.

 

This movie requires Flash Player 9

Download Source Here

Efficient storage and retrieval of boolean values using bitwise operations

Thursday, May 1st, 2008

Since each digit in a binary number is only composed of one of two possible values, 0 or 1, a binary number can be thought of as a series of switches.

Each of these switches can be thought of as a TRUE or FALSE value if it is 1 or 0. So a binary number can then be used to represent a list of boolean values. If we assigned a property to each bit in this binary number we would be able to store the value of a set of boolean properties (five properties in this case) within a single number.

For example, suppose you wanted to limit access to your computer for certain users, and you wanted to store what privileges each user had within a database. You could create a table for the users and create fields for CAN_READ, CAN_WRITE, CAN_EXECUTE. This would work fine, but using a binary number as the storage mechanism for the privileges can make this process much more elegant and efficient.

Take a three bit binary number, for instance, 111 (read that as one-one-one). Each bit could be assigned a boolean value. So the rightmost bit could represent the boolean value for CAN_READ, the middle bit could represent CAN_WRITE, and the leftmost bit could represent CAN_EXECUTE. Therefore switching any of these three values to 0 within the binary number would specify that that privilege was not granted for a particular user. For example, the binary number 011 (otherwise written as 3 in decimal) would specify that a user could read and write files on the computer but could not execute applications.

To create this kind of arrangement create a table to hold the privileges (a.k.a. permissions). Insert entries into this table for each bit in the whole binary number. Next create a users table that has a field for holding a number that represents what privileges a user has. In the permissions table each entry will only have one bit turned on, while the entries in the users table could have multiple bits turned on because a user could have more than one privilege on the computer.

So here is the SQL to create those two tables and fill them with data:

CREATE TABLE PERMISSION
(
	bit			BIGINT NOT NULL UNIQUE,
	name			VARCHAR( 32 ) NOT NULL UNIQUE,
	description		VARCHAR( 2048 ) NOT NULL,
	PRIMARY KEY ( bit )
);
 
CREATE TABLE USER
(
	id			SERIAL,
	name			VARCHAR( 32 ) NOT NULL UNIQUE,
	bitpattern		BIGINT NOT NULL,
	PRIMARY KEY ( id )
);
 
INSERT INTO PERMISSION ( bit, name, description )
	 VALUES ( 1, 'CAN_READ', 'User can read files');
INSERT INTO PERMISSION ( bit, name, description )
	 VALUES ( 2, 'CAN_WRITE', 'User can write files');
INSERT INTO PERMISSION ( bit, name, description )
	 VALUES ( 4, 'CAN_EXECUTE', 'User can execute applications');
 
INSERT INTO USER ( id, name, bitpattern )
	 VALUES ( 1, 'admin', 7);
INSERT INTO USER ( id, name, bitpattern )
	 VALUES ( 2, 'manager', 3);
INSERT INTO USER ( id, name, bitpattern )
	 VALUES ( 3, 'enduser', 1);

Here’s what they look like in a more visual way: 

…and filled with data:

Now to pull the permissions for a particular user out of the database we will use the bitwise AND operator (&). This operator compares two numbers binary bit by binary bit. If the bit at a particular position in both numbers is 1, then the bit at that position in the resulting number is 1, otherwise it is 0. So for example if we took the numbers 011 (3 in decimal) and 100 (4 in decimal) and performed a bitwise AND operation on them it would look like this:

011
100
—-
000

The result is 000, because none of the 1 bits overlapped. If the first number was the permissions a user had and the second number was the permission to execute applications, then performing a bit AND operation on these two numbers would determine that that particular user could not execute applications. If it had resulted in any other number besides 0 it means that they could execute applications. Therefore to query the database to find the permissions of a particular user we would perform the following:

SELECT * FROM USER, PERMISSION 
	  WHERE (bitpattern & bit != 0) 
	  AND (name = 'manager');

Which would search through the PERMISSION table and only return those entries where a bitwise AND operation between the ‘manager’ user’s permissions number and the bit of the privilege did not return 0. In this case it would return the entries for CAN_READ and CAN_WRITE.

Formatting decimal as binary

Thursday, May 1st, 2008

While most of the time you will see numbers in the decimal number system (using the digits 0 through 9), internally within your computer these numbers will be represented in binary. In the binary numeral system each number can only be composed of a sequence of two values: 0 or 1, ON or OFF, TRUE or FALSE, and so on.

Binary numbers are sequences of 1’s and 0’s, moving from right to left, each occurrence of a 1 is equivalent to twice the decimal value of the previous digit’s decimal value. Take for example the binary number 11111111. The first digit has the decimal value of 1, the second has the decimal value of 2, the third has the decimal value of 4, and so on. Adding all these values together equals the final decimal value, which in this case is 255.

Each digit in a binary number is called a bit, in this case all bits are 1. If some of the bits were 0, they would not add to the resulting decimal number, but they would still represent a place within the sequence.

To play around with converting numbers from one base to another, try my Base Converter widget.

Treating decimal numbers as binary numbers is useful when dealing with bitwise programming, where individual bits within a binary number can be switched to their reverse value (either 1 or 0). This allows for extremely efficient division by 2 arithmetic and for a technique of representing binary numbers as an efficient storage mechanism for a bunch of boolean values.

Number Base System Converter

Thursday, May 1st, 2008

Sometimes it is handy to be able to convert a number from one base to another, especially when working with bitwise operations. To help you in that endeavor I present the Base Converter:

This movie requires Flash Player 9