<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3306467612475312611</id><updated>2011-11-27T15:25:07.108-08:00</updated><category term='flex TreeItemRenderer actionscript ListBase List Tree'/><category term='flex mxml actionscript hover reuse'/><category term='flex mxml actionscript code formatting formatter'/><category term='flex TreeItemRenderer adobe'/><category term='anti-pattern memory_leaks arraycollection java'/><category term='transparent selectionColor useRollOver rollovercolor highlight roll highlight tree list'/><title type='text'>the Flexnaut</title><subtitle type='html'>Exploring the Flex universe!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Kelly Davis</name><uri>http://www.blogger.com/profile/18233881593532454986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-2095149003087099794</id><published>2009-10-19T06:49:00.000-07:00</published><updated>2009-12-01T04:57:36.082-08:00</updated><title type='text'>Extensible List Item Renderers</title><content type='html'>For all of list-based components (&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;DataGrid&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;HorizontalList&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Menu&lt;/span&gt;, &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;TileList&lt;/span&gt;, and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt;) you can implement custom item renderers to override the default rendering of data. For simple cases, you can just extend a component which implement&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;IDropInListItemRenderer&lt;/span&gt;.&amp;nbsp;For more complex controls, especially where the item renderers need to have varying heights, I have discovered that this approach becomes complicated. I have often run into layout issues with complex item renderers when used in &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt; components where they have extra space between the renderers or the renderers overlap. This post will present a general approach to resolving these issues by using what I call an Extensible Item Renderer.&lt;br /&gt;&lt;br /&gt;The approach involves first extending the default item renderer class for the particular &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ListBase&lt;/span&gt; component being used. In this post I will show implementations for the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt; components. The following code is for what I call the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ExtensibleListItemRenderer&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;package&lt;br /&gt;{&lt;br /&gt;  import mx.controls.listClasses.ListBase;&lt;br /&gt;  import mx.controls.listClasses.ListItemRenderer;&lt;br /&gt;  import mx.core.IDeferredInstance;&lt;br /&gt;  import mx.core.UIComponent;&lt;br /&gt;  import mx.events.FlexEvent;&lt;br /&gt;&lt;br /&gt;  public class ExtensibleListItemRenderer extends ListItemRenderer&lt;br /&gt;  {&lt;br /&gt;    //We use a deferred instance to cause component instantiation&lt;br /&gt;    //to be deferred until it is needed&lt;br /&gt;    [InstanceType("mx.core.UIComponent")]&lt;br /&gt;    public var contents:IDeferredInstance; &lt;br /&gt;    &lt;br /&gt;    public function ExtensibleListItemRenderer()&lt;br /&gt;    {&lt;br /&gt;      super();&lt;br /&gt;      &lt;br /&gt;      addEventListener(FlexEvent.INITIALIZE, handleInitialize, false, 0, true );&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private function handleInitialize( evt:FlexEvent ):void&lt;br /&gt;    {&lt;br /&gt;      //On initialize, add the custom contents to the renderer&lt;br /&gt;      if ( contents ) addChild( UIComponent(contents.getInstance()) );&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    override protected function createChildren():void&lt;br /&gt;    {&lt;br /&gt;      super.createChildren();&lt;br /&gt;      &lt;br /&gt;      //hide the default label&lt;br /&gt;      label.visible = false;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    override protected function measure():void&lt;br /&gt;    {&lt;br /&gt;      super.measure();&lt;br /&gt;      &lt;br /&gt;      //The height of the renderer is set to the height of the contents&lt;br /&gt;      if ( contents ) measuredHeight = measuredMinHeight = UIComponent(contents.getInstance()).getExplicitOrMeasuredHeight();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void&lt;br /&gt;    {&lt;br /&gt;      super.updateDisplayList( unscaledWidth, unscaledHeight );&lt;br /&gt;      &lt;br /&gt;      if( super.data ) &lt;br /&gt;      {        &lt;br /&gt;        if ( contents )&lt;br /&gt;        {&lt;br /&gt;          //Position the contents using the position of the label&lt;br /&gt;          UIComponent(contents.getInstance()).x = label.x;&lt;br /&gt;          UIComponent(contents.getInstance()).y = label.y;&lt;br /&gt;          &lt;br /&gt;          //TForces the contents to calculate height by setting the width&lt;br /&gt;          UIComponent(contents.getInstance()).width = width - UIComponent(contents.getInstance()).x;&lt;br /&gt;&lt;br /&gt;          //This sets the components actual size to the calculated width &amp;amp; height&lt;br /&gt;          UIComponent(contents.getInstance()).setActualSize( UIComponent(contents.getInstance()).getExplicitOrMeasuredWidth(), UIComponent(contents.getInstance()).getExplicitOrMeasuredHeight() );&lt;br /&gt;&lt;br /&gt;          //This resolves an (apparent) bug in the ListBase component&lt;br /&gt;          //If the calculated height of the renderer doesn't match what gets passed to this &lt;br /&gt;          //method, we need to tell the Tree to re-layout the renderers&lt;br /&gt;          if ( unscaledHeight != measuredHeight &amp;&amp; name != "hiddenItem" )  callLater( ListBase(owner).invalidateList );&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;measure()&lt;/span&gt;, we are setting the height of the renderer based on the height of the contents. In &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;updateDisplayList()&lt;/span&gt;, we position the component, force it to compute its size, and then size it using the computed size. If you do these things your item renderer will &lt;i&gt;mostly&lt;/i&gt; work right, but there seems to be a bug in &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ListBase&lt;/span&gt; when the renderer changes size, it does not re-layout the renderers and they can overlap each other. This is what that looks like:&lt;br /&gt;&lt;script language="JavaScript" type="text/javascript"&gt; swfobject.embedSWF("http://host.planetdavis.com/flexnaut/extensibleitemrenderer/BrokenItemRenderersExample.swf", "flashContent_extenslistrenderer1", "600", "400", "10.0.22.87", "http://host.planetdavis.com/flexnaut/expressInstall.swf", {}, {}, {} );&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="flashContent_extenslistrenderer1"&gt;&lt;b&gt;Unable to initialize flash content&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The last bit of code in &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;updateDisplayList()&lt;/span&gt; fixes this, by detecting that the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;unscaledHeight&lt;/span&gt; passed to the method is different than the calculated height and calling &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;invalidateList&lt;/span&gt; on the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ListBase&lt;/span&gt; component. We need to use &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;callLater()&lt;/span&gt; to make the layout happen on the next render cycle since we are calling it from &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;updateDisplayList()&lt;/span&gt;. The &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ExtensibleTreeItemRenderer&lt;/span&gt; is almost identical to the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt; version, except that it extends the default &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;TreeItemRenderer&lt;/span&gt; to provide the open/close controls:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;package&lt;br /&gt;{&lt;br /&gt;  import mx.controls.listClasses.ListBase;&lt;br /&gt;  import mx.controls.treeClasses.TreeItemRenderer;&lt;br /&gt;  import mx.core.IDeferredInstance;&lt;br /&gt;  import mx.core.UIComponent;&lt;br /&gt;  import mx.events.FlexEvent;&lt;br /&gt;&lt;br /&gt;  public class ExtensibleTreeItemRenderer extends TreeItemRenderer&lt;br /&gt;  {&lt;br /&gt;    //We use a deferred instance to cause component instantiation&lt;br /&gt;    //to be deferred until it is needed&lt;br /&gt;    [InstanceType("mx.core.UIComponent")]&lt;br /&gt;    public var contents:IDeferredInstance;&lt;br /&gt;    &lt;br /&gt;    public function ExtensibleTreeItemRenderer()&lt;br /&gt;    {&lt;br /&gt;      super();&lt;br /&gt;      &lt;br /&gt;      //On initialize, add the custom contents to the renderer&lt;br /&gt;      addEventListener(FlexEvent.INITIALIZE, handleInitialize, false, 0, true );&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private function handleInitialize( evt:FlexEvent ):void&lt;br /&gt;    {&lt;br /&gt;      if ( contents ) addChild( UIComponent(contents.getInstance()) );&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    override protected function createChildren():void&lt;br /&gt;    {&lt;br /&gt;      super.createChildren();&lt;br /&gt;      &lt;br /&gt;      //hide the default label&lt;br /&gt;      label.visible = false;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    override protected function measure():void&lt;br /&gt;    {&lt;br /&gt;      super.measure();&lt;br /&gt;      &lt;br /&gt;      //The height of the renderer is set to the height of the contents&lt;br /&gt;      if ( contents ) measuredHeight = measuredMinHeight = UIComponent(contents.getInstance()).getExplicitOrMeasuredHeight();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void&lt;br /&gt;    {&lt;br /&gt;      super.updateDisplayList( unscaledWidth, unscaledHeight );&lt;br /&gt;      &lt;br /&gt;      if( super.data ) &lt;br /&gt;      {&lt;br /&gt;        if ( contents )&lt;br /&gt;        {&lt;br /&gt;          //Position the contents using the position of the label&lt;br /&gt;          UIComponent(contents.getInstance()).x = label.x;&lt;br /&gt;          UIComponent(contents.getInstance()).y = label.y;&lt;br /&gt;          &lt;br /&gt;          //TForces the contents to calculate height by setting the width&lt;br /&gt;          UIComponent(contents.getInstance()).width = width - UIComponent(contents.getInstance()).x;&lt;br /&gt;&lt;br /&gt;          //This sets the components actual size to the calculated width &amp;amp; height&lt;br /&gt;          UIComponent(contents.getInstance()).setActualSize( UIComponent(contents.getInstance()).getExplicitOrMeasuredWidth(), UIComponent(contents.getInstance()).getExplicitOrMeasuredHeight() );&lt;br /&gt;          &lt;br /&gt;          //This resolves an (apparent) bug in the ListBase component&lt;br /&gt;          //If the calculated height of the renderer doesn't match what gets passed to this &lt;br /&gt;          //method, we need to tell the Tree to re-layout the renderers&lt;br /&gt;          if ( unscaledHeight != measuredHeight &amp;&amp; name != "hiddenItem" )  callLater( ListBase(owner).invalidateList );&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In both of these renderers we use a &lt;a href="http://livedocs.adobe.com/flex/3/html/help.html?content=templating_3.html"&gt;component template&lt;/a&gt; approach to make it simple to extend them using mxml.&lt;br /&gt;&lt;br /&gt;We start by creating a simple item renderer in mxml which extends an &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;HBox&lt;/span&gt; container which I call &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ActorRenderer&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"&amp;gt;&lt;br /&gt;  &amp;lt;mx:VBox&amp;gt;&lt;br /&gt;    &amp;lt;mx:Image id="image" source="{data.image != null ? data.image : 'missing.jpg'}"/&amp;gt;&lt;br /&gt;    &amp;lt;mx:Label id="name_label" fontWeight="bold" text="{data.name}"/&amp;gt;  &lt;br /&gt;  &amp;lt;/mx:VBox&amp;gt;&lt;br /&gt;  &amp;lt;mx:Text htmlText="{data.bio}" width="{width - Math.max( image.width, name_label.width ) - 20}"/&amp;gt;&lt;br /&gt;&amp;lt;/mx:HBox&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The component consists of an image positioned on the left with a caption under it and a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Text&lt;/span&gt; component on the right. For the example I use it display a photo of an actor with their name and biographical information. In order to get the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Text&lt;/span&gt; component to wrap I explicitly set the width to an absolute value calculated from the width of the component.&lt;br /&gt;&lt;br /&gt;I could drop this right into a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt; and it will mostly just work. My experience has been, though, that intermittently the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt; will not update the layout correctly due to the bug mentioned above. To get around it, we just wrap the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ActorRenderer&lt;/span&gt; in the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ExtensibleListItemRenderer&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;ExtensibleListItemRenderer xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml"&amp;gt;&lt;br /&gt;  &amp;lt;contents&amp;gt;&lt;br /&gt;    &amp;lt;ActorRenderer data="{data}"/&amp;gt;&lt;br /&gt;  &amp;lt;/contents&amp;gt;&lt;br /&gt;&amp;lt;/ExtensibleListItemRenderer&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;If we want to use our custom item renderer in a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt;, we wouldn't be able to just drop it directly into the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt; because we would then need to implement the item disclosure controls. We are pretty much forced to extend from the default &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;TreeItemRenderer&lt;/span&gt;. Fortunately, by wrapping it inside of the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;ExtensibleTreeItemRenderer&lt;/span&gt;, it becomes super-simple to put the custom item renderer into a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;ExtensibleTreeItemRenderer xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml"&amp;gt;&lt;br /&gt;  &amp;lt;contents&amp;gt;&lt;br /&gt;    &amp;lt;ActorRenderer data="{data}"/&amp;gt;&lt;br /&gt;  &amp;lt;/contents&amp;gt;&lt;br /&gt;&amp;lt;/ExtensibleTreeItemRenderer&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Here is the code for the example &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Application&lt;/span&gt; which displays the same set of data in a &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"&amp;gt;&lt;br /&gt;  &amp;lt;mx:Script&amp;gt;&lt;br /&gt;    &amp;lt;![CDATA[    &lt;br /&gt;    [Bindable] private var actors:Array = [ { name:'Leonard Nimoy', image:'nimoy.jpg', bio:'Leonard Simon Nimoy (pronounced /ˈniːmɔɪ/; born March 26, 1931) is an American actor, film director, poet, musician and photographer. He is famous for playing the character of Spock on the original Star Trek series, and he reprised the role in various movie and television sequels.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;b&amp;gt;Source:&amp;lt;/b&amp;gt; wikipedia.org',&lt;br /&gt;                                              children : [ { name:'Adam Nimoy', image:null, bio:'Adam B. Nimoy (born August 9, 1956) is an American television director. Nimoy is the son of actor Leonard Nimoy and his first wife, actress Sandra Zober.' } ] },&lt;br /&gt;                                            { name:'William Shatner', image:'shatner.jpg', bio:'William Alan Shatner (born March 22, 1931)[1] is a Canadian actor and novelist. He gained worldwide fame and became a cultural icon for his portrayal of Captain James T. Kirk, captain of the starship USS Enterprise, in the television series Star Trek from 1966 to 1969, Star Trek: The Animated Series and in seven of the subsequent Star Trek feature films. He has written a series of books chronicling his experiences playing Captain Kirk and being a part of Star Trek as well as several co-written novels set in the Star Trek universe. He has also authored a series of science fiction novels called TekWar that were adapted for television.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;b&amp;gt;Source:&amp;lt;/b&amp;gt; wikipedia.org' },&lt;br /&gt;                                            { name:'DeForest Kelley', image:'kelley.jpg', bio:'Jackson DeForest Kelley (January 20, 1920 – June 11, 1999) was an American actor known for his iconic role Dr. Leonard "Bones" McCoy of the USS Enterprise in the television and film series Star Trek.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&amp;lt;b&amp;gt;Source:&amp;lt;/b&amp;gt; wikipedia.org' } ];&lt;br /&gt;    ]]&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Script&amp;gt;&lt;br /&gt;  &amp;lt;mx:HBox width="100%" height="100%" horizontalGap="5" minWidth="0" minHeight="0"&amp;gt;&lt;br /&gt;    &amp;lt;mx:Panel title="Tree" width="100%" height="100%"&amp;gt;&lt;br /&gt;      &amp;lt;mx:Tree minHeight="0" minWidth="0" variableRowHeight="true" itemRenderer="ActorTreeItemRenderer" dataProvider="{actors}" width="100%" height="100%"&lt;br /&gt;         folderClosedIcon="{null}" folderOpenIcon="{null}" defaultLeafIcon="{null}"/&amp;gt;      &lt;br /&gt;    &amp;lt;/mx:Panel&amp;gt;&lt;br /&gt;    &amp;lt;mx:Panel title="List" width="100%" height="100%"&amp;gt;&lt;br /&gt;      &amp;lt;mx:List minHeight="0" minWidth="0" variableRowHeight="true" itemRenderer="ActorListItemRenderer" dataProvider="{actors}" width="100%" height="100%"/&amp;gt;&lt;br /&gt;    &amp;lt;/mx:Panel&amp;gt;&lt;br /&gt;  &amp;lt;/mx:HBox&amp;gt;&lt;br /&gt;&amp;lt;/mx:Application&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;We populate the data provider with some example data, set &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;variableRowHeight='true'&lt;/span&gt; for the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt; &amp;amp; &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;List&lt;/span&gt;, and disable the icons on the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;Tree&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Here is the demo:&lt;br /&gt;&lt;script language="JavaScript" type="text/javascript"&gt; swfobject.embedSWF("http://host.planetdavis.com/flexnaut/extensibleitemrenderer/ExtensibleItemRenderersExample.swf", "flashContent_extenslistrenderer2", "600", "400", "10.0.22.87", "http://host.planetdavis.com/flexnaut/expressInstall.swf", {}, {}, {} );&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="flashContent_extenslistrenderer2"&gt;&lt;b&gt;Unable to initialize flash content&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Source is hosted on &lt;a href="http://code.google.com/p/flexnaut-examples/source/browse/#svn/trunk/ExtensibleItemRendererExample%3Fstate%3Dclosed"&gt;google code&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-2095149003087099794?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/2095149003087099794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=2095149003087099794' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/2095149003087099794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/2095149003087099794'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2009/10/extensible-list-item-renderers.html' title='Extensible List Item Renderers'/><author><name>Kelly Davis</name><uri>http://www.blogger.com/profile/18233881593532454986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-4525928465299850697</id><published>2009-10-16T06:40:00.000-07:00</published><updated>2009-12-01T04:55:45.648-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex TreeItemRenderer actionscript ListBase List Tree'/><title type='text'>New &amp; Improved TreeItemRenderer Example</title><content type='html'>I have written two posts (&lt;a href="http://flexnaut.blogspot.com/2007/11/adding-mxcontrolstext-component-to.html"&gt;here&lt;/a&gt; and &lt;a href="http://flexnaut.blogspot.com/2009/04/more-itemrenderer-woes.html"&gt;here&lt;/a&gt;) on creating variable size item renderers for List based components that size correctly. The &lt;a href="http://host.planetdavis.com/googlepages/TreeRendererExample.html"&gt;example&lt;/a&gt; for the TreeItemRenderer mostly works, but still has some issues that have been plaguing me for a while. I decided to spend some time trying to figure out what the problem really is and made significant progress that I wanted to share.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;TreeRenderer Example Version 2&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I have made some changes to the original TreeRendererExample that significantly improve its behavior. The example code is hosted on the Flexnaut googlecode &lt;a href="http://code.google.com/p/flexnaut-examples/"&gt;site&lt;/a&gt; under the TreeRendererExample2 &lt;a href="http://code.google.com/p/flexnaut-examples/source/browse/#svn/trunk/TreeRendererExample2"&gt;project&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Enhancement 1&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The original custom renderer was a lot more complicated than it needed to be. I was adding a resize event listener to the tree (for each renderer) that set the Text component's width/height to NaN. The measure() override looked like this:&lt;br /&gt;&lt;pre&gt;override protected function measure():void&lt;br /&gt;  {&lt;br /&gt;    super.measure();&lt;br /&gt;    &lt;br /&gt;    description.width = explicitWidth - super.label.x;&lt;br /&gt;    measuredHeight += description.measuredHeight;&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;Then in updateDisplayList I would set the height of the Text component to it's measuredHeight. In the new version, I don't set any resize listener on the Tree component and I don't do set any properties on the Text component. I just use the Text component's size to calculate the size of the renderer:&lt;br /&gt;&lt;pre&gt;override protected function measure():void&lt;br /&gt;  {&lt;br /&gt;    super.measure();&lt;br /&gt;    &lt;br /&gt;    measuredHeight = measuredMinHeight = measuredHeight description.getExplicitOrMeasuredHeight();&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;Then, in updateDisplayList, I do the following to size the Text component:&lt;br /&gt;&lt;pre&gt;//This forces the Text component to calculate it's height&lt;br /&gt;  description.width = width - description.x;&lt;br /&gt;&lt;br /&gt;  //This sets the Text component to the calculated width &amp; height&lt;br /&gt;  description.setActualSize( description.getExplicitOrMeasuredWidth(), description.getExplicitOrMeasuredHeight() );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;With these changes, everything &lt;i&gt;almost&lt;/i&gt; works correctly. The item renderers all size correctly, but the problem is that the renderers seem to overlap each other now. This condition can be detected in the renderer updateDisplayList by comparing the unscaledHeight parameter to the measuredHeight parameter. It looks like there is a bug in &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/controls/listClasses/ListBase.html"&gt;ListBase&lt;/a&gt; which causes it to not detect changes in the height of the renderers. Fortunately, the fix is simply to add this line to updateDisplayList:&lt;br /&gt;&lt;pre&gt;if ( unscaledHeight != measuredHeight ) callLater( ListBase(owner).invalidateList );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This causes the protected property itemsSizeChanged on ListBase to be set to true, and invalidates the display list. The callLater is necessary, because updateDisplayList can't be called while the current updateDisplayList is running.&lt;br /&gt;&lt;br /&gt;With these changes, we now have a much simpler and functional TreeItemRenderer with a Text component. The following demonstrates the improved behavior:&lt;br /&gt;&lt;br /&gt;&lt;script language="JavaScript" type="text/javascript"&gt;  swfobject.embedSWF("http://host.planetdavis.com/googlepages/TreeRendererExample.swf", "flashContent_newimprovtreerend1", "400", "400", "10.0.22.87", "http://host.planetdavis.com/flexnaut/expressInstall.swf", {}, {}, {} );  swfobject.embedSWF("http://host.planetdavis.com/flexnaut/TreeRendererExample2.swf", "flashContent_newimprovtreerend2", "400", "400", "10.0.22.87", "http://host.planetdavis.com/flexnaut/expressInstall.swf", {}, {}, {} );&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="flashContent_newimprovtreerend1"&gt;&lt;b&gt;Unable to initialize flash content&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;i&gt;Original Broken Version - Scroll and click around to see broken behavior&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="flashContent_newimprovtreerend2"&gt;&lt;b&gt;Unable to initialize flash content&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;i&gt;New Version - Scroll and click works as expected&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Check out the &lt;a href="http://code.google.com/p/flexnaut-examples/source/browse/#svn/trunk/TreeRendererExample2"&gt;source&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-4525928465299850697?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/4525928465299850697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=4525928465299850697' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/4525928465299850697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/4525928465299850697'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2009/10/new-improved-treeitemrenderer-example.html' title='New &amp; Improved TreeItemRenderer Example'/><author><name>Kelly Davis</name><uri>http://www.blogger.com/profile/18233881593532454986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-1951279955010411147</id><published>2009-04-14T07:22:00.000-07:00</published><updated>2009-04-15T06:54:25.078-07:00</updated><title type='text'>More ItemRenderer Woes</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Update:&lt;/span&gt; Ok, I am officially frustrated. It seemed like adding the validateNow() was working, but as I ran through more test cases, it definitely wasn't. The final solution that seems to work consistently is to NOT use a percentWidth on the Text component. You can bind the width of the Text component to the parent's width, and you get the benefit of setting an explicitWidth on the Text component which fixes the incorrect sizing problems and it fits properly in the parent container.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I have been struggling recently with getting a custom ItemRenderer in a List to display correctly. It basically consists of a small Image component used as an icon, a Text field used for a title to the right of the icon, and a Text field used as a description below the title. I arranged these on a Canvas and sized them using percent widths. When I scrolled the list, the sizes of the renderers would vary dramatically, sometimes only displaying the title, sometimes displaying with too much whitespace. I found what seems to be a solution on Kalen Gibbons &lt;a href="http://www.kalengibbons.com/blog/index.php/2008/12/update-solution-to-disappearing-data-in-your-itemrenderer2/"&gt;blog&lt;/a&gt;. Basically, you need to get the Text fields validated before the size of the renderer is calculated. So, for each Text component, I am calling validateNow() on it in my commitProperties() method. This is a little different than Kalen's solution. When I called validateNow() on the renderer and not on the Text components, it did not fix the problem. &lt;br /&gt;&lt;br /&gt;As an aside, in my attempts at fixing this issue, I re-implemented the renderer by extending mx.controls.listClasses.ListItemRenderer. When I did this, the Text components didn't display at all. The reason for this isn't totally clear, but I did discover part of the cause. The Text component, when you either set left/right constraints or a percentWidth (and don't set a height) the Text component does a special two pass calculation of the height. On the first pass the component will bypass measure() and wait until updateDisplayList() is called to get it's unscaledWidth. It then calls invalidateSize() which causes measure() to get called again and then uses the width obtained from updateDisplayList to calculate the height of the component. The problem is that when you add a Text component to the ListItemRenderer and specify the percent width, the updateDisplayList() for the Text component always gets called with a width = 0. I don't know why this is happening, but because of this it causes the 2 pass calculation to fail. So basically, don't use a Text component in ListItemRenderer or you will need to set it's size explicitly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-1951279955010411147?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/1951279955010411147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=1951279955010411147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/1951279955010411147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/1951279955010411147'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2009/04/more-itemrenderer-woes.html' title='More ItemRenderer Woes'/><author><name>Kelly Davis</name><uri>http://www.blogger.com/profile/18233881593532454986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-2712813203617320414</id><published>2008-07-11T10:28:00.000-07:00</published><updated>2008-07-11T10:43:33.224-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='transparent selectionColor useRollOver rollovercolor highlight roll highlight tree list'/><title type='text'>Transparent List</title><content type='html'>I often run into situations where I want to use a &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/controls/List.html"&gt;List&lt;/a&gt; but I want to have the rollOver and selection highlights disabled. This often occurs when I want a completely transparent list. There is a style which controls whether the rollOver highlight is displayed, called useRollOver, but it doesn't disable the selection highlight. In addition, even though Tree extends List, the useRollOver style has no effect for the &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/controls/Tree.html"&gt;Tree&lt;/a&gt; component. Fortunately, due to a good api design, there is a simple solution. You just create a new component class which extends List:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package&lt;br /&gt;{&lt;br /&gt;  import mx.controls.List;&lt;br /&gt;  import mx.controls.listClasses.IListItemRenderer;&lt;br /&gt;  &lt;br /&gt;  public class TransparentList extends List&lt;br /&gt;  {&lt;br /&gt;    override protected function createChildren():void&lt;br /&gt;    {&lt;br /&gt;      super.createChildren();&lt;br /&gt;      &lt;br /&gt;      setStyle( "backgroundAlpha", "0" );&lt;br /&gt;      setStyle( "borderStyle", "none" );&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    override protected function drawItem( item:IListItemRenderer, &lt;br /&gt;                                          selected:Boolean=false, &lt;br /&gt;                                          highlighted:Boolean=false, &lt;br /&gt;                                          caret:Boolean=false, &lt;br /&gt;                                          transition:Boolean=false):void&lt;br /&gt;    {&lt;br /&gt;      super.drawItem(item, false, false, caret, transition);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In createChildren() set the border and background alpha styles. Then override the protected drawItem() function and always pass false to the selected and highlighted parameters of the parent function. You can do the same thing for the &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/controls/Tree.html"&gt;Tree&lt;/a&gt; component.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-2712813203617320414?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/2712813203617320414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=2712813203617320414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/2712813203617320414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/2712813203617320414'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2008/07/transparent-list.html' title='Transparent List'/><author><name>Kelly Davis</name><uri>http://www.blogger.com/profile/18233881593532454986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-6005779431137038617</id><published>2008-06-18T12:36:00.000-07:00</published><updated>2009-12-01T04:58:39.073-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex mxml actionscript hover reuse'/><title type='text'>A Reusable Flex Hover Details Window</title><content type='html'>&lt;b&gt;Update:&lt;/b&gt; The source code for this is now hosted on &lt;a href="http://code.google.com/p/flexnaut-examples/source/browse/#svn/trunk/HoverDetailDemo"&gt;googlecode&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;An increasingly common feature in rich web interfaces is when hovering over some piece of information, a window pops up providing more details about that item. An example of this is in the Gmail interface. If you hover over a name in your chat list, you get a popup which displays more details about the person, such as their name, photo and email address. In this short tutorial, I will go over how to do something similar in Flex in a reusable way.&lt;br /&gt;&lt;br /&gt;First we start with our simple demo Application.&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;  &amp;lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()"&amp;gt;&lt;br /&gt;  &amp;lt;mx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;    import mx.collections.ArrayCollection;&lt;br /&gt;    [Bindable] &lt;br /&gt;    private var dataProvider:ArrayCollection = &lt;br /&gt;                  new ArrayCollection( [ { name: "Leonard Nimoy", image: "nimoy.jpg" }, &lt;br /&gt;                                         { name: "William Shatner", image: "shatner.jpg" }, &lt;br /&gt;                                         { name: "Deforest Kelley", image: "kelley.jpg" },] );&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Script&amp;gt;&lt;br /&gt;  &amp;lt;mx:Panel title="Famous Actors: Hover Over For More Details"&amp;gt;&lt;br /&gt;    &amp;lt;mx:List dataProvider="{dataProvider}" &lt;br /&gt;                labelField="name" &lt;br /&gt;                itemRenderer="PersonRenderer" &lt;br /&gt;                width="100%"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Panel&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In this case we are just displaying a set of names in a &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/controls/List.html" target="_blank"&gt;List&lt;/a&gt; component. We create a dataProvider for the list which is a set of persons where each person has a name and image property. We specify the labelField for the List as the name property of a person. Next we create a simple ItemRenderer called PersonRenderer which is used by the List component to display the items.&lt;br /&gt;&lt;pre&gt;&amp;lt;mx:Label xmlns:mx="http://www.adobe.com/2006/mxml"&amp;gt;&lt;br /&gt;  &amp;lt;mx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;    import mx.binding.utils.BindingUtils;&lt;br /&gt;&lt;br /&gt;    override protected function createChildren():void&lt;br /&gt;    {&lt;br /&gt;      super.createChildren();&lt;br /&gt;&lt;br /&gt;      //Instance the ImageHover object and attach it to&lt;br /&gt;      //the item renderer&lt;br /&gt;      var imageHover:ImageHover = new ImageHover();&lt;br /&gt;      imageHover.parentComponent = this;&lt;br /&gt;&lt;br /&gt;      //Create a binding between the image property of the data object&lt;br /&gt;      //and the source property of the ImageHover so it knows which image to display&lt;br /&gt;      BindingUtils.bindProperty( imageHover, "source", this, ["data","image"] );&lt;br /&gt;&lt;br /&gt;      //Create a binding between the name property of the data object&lt;br /&gt;      //and the title property of the ImageHover so it knows which title to display&lt;br /&gt;      BindingUtils.bindProperty( imageHover, "title", this, ["data","name"] );        &lt;br /&gt;    }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Script&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Label&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This renderer is based on the &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/controls/Label.html" target="_blank"&gt;Label&lt;/a&gt; component. Since it implements &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/core/IDataRenderer.html" target="_blank"&gt;IDataRenderer&lt;/a&gt; we can use it almost 'as is' in the List. We  override createChildren() where we attach our ImageHover component to the renderer. This component is what actually displays the details window when we hover over the renderer. There are only three properties we set on this component, the &lt;span style="font-weight:bold;"&gt;title&lt;/span&gt; and the &lt;span style="font-weight:bold;"&gt;source&lt;/span&gt;, which we bind to the name and image properties of our person, and the &lt;span style="font-weight:bold;"&gt;parentComponent&lt;/span&gt; which is the component that we want the hover detail window to appear over. Let's look at the ImageHover component to see how it works:&lt;br /&gt;&lt;pre&gt;&amp;lt;HoverComponent xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml"&amp;gt;&lt;br /&gt;  &amp;lt;!-- Simple extension of the HoverComponent to display&lt;br /&gt;    an image specified by the source property with a title --&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;mx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;    [Bindable] public var source:String;&lt;br /&gt;    [Bindable] public var title:String;&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;mx:Panel paddingBottom="5"&lt;br /&gt;               paddingLeft="5"&lt;br /&gt;               paddingTop="5"&lt;br /&gt;               paddingRight="5"&lt;br /&gt;               backgroundAlpha="1"&lt;br /&gt;               title="{title}"&amp;gt;&lt;br /&gt;    &amp;lt;mx:Image id="image" source="{source}"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:Panel&amp;gt;&lt;br /&gt;  &amp;lt;/HoverComponent&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This component is very simple and only consists of a &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/containers/Panel.html" target="_blank"&gt;Panel&lt;/a&gt; with a title and an &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/controls/Image.html" target="_blank"&gt;Image&lt;/a&gt; component inside the Panel. The key thing is that it extends HoverComponent, which provides the hover capabilities. You can modify the ImageHover to do just about anything as long as it extends the HoverComponent. So, finally let's look at the HoverComponent class:&lt;br /&gt;&lt;pre&gt;package&lt;br /&gt;  {&lt;br /&gt;    import flash.events.MouseEvent;&lt;br /&gt;    import flash.events.TimerEvent;&lt;br /&gt;    import flash.geom.Point;&lt;br /&gt;    import flash.utils.Timer;&lt;br /&gt;&lt;br /&gt;    import mx.containers.Canvas;&lt;br /&gt;    import mx.core.UIComponent;&lt;br /&gt;    import mx.managers.PopUpManager;&lt;br /&gt;&lt;br /&gt;    public class HoverComponent extends Canvas&lt;br /&gt;    {&lt;br /&gt;      public var delay:Number = 1000;&lt;br /&gt;      private var _parentComponent:UIComponent;&lt;br /&gt;&lt;br /&gt;      private var timer:Timer;&lt;br /&gt;      private var popped:Boolean = false;&lt;br /&gt;&lt;br /&gt;      public function set parentComponent( parentComponent:UIComponent ):void&lt;br /&gt;      {&lt;br /&gt;        _parentComponent = parentComponent;&lt;br /&gt;        if ( _parentComponent != null )&lt;br /&gt;        {&lt;br /&gt;          var thisComponent:UIComponent = this;&lt;br /&gt;&lt;br /&gt;          //Detects mouse overs and starts a timer to display the hover&lt;br /&gt;          parentComponent.addEventListener( MouseEvent.MOUSE_OVER, function( evt:MouseEvent ):void&lt;br /&gt;          {&lt;br /&gt;            //Initialize the timer to trigger one time after delay millis&lt;br /&gt;            timer = new Timer( delay, 1 );&lt;br /&gt;&lt;br /&gt;            //Wait for the timer to complete&lt;br /&gt;            timer.addEventListener(TimerEvent.TIMER_COMPLETE, function( tevt:TimerEvent ):void&lt;br /&gt;            {&lt;br /&gt;              //move to a position relative to the mouse cursor&lt;br /&gt;              thisComponent.move( evt.stageX + 20, evt.stageY + 20 );&lt;br /&gt;&lt;br /&gt;              //Popup the hover component&lt;br /&gt;              PopUpManager.addPopUp( thisComponent, parentComponent );&lt;br /&gt;&lt;br /&gt;              //Set a flag so we know that a popup actually occurred&lt;br /&gt;              popped = true;&lt;br /&gt;            });&lt;br /&gt;&lt;br /&gt;            //start the timer&lt;br /&gt;            timer.start();&lt;br /&gt;          });&lt;br /&gt;&lt;br /&gt;          parentComponent.addEventListener( MouseEvent.MOUSE_OUT, function( evt:MouseEvent ):void&lt;br /&gt;          {&lt;br /&gt;            //If the timer exists we stop it&lt;br /&gt;            if ( timer )&lt;br /&gt;            {&lt;br /&gt;              timer.stop();&lt;br /&gt;              timer = null;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            //If we popped up, remove the popup&lt;br /&gt;            if ( popped )&lt;br /&gt;            {&lt;br /&gt;              PopUpManager.removePopUp( thisComponent );&lt;br /&gt;              popped = false;&lt;br /&gt;            }&lt;br /&gt;          });&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      public function get parentComponent():UIComponent&lt;br /&gt;      {&lt;br /&gt;        return _parentComponent;&lt;br /&gt;      }  &lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The HoverComponent class extends the &lt;a href="http://livedocs.adobe.com/flex/3/langref/mx/containers/Canvas.html" target="_blank"&gt;Canvas&lt;/a&gt; component. It adds a &lt;span style="font-weight:bold;"&gt;delay&lt;/span&gt; property, which is the amount of time in milliseconds that you need to hover over an item before the window displays. It also adds the &lt;span style="font-weight:bold;"&gt;parentComponent&lt;/span&gt; property which is the item that you want the hover to appear over. The default delay is 1 second. When you set the parentComponent, a mouseOver and mouseOut listener get added to the parentComponent. When you mouseOver, a timer gets started. When the timer completes, the hover component gets positioned and uses PopUpManager to display itself. When you mouseOut, the timer will get cancelled if it is not completed, and the hover window is removed, if it was displayed.&lt;br /&gt;&lt;br /&gt;So with the HoverComponent class we have a simple and re-usable way to create custom hover detail windows. Just create your window by extending the HoverComponent and attach it to the component you want it to appear over like we did in the PersonRenderer.&lt;br /&gt;&lt;br /&gt;Here is a &lt;a href="http://host.planetdavis.com/googlepages/HoverDetailDemo.html" target="_blank"&gt;demo&lt;/a&gt; and the &lt;a href="http://host.planetdavis.com/googlepages/HoverDetailDemo.zip"&gt;source&lt;/a&gt; code.&lt;br /&gt;&lt;br /&gt;&lt;script language="JavaScript" type="text/javascript"&gt;  swfobject.embedSWF("http://host.planetdavis.com/googlepages/HoverDetailDemo.swf", "flashContent_hover", "400", "400", "10.0.22.87", "http://host.planetdavis.com/flexnaut/expressInstall.swf", {}, {}, {} );&lt;/script&gt;&lt;br /&gt;&lt;b&gt;Demo:&lt;/b&gt;&lt;br /&gt;&lt;div id="flashContent_hover"&gt;&lt;b&gt;Unable to initialize flash content&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-6005779431137038617?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/6005779431137038617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=6005779431137038617' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/6005779431137038617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/6005779431137038617'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2008/06/how-to-create-hover-details-window-in.html' title='A Reusable Flex Hover Details Window'/><author><name>Kelly Davis</name><uri>http://www.blogger.com/profile/18233881593532454986</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-443302570600817054</id><published>2008-03-21T07:25:00.000-07:00</published><updated>2008-03-21T07:52:07.286-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti-pattern memory_leaks arraycollection java'/><title type='text'>Object Leaks &amp; The Dangers of ArrayCollection.removeItemAt</title><content type='html'>I have been using the new &lt;a href="http://labs.adobe.com/wiki/index.php/Flex_3:Feature_Introductions:_Performance_and_Memory_Profiling"&gt;Profiler&lt;/a&gt; in &lt;a href="http://www.adobe.com/products/flex/"&gt;Flex Builder 3&lt;/a&gt; to fix some performance issues in my flex apps and discovered a bit of an anti-pattern in several places in my code. I like to use object pools to re-use my custom renderer objects. To do this I first have my renderers implement the &lt;a href="http://livedocs.adobe.com/flex/201/langref/mx/core/IFactory.html"&gt;IFactory&lt;/a&gt; interface. Which is basically just adding this function:&lt;br /&gt;&lt;pre&gt;public function newInstance():*&lt;/pre&gt;In the class that I will be using the renderers, I create some code to manage the pool of renderers, which is basically just two methods:&lt;br /&gt;&lt;pre&gt;protected function getRenderer():MyRenderer&lt;br /&gt;protected function freeRenderers():void&lt;/pre&gt;Calling getRenderer() will check the pool of "free" renderers and return one if available, or if not, create a new one and add it tool the pool of renderers currently in use. The freeRenderers() method just takes all of the in-use renderers and moves them to the free pool. The discovered my anti-pattern here in the freeRenderers() method:&lt;br /&gt;&lt;pre&gt;for ( var I:int i = 0; i &lt; usedRenderers.length; i++ )&lt;br /&gt;{&lt;br /&gt;  freeRenderers.addItem( usedRenderers.removeItemAt(i) );&lt;br /&gt;}&lt;/pre&gt;This code will fail to copy all of the used renderers from the in-use pool to the free pool. The reason is that as we remove items, we are changing the length of the collection that we are indexing across. The proper way to do this is:&lt;br /&gt;&lt;pre&gt;while ( usedRenderers.length &gt; 0 )&lt;br /&gt;{&lt;br /&gt;  freeRenderers.addItem( usedRenderers.removeItemAt( 0 ) );&lt;br /&gt;}&lt;/pre&gt;There is another variation of this issue which needs to be handled differently. If you are only wanting to transfer some of the items out of the collection, you might do something like this:&lt;br /&gt;&lt;pre&gt;var key:String = "foo";&lt;br /&gt;for ( var i:int i = 0; i &lt; collection.length; i++ )&lt;br /&gt;{&lt;br /&gt;  if ( MyObject(collection.getItemAt( i )).id == key )&lt;br /&gt;    collection.removeItemAt( i );&lt;br /&gt;}&lt;/pre&gt;Doing this will cause problems similar to the first example. This is basically like a &lt;a href="http://java.sun.com/j2se/1.3/docs/api/java/util/ConcurrentModificationException.html"&gt;ConcurrentModificationException&lt;/a&gt; that you might get in Java. The problem is that in Flex's ArrayCollection you don't get any exception when you do this, so it is real easy to think you are doing the right thing when you are not. Here is one possible fix for this:&lt;br /&gt;&lt;pre&gt;var key:String = "foo";&lt;br /&gt;var removes:ArrayCollection = new ArrayCollection();&lt;br /&gt;for ( var i:int = 0; i &lt; collection.length; i++ )&lt;br /&gt;{&lt;br /&gt;  if ( MyObject(collection.getItemAt( i )).id == key )&lt;br /&gt;    removes.addItem( collection.getItemAt( i ) );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;for ( i = 0; i &lt; removes.length; i++ )&lt;br /&gt;{&lt;br /&gt;  collection.removeItemAt( collection.getItemIndex( removes.getItemAt( i ) ) );&lt;br /&gt;} &lt;/pre&gt;This is pretty simple but it is definitely something worth remembering&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-443302570600817054?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/443302570600817054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=443302570600817054' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/443302570600817054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/443302570600817054'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2008/03/object-leaks-dangers-of.html' title='Object Leaks &amp; The Dangers of ArrayCollection.removeItemAt'/><author><name>Hi!  I'm Shanna.</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_B3vAh-miqTQ/TTYoKu3snzI/AAAAAAAABFs/LmjW6b5hvqc/S220/DSC_5518.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-7468882692166116204</id><published>2008-02-28T14:47:00.001-08:00</published><updated>2008-05-22T04:36:15.771-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex mxml actionscript code formatting formatter'/><title type='text'>What's Missing In Flex Builder 3</title><content type='html'>I have been using a beta version of the new Flex Builder 3 for a while now. I am pretty happy with the new features added to it, but there is something missing that I would really expect to be there. There is no code formatting functionality for the ActionScript 3 or MXML editors. For a $249 IDE plugin, I am amazed by this.&lt;br /&gt;&lt;br /&gt;Reformatting your code by hand is an extremely tedious and error prone task. It also seems that with FB I am especially prone to writing badly  formatted code. I did a google search for ActionScript code formatter and basically came up with very little. There is a PHP cut and paste formatter hosted on &lt;a href="http://www.senocular.com/pub/kirupa/formatcode/"&gt;Senocular&lt;/a&gt;, but it isn't really usable for reformatting code in the IDE. I did learn today that IntelliJ IDEA has just added Flex &lt;a href="http://www.jetbrains.com/idea/features/javascript_editor.html"&gt;functionality&lt;/a&gt;, including &lt;a href="http://www.jetbrains.com/idea/features/javascript_editor.html#link12"&gt;code formatting&lt;/a&gt; and a nice set of refactorings (Copy, Move, Safe delete, Introduce variable, Migrate). I think I will have to check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-7468882692166116204?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/7468882692166116204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=7468882692166116204' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/7468882692166116204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/7468882692166116204'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2008/02/whats-missing-in-flex-builder-3.html' title='What&apos;s Missing In Flex Builder 3'/><author><name>Hi!  I'm Shanna.</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_B3vAh-miqTQ/TTYoKu3snzI/AAAAAAAABFs/LmjW6b5hvqc/S220/DSC_5518.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3306467612475312611.post-1112949256394180959</id><published>2007-11-19T04:53:00.000-08:00</published><updated>2009-10-16T07:02:49.074-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex TreeItemRenderer adobe'/><title type='text'>Adding the mx.controls.Text component to a custom TreeItemRenderer</title><content type='html'>&lt;br&gt;&lt;br&gt;&lt;b&gt;Update:&lt;/b&gt; This &lt;a href="http://flexnaut.blogspot.com/2009/10/new-improved-treeitemrenderer-example.html"&gt;post&lt;/a&gt; has a much improved example of how to do this properly. I highly recommend going there now. :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I recently had to build a custom TreeItemRenderer which displayed an icon and a label. I found Mac Martine's &lt;a href="http://www.macmartine.com/blog/2006/04/extending_treeitemrenderer_to.html"&gt;example&lt;/a&gt; to be quite helpful in implementing it successfully. More recently I needed to extend this work to add a &lt;a href="http://livedocs.adobe.com/flex/201/langref/mx/controls/Text.html" target="_blank"&gt;mx.controls.Text&lt;/a&gt; component to the renderer, to display a variable length description under the label. I initially believed that this would be a simple task, but it turns out to be quite a challenge.&lt;br /&gt;&lt;br /&gt;My first strategy to accomplish this was to implement a new TreeItemRenderer from scratch without extending &lt;a href="http://livedocs.adobe.com/flex/201/langref/mx/controls/treeClasses/TreeItemRenderer.html" target="_blank"&gt;mx.controls.treeClasses.TreeItemRenderer&lt;/a&gt;. I wanted to do this because I believed I could very quickly lay it out in MXML. The problem is, that the default TreeItemRenderer implements the expand/collapse controls for the item and does so by accessing a property (isOpening) and method (dispatchTreeEvent) which are both scoped mx_internal. So without some extra gymnastics, I am better off extending the default TreeItemRenderer.&lt;br /&gt;&lt;br /&gt;I reverted back to my modified implementation of Mac Martine's custom renderer. I had to modify the existing updateDisplayList() method override and implement the measure() method override. In updateDisplayList(), I basically just need to position the Text component under the existing Label component. In measure(), I need to make the renderer taller to accomodate the height of the additional Text component. The problem is that the Text component renderering code is complex and a seemingly inconsistent in how it behaves. If you don't set the width and height properties in just the right order, it won't render correctly. After several &lt;span style="font-style:italic;"&gt;hours&lt;/span&gt; of trial and error, I was able to get it to behave properly. Here is basically what I did.&lt;br /&gt;&lt;br /&gt;1) In measure(), I set the width property of the Text component to the width of the item renderer less the x position of the label. Then I read the measuredHeight property of the Text component which is calculated based on the length of the text/htmlText property of the component and the explicit width of the component, and I add that to the measuredHeight of my renderer.&lt;br /&gt;&lt;br /&gt;2) In updateDisplayList, after positioning all of my components, I explicitly set the height of the Text component to the measuredHeight property of the Text component. This seems like an odd thing to have to do, but if I don't do it, the text doesn't display at all.&lt;br /&gt;&lt;br /&gt;If you do these things, your Text will display and your renderer will be sized properly. There is one other important thing to do if your renderers are going to be different sizes, which is to set the variableRowHeight property on the Tree to true.&lt;br /&gt;&lt;br /&gt;Additionally, if your Tree component will need to be resizable, there is something else that needs to be done to get the Text component to resize correctly. When the width and height of a Text component are both explicitly set, the component doesn't call measure() anymore, so it won't resize. To fix this, we need to set the explicitWidth &amp;amp; explicitHeight on the Text component to NaN. So we add a listener to the parent Tree to listen for ResizeEvents, and when they occur, set the explicitHeight and explicitWidth to NaN. This will then cause Text component to resize properly.&lt;br /&gt;&lt;br /&gt;I have created an &lt;a href="http://host.planetdavis.com/googlepages/TreeRendererExample.html" target="_blank"&gt;example&lt;/a&gt; application with &lt;a href="http://host.planetdavis.com/googlepages/TreeRendererExample.zip"&gt;source&lt;/a&gt; code (right click the example and select View Source). It consists of an MXML application and a custom renderer. Hopefully this will save you so some time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3306467612475312611-1112949256394180959?l=flexnaut.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://flexnaut.blogspot.com/feeds/1112949256394180959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3306467612475312611&amp;postID=1112949256394180959' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/1112949256394180959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3306467612475312611/posts/default/1112949256394180959'/><link rel='alternate' type='text/html' href='http://flexnaut.blogspot.com/2007/11/adding-mxcontrolstext-component-to.html' title='Adding the mx.controls.Text component to a custom TreeItemRenderer'/><author><name>Hi!  I'm Shanna.</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_B3vAh-miqTQ/TTYoKu3snzI/AAAAAAAABFs/LmjW6b5hvqc/S220/DSC_5518.JPG'/></author><thr:total>4</thr:total></entry></feed>
