This weekend I’ve been programming a new tree component that is intended to be used as a hierarchical menu. One thing that I have to do was to change the default behavior of the disclosureIcon. If you wonder what is the disclosureIcon, it is the grey arrow that shows if there is a node or a leaf and if that node is opened or not. That is the disclosureIcon and it has its own behavior different than the item itself.
I needed to implement the same behavior of a regular item but to do this I had to stop the default behavior. So I created a new item renderer based the default TreeItemRenderer in which we will try to modify this behavior.
First I started to study the TreeItemRenderer, to see what it implements what can be changed or overridden, etc. disclosureItem is a protected object so it can be used in our new tree item renderer that extends TreeItemRenderer.
So a logical approach was to remove the event listener of the disclosureIcon. Well that is not possible because the function bind to the event is private so we cannot do:
disclosureIcon.removeEventListener(MouseEvent.MOUSE_DOWN, disclosureMouseDownHandler);
The method disclosureMouseDownHandler is private so cannot be accessed.
Digging further into the code I discovered that the disclosureMouseDownHandler method just sets some variables and then dispatches a TreeEvent.ITEM_OPENING type of event.
With this in my mind and because I didn’t need the TreeEvent.ITEM_OPENING event I just removed the event in the init method of my tree component like this:
15 | removeEventListener(TreeEvent.ITEM_OPENING, mx_internal::expandItemHandler); |
Please notice that the expandItemHandler is using mx_internal name space so we had to use that name space to be able to access the method.
Now having this removed I started to implement my needed event behavior. For this article I’ll implement another behavior to be more easily understood – just an alert pop-up containing the label of the clicked node.
You need to understand that by doing this there is no other default alternative to open the nodes. You may wonder you did I replaced the default behavior of the disclosureIcon? Well I needed to have the following behavior of my custom tree:
- click on a closed item will select it and open it if it has children
- click on a opened item will select it and close it if it has children
- click on a closed item having already an opened node will close the previous node, then select the one clicked on and will open it
This should happen either if we click on the text or on the disclosureIcon. But this is not what we will do here only a short explanation regarding why I removed the default disclosureIcon’s behavior.
Bellow is our example. Click on an arrow to see the result – a simple alert with the name (label) of the clicked node.
In the following example we used four files (source files are bellow and also downloadable at the end of the article):
- main application – DisclosureIconBehaviorChangeApp.mxml
- our tree component – CustomTree.mxml
- our custom tree item renderer – CustomTreeItemRenderer.as
- our custom tree event – CustomTreeEvent.as
1) DisclosureIconBehaviorChangeApp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:flexer="com.flexer.*" creationComplete="start()" > <flexer:CustomTree id="myTree" x="10" y="10" width="200" height="200" labelField="@label" /> <mx:Script> <![CDATA[ // item tree structure private var _menuTreeContent:XML = <mlb> <league label="American League"> <division label="East"> <team label="Boston" /> <team label="New York" /> <team label="Toronto" /> <team label="Baltimore" /> <team label="Tampa Bay" /> </division> <division label="Central"> <team label="Cleveland" /> <team label="Detroit" /> <team label="Minnesota" /> <team label="Chicago" /> <team label="Kansas City" /> </division> <division label="West"> <team label="Los Angeles" /> <team label="Seattle" /> <team label="Oakland" /> <team label="Texas" /> </division> </league> </mlb>; // initialization private function start():void { // setting the data provider myTree.dataProvider = _menuTreeContent.league; // expanding the some nodes callLater( function (node:XML):void { myTree.expandItem(node.league[0], true); myTree.expandItem(node.league[0].division[1], true); }, [_menuTreeContent] ); } ]]> </mx:Script> </mx:Application> |
2) CustomTree
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?xml version="1.0" encoding="utf-8"?> <mx:Tree xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()" itemRenderer="com.flexer.CustomTreeItemRenderer" > <mx:Script> <![CDATA[ import mx.controls.Alert; import mx.events.TreeEvent; // initialization private function init():void { // removing the default event on opeining nodes removeEventListener(TreeEvent.ITEM_OPENING, mx_internal::expandItemHandler); // listening for our custom event addEventListener(CustomTreeEvent.ITEM_SELECTED, handleItemSelected); } // handler for our new custom tree event private function handleItemSelected(e:CustomTreeEvent):void { Alert.show(e.data.@label.toString()); } ]]> </mx:Script> </mx:Tree> |
3) CustomTreeItemRenderer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package com.flexer { import flash.events.MouseEvent; import mx.collections.*; import mx.controls.Tree; import mx.controls.treeClasses.*; public class CustomTreeItemRenderer extends TreeItemRenderer { public function CustomTreeItemRenderer() { super(); } override protected function commitProperties():void { super.commitProperties(); disclosureIcon.addEventListener(MouseEvent.MOUSE_DOWN, arrowMouseDownHandler); } private function arrowMouseDownHandler(e:MouseEvent):void { var stEvent:CustomTreeEvent = new CustomTreeEvent( CustomTreeEvent.ITEM_SELECTED, this.data); (listData.owner as Tree).dispatchEvent(stEvent); } } } |
4) CustomTreeEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package com.flexer { import flash.events.Event; public class CustomTreeEvent extends Event { public static const ITEM_SELECTED:String = "itemSelected"; private var _obj:*; public function CustomTreeEvent(type:String, item:*, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles, cancelable); _obj = item; } override public function clone():Event { return new CustomTreeEvent(type, _obj, bubbles, cancelable); } public function get data():* { return _obj; } } } |
| ||
|
Tags: component, Components, tree
This post was written by Andrei Ionescu
Views: 2355









