Archive for the 'flex' Category

Using the Senocular AS3 TransformTool in Flex

Hey,I am so interested about that you had ever used the ‘TransformTool’ library in your Flex project. But there is little examples showing how to use it in flex, Would you please share some example about how to use ‘TransformTool’ in Flex? I have tried as such a way:

but it failed at line
canvas.addChild(defaultTool);
Can you give any hints? Thanks.

Like most pure AS3 display classes, the TransformTool needs to be added to a UIComponent wrapper to function properly in Flex.

Source.

Flex component transformation with ObjectHandles

Rogue Development's ObjectHandles is a great component. It is simple to use and provides all of the functionality that I was looking for in a transformation modifier. Prior to implementing this, I was using the TransformTool from senocular.com's library. This is also a great utility, but it wants to scale my content, and that was a deal breaker in my current project. ObjectHandles does NOT resize the child components. There are use cases for both approaches, but ObjectHandles allows me to decide when to scale.

<?xml version="1.0" encoding="utf-8"?>
<ObjectHandles
	xmlns="com.roguedevelopment.objecthandles.*"
	xmlns:mx="http://www.adobe.com/2006/mxml"
	allowRotate="false"
	objectMovedEvent="objectUpdatedHandler( event )"
	width="{image.width}"
	height="{image.height}" >
<mx:Script>
	<![CDATA[
		import com.roguedevelopment.objecthandles.ObjectHandlesMouseCursors;
		public static const CHANGE:String = "imageBoxChanged";
 
		private function objectUpdatedHandler( event:Event ):void
		{
			dispatchEvent( new Event( CHANGE, true ) );
		}
	]]>
</mx:Script>
	<mx:Image id="image" source="@Embed(source='/assets/cower.png')" />
</ObjectHandles>

Accessing a List from its itemRenderer

This was really throwing me off tonight. I could not figure out how to get at the List from its itemRenderer. this.parent... no this.owner... no

So I started The Search™, trying to hunt down The Answer™. This is one of those things that doesn't just jump out of the manual at you. Luckily, Peter Ent is running an extremely informative series on itemRenders. He says to get at the List, we need to simply access the listData property. But there's a catch:

Most controls such as Text, Label, Button, CheckBox, and so forth, implement IDropInListItemRenderer. Most containers, such as HBox, Canvas, etc. do not implement that interface. If you want to use listData in an itemRenderer that extends a Container you will have to implement IDropInListItemRenderer yourself - I'll cover that in the next article.

Luckily for us, it is a simple process:

<mx:hbox xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.controls.listClasses.IDropInListItemRenderer"></mx:hbox>

We will need to implement the appropriate methods in the itemRenderer's Script tag also:

import mx.controls.listClasses.BaseListData;
 
private var _listData:BaseListData;
private var list:List;
 
public function get listData() : BaseListData
{
	return _listData;
}
public function set listData( value:BaseListData ) : void
{
	_listData = value;
	list = listData.owner as List
	list.addEventListener( ListEvent.CHANGE, onListChange, false, 0, true )
}

In my case, I wanted to listen for changes so that I could set one of the itemRenderer sub-component's properties whenever the list had changed. Now to access the List:

if ( list.selectedItem == data ) doSomeStuff();

Easy as that.

Complex DataGrid filterFunction in Flex/Air

So I need to add robust user controlled filtering options in the application I am working on. This problem has dogged me for a month or two, with my co-workers politely insisting on more and better ways to filter their data. This is completely understandable. When you are staring down a datagrid that is virtually 12 feet long, getting to what you actually want to see is important.

This 2006 article from Bruce Phillips was a big help in the basic concept of multiple input filtering. As is his normal style, it is littered with good references to the source material from his research. This is only considering two filter parameters, however, and I need to consider n parameters, that will probably shift as the needs of the end user grow.

The problem is that each new filtering parameter exponentially increases the complexity of the filterFunction. I can see the pattern, but I haven't quite reached the epiphany that I need to break it down into one of those tight little functions I see real programmers creating (unfortunately, I haven't seen any that address my specific problem).

I thought I'd share my naive, and perhaps confusing filterFunction. It would be great to hear how others approach this problem, and come up with a concise solution.

This function utilizes a TextInput to get text search input from the user. It uses
a series of CheckBoxes for various status condition to generate an array [ 1, 0, 1, 1 ]
to represent their on/off state. It also uses two combo boxes to filter by staff members
as well as clients.

filterFunction:

private function filterCases(item:CaseVO):Boolean
{
	//is the item visible or hidden
	var result:Boolean = false;
	//array of CheckBox.selected property values
       // in handy ones and zeroes. This is returned from a function
       // that takes the actual CheckBoxes as input and gives me this.
	var case_mask:Array = [ 1, 0, 1, 1 ];
        //a couple VOs to verify the selectedItem in the ComboBoxes.
	var client:PersonVO;
	var expert:PersonVO;
	//array iteration variable
	var i:int;
 
	var dateFormat:DateFormatter = new DateFormatter( )
	dateFormat.formatString = 'MM/DD/YY'
 
	//text search
	if ( caseGrid.filter.caseNumInput.text.length &gt; 0 )
	{
		var searchResult:Boolean = ( ( String( '0' + item.case_id.toString() ).search( caseGrid.filter.caseNumInput.text ) &gt;= 0 ) ||
										( item.style.toLowerCase().search( caseGrid.filter.caseNumInput.text.toLowerCase() ) &gt;= 0 )  );
		if( item.description )
		{
			searchResult = searchResult || ( item.description.toLowerCase().search( caseGrid.filter.caseNumInput.text.toLowerCase() ) &gt;= 0 )
		}
 
		if ( item.client_id )
		{
			searchResult = searchResult || ( personProxy.personFromId( item.client_id ).fullName.toLowerCase().search( caseGrid.filter.caseNumInput.text.toLowerCase() ) &gt;= 0 )
		}
 
		if ( item.date_of_accident )
		{
			searchResult = searchResult || ( dateFormat.format(item.date_of_accident).search( caseGrid.filter.caseNumInput.text ) &gt;= 0 )
		}
 
		for ( i = 0; i &lt; case_mask.length; i++ )
		{
			if ( caseGrid.filter.client.selectedItem is PersonVO )
			{
				client = caseGrid.filter.client.selectedItem
 
				//is an expert selected for filtering also?
				if ( caseGrid.filter.expert.selectedItem is PersonVO &amp;&amp; searchResult)
				{
					expert = caseGrid.filter.expert.selectedItem;
					//filter for client, expert, and status
					if ( (case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
							&amp;&amp; item.client_id == client.id
							&amp;&amp; item.expert_id == expert.id &amp;&amp; searchResult  )
						result = true;
				}
				else
				{
					//filter for client and status
					if ( (case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
							&amp;&amp; item.client_id == client.id &amp;&amp; searchResult  )
						result = true;
				}
			}
			else if ( caseGrid.filter.expert.selectedItem is PersonVO )
			{
				expert = caseGrid.filter.expert.selectedItem;
				for ( i = 0; i &lt; case_mask.length; i++ )
				{
					//filter for expert and status
					 if ( (case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
					 		&amp;&amp; item.expert_id == expert.id &amp;&amp; searchResult  )
					 	result = true
				}
 
			}
			else
			{
				//filter for client and status
				if ( (case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
						&amp;&amp; searchResult  )
					result = true;
			}
		}
	}
	//see if a client is selected for filtering
	else if ( caseGrid.filter.client.selectedItem is PersonVO )
	{
		client = caseGrid.filter.client.selectedItem
		for ( i = 0; i &lt; case_mask.length; i++ )
		{
			//is an expert selected for filtering also?
			if ( caseGrid.filter.expert.selectedItem is PersonVO )
			{
				expert = caseGrid.filter.expert.selectedItem;
				//filter for client, expert, and status
				if ( (case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
						&amp;&amp; item.client_id == client.id
						&amp;&amp; item.expert_id == expert.id  )
					result = true;
			}
			else
			{
				//filter for client and status
				if ( (case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
						&amp;&amp; item.client_id == client.id  )
					result = true;
			}
		}
	}
	//client isn't selected, check the expert filter.
	else if ( caseGrid.filter.expert.selectedItem is PersonVO )
	{
		expert = caseGrid.filter.expert.selectedItem;
		for ( i = 0; i &lt; case_mask.length; i++ )
		{
			//filter for expert and status
			 if ( (case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
			 		&amp;&amp; item.expert_id == expert.id  )
			 	result = true
		}
 
	}
	//finally, filter for the status
	else
	{
		for ( i = 0; i &lt; case_mask.length; i++ )
		{
			//filter for status
			if ( case_mask[i] &amp;&amp; item.status == String( i + 1 ) )
				result = true;
		}
	}
 
	return result
}

You can see that I am repeating myself from the top down to the final else statement, cutting the filter parameters down like a layer cake. It works, and is relatively quick on a grid with 1500 or so items. This just screams "REFACTOR ME" every time I see it.

VEsession - Flex photography studio management and client ordering application

My wife saw the application that I am working on at work to manage tasks and immediately asked, "Where's mine?"

21st century honey-do list.

So far, this is what I have created. PureMVC is the underlying framework. The photos are loaded from SlideShowPro Director XML galleries. Unforutately, the most recent version of SSP-D won't let you use it as a service in this way. This older version is has all the functionality I need though, so it isn't an issue. Eventually I will implement functionality to eliminate the need for SSP-D with some gallery management. It will be better to keep it all under one roof.

The backend is Django using pyAMF for communications back and forth. Django elminates the pain of CRUD operations and provides an excellent admin interface for free.

My goal is to open source the application and provide it as a PureMVC/Django example.

UPDATED: This version is a little jacked because I am working on a new version. The demo images are way too big and cause the application to scroll in unsightly ways. The new demo is located here, and uses the same credentials as below.

[Here is the demo]
user: demo_client
pass:demo_client

session_sshot.jpg

[source]

Do to some, uh, laziness on my part, this will only compile with strict mode turned off The new version does not have this problem.