FLEX 构建完美的带有CheckBox三状态的Tree控件(checkTree)

阅读更多

不用说什么了,需要两个文件:

CheckTree.as

package ht { import mx.controls.Tree; import mx.core.ClassFactory; import mx.events.ListEvent; /** * 三状态复选框树控件 *

*/ public class CheckTree extends Tree { //数据源中状态字段 private var m_checkBoxStateField:String="@state"; //部分选中的填充色 [Bindable] private var m_checkBoxBgColor:uint=0x009900; //填充色的透明度 [Bindable] private var m_checkBoxBgAlpha:Number=1; //填充色的边距 [Bindable] private var m_checkBoxBgPadding:Number=3; //填充色的四角弧度 [Bindable] private var m_checkBoxBgElips:Number=2; //取消选择是否收回子项 [Bindable] private var m_checkBoxCloseItemsOnUnCheck:Boolean=true; //选择项时是否展开子项 [Bindable] private var m_checkBoxOpenItemsOnCheck:Boolean=false; //选择框左边距的偏移量 [Bindable] private var m_checkBoxLeftGap:int=8; //选择框右边距的偏移量 [Bindable] private var m_checkBoxRightGap:int=20; //是否显示三状态 [Bindable] private var m_checkBoxEnableState:Boolean=true; //与父项子项关联 [Bindable] private var m_checkBoxCascadeOnCheck:Boolean=true; //双击项目 public var itemDClickSelect:Boolean=true; public function CheckTree() { super(); doubleClickEnabled=true; } override protected function createChildren():void { var myFactory:ClassFactory=new ClassFactory(CheckTreeRenderer); this.itemRenderer=myFactory; super.createChildren(); addEventListener(ListEvent.ITEM_DOUBLE_CLICK, onItemDClick); } public function PropertyChange():void { dispatchEvent(new ListEvent(mx.events.ListEvent.CHANGE)); } /** * 树菜单,双击事件 * @param evt 双击事件源 * */ public function onItemDClick(e:ListEvent):void { if(itemDClickSelect) OpenItems(); } /** * 打开Tree节点函数,被 有打开节点功能的函数调用 * @param item 要打开的节点 * */ public function OpenItems():void { if (this.selectedIndex >= 0 && this.dataDescriptor.isBranch(this.selectedItem)) this.expandItem(this.selectedItem, !this.isItemOpen(this.selectedItem), true); } /** * 数据源中状态字段 * @return * */ [Bindable] public function get checkBoxStateField():String { return m_checkBoxStateField; } public function set checkBoxStateField(v:String):void { m_checkBoxStateField=v; PropertyChange(); } /** * 部分选中的填充色 * @return * */ [Bindable] public function get checkBoxBgColor():uint { return m_checkBoxBgColor; } public function set checkBoxBgColor(v:uint):void { m_checkBoxBgColor=v; PropertyChange(); } /** * 填充色的透明度 * @return * */ [Bindable] public function get checkBoxBgAlpha():Number { return m_checkBoxBgAlpha; } public function set checkBoxBgAlpha(v:Number):void { m_checkBoxBgAlpha=v; PropertyChange(); } /** * 填充色的边距 * @return * */ [Bindable] public function get checkBoxBgPadding():Number { return m_checkBoxBgPadding; } public function set checkBoxBgPadding(v:Number):void { m_checkBoxBgPadding=v; PropertyChange(); } /** * 填充色的四角弧度 * @return * */ [Bindable] public function get checkBoxBgElips():Number { return m_checkBoxBgElips; } public function set checkBoxBgElips(v:Number):void { m_checkBoxBgElips=v; PropertyChange(); } /** * 取消选择是否收回子项 * @return * */ [Bindable] public function get checkBoxCloseItemsOnUnCheck():Boolean { return m_checkBoxCloseItemsOnUnCheck; } public function set checkBoxCloseItemsOnUnCheck(v:Boolean):void { m_checkBoxCloseItemsOnUnCheck=v; PropertyChange(); } /** * 选择项时是否展开子项 * @return * */ [Bindable] public function get checkBoxOpenItemsOnCheck():Boolean { return m_checkBoxOpenItemsOnCheck; } public function set checkBoxOpenItemsOnCheck(v:Boolean):void { m_checkBoxOpenItemsOnCheck=v; PropertyChange(); } /** * 选择框左边距的偏移量 * @return * */ [Bindable] public function get checkBoxLeftGap():int { return m_checkBoxLeftGap; } public function set checkBoxLeftGap(v:int):void { m_checkBoxLeftGap=v; PropertyChange(); } /** * 选择框右边距的偏移量 * @return * */ [Bindable] public function get checkBoxRightGap():int { return m_checkBoxRightGap; } public function set checkBoxRightGap(v:int):void { m_checkBoxRightGap=v; PropertyChange(); } /** * 是否显示三状态 * @return * */ [Bindable] public function get checkBoxEnableState():Boolean { return m_checkBoxEnableState; } public function set checkBoxEnableState(v:Boolean):void { m_checkBoxEnableState=v; PropertyChange(); } /** * 与父项子项关联 * @return * */ [Bindable] public function get checkBoxCascadeOnCheck():Boolean { return m_checkBoxCascadeOnCheck; } public function set checkBoxCascadeOnCheck(v:Boolean):void { m_checkBoxCascadeOnCheck=v; PropertyChange(); } } }

CheckTreeRenderer.as

package ht { import flash.events.MouseEvent; import flash.geom.Rectangle; import flash.xml.*; import mx.collections.*; import mx.controls.CheckBox; import mx.controls.Tree; import mx.controls.listClasses.*; import mx.controls.treeClasses.*; import mx.events.FlexEvent; import mx.events.ListEvent; /** * 三状态复选框树控件 *

*/ public class CheckTreeRenderer extends TreeItemRenderer { protected var myCheckBox:CheckBox; /** * STATE_SCHRODINGER : 部分子项选中
* STATE_CHECKED : 全部子项选中
* STATE_UNCHECKED : 全部子项未选中
*/ static private var STATE_SCHRODINGER:int=2; static private var STATE_CHECKED:int=1; static private var STATE_UNCHECKED:int=0; private var myTree:CheckTree; public function CheckTreeRenderer() { super(); mouseEnabled=true; } /** * 初始化完成时处理复选框和图片对象 * */ override protected function createChildren():void { myCheckBox=new CheckBox(); addChild(myCheckBox); myCheckBox.addEventListener(MouseEvent.CLICK, checkBoxToggleHandler); myTree = this.owner as CheckTree; super.createChildren(); myTree.addEventListener(ListEvent.CHANGE,onPropertyChange); } protected function onPropertyChange(e:ListEvent=null):void { this.updateDisplayList(unscaledWidth,unscaledHeight); } /** * // TODO : 递归设置父项目的状态 * @param item 项目 * @param tree 树对象 * @param state 目标状态 * */ private function toggleParents(item:Object, tree:Tree, state:int):void { if (item == null) return ; else { var stateField:String=myTree.checkBoxStateField; var tmpTree:IList=myTree.dataProvider as IList; var oldValue:Number=item[stateField] as Number; var newValue:Number=state as Number; item[myTree.checkBoxStateField]=state; tmpTree.itemUpdated(item,stateField,oldValue,newValue); //item[myTree.checkBoxStateField]=state; var parentItem:Object=tree.getParentItem(item); if(null!=parentItem) toggleParents(parentItem, tree, getState(tree, parentItem)); } } /** * // TODO : 设置项目的状态和子项的状态 * @param item 项目 * @param tree 树对象 * @param state 目标状态 * */ private function toggleChildren(item:Object, tree:Tree, state:int):void { if (item == null) return ; else { var stateField:String=myTree.checkBoxStateField; var tmpTree:IList=myTree.dataProvider as IList; var oldValue:Number=item[stateField] as Number; var newValue:Number=state as Number; item[myTree.checkBoxStateField]=state; tmpTree.itemUpdated(item,stateField,oldValue,newValue); var treeData:ITreeDataDescriptor=tree.dataDescriptor; if (myTree.checkBoxCascadeOnCheck && treeData.hasChildren(item)) { var children:ICollectionView=treeData.getChildren(item); var cursor:IViewCursor=children.createCursor(); while(!cursor.afterLast) { toggleChildren(cursor.current, tree, state); cursor.moveNext(); } } } } /** * //TODO:获得parent的状态 * @param tree 树对象 * @param parent 目标项 * @return 状态 * */ private function getState(tree:Tree, parent:Object):int { var noChecks:int=0; var noCats:int=0; var noUnChecks:int=0; if (parent != null) { var treeData:ITreeDataDescriptor=tree.dataDescriptor; var cursor:IViewCursor=treeData.getChildren(parent).createCursor(); while(!cursor.afterLast) { if (cursor.current[myTree.checkBoxStateField] == STATE_CHECKED) noChecks++; else if (cursor.current[myTree.checkBoxStateField] == STATE_UNCHECKED) noUnChecks++; else noCats++; cursor.moveNext(); } } if ((noChecks > 0 && noUnChecks > 0) || noCats > 0) return STATE_SCHRODINGER; else if (noChecks > 0) return STATE_CHECKED; else return STATE_UNCHECKED; } /** * //TODO:设置项目的父项状态和子项状态 * @param event 事件 * */ private function checkBoxToggleHandler(event:MouseEvent):void { if (data) { var myListData:TreeListData=TreeListData(this.listData); var selectedNode:Object=myListData.item; myTree=myListData.owner as CheckTree; var toggle:Boolean=myCheckBox.selected; if (toggle) { toggleChildren(data, myTree, STATE_CHECKED); if (myTree.checkBoxOpenItemsOnCheck) myTree.expandChildrenOf(data, true); } else { toggleChildren(data, myTree, STATE_UNCHECKED); if (myTree.checkBoxCloseItemsOnUnCheck) myTree.expandChildrenOf(data, false); } //TODO:如果所有子项选中时需要选中父项则执行以下代码 if (myTree.checkBoxCascadeOnCheck) { var parent:Object=myTree.getParentItem(data); if(null!=parent) toggleParents(parent, myTree, getState(myTree, parent)); } } //myTree.PropertyChange(); //dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE)); } /** * 设置本项的复选框状态 * @param checkBox 复选框 * @param value * @param state 状态 * */ private function setCheckState(checkBox:CheckBox, value:Object, state:int):void { if (state == STATE_CHECKED) checkBox.selected=true; else if (state == STATE_UNCHECKED) checkBox.selected=false; else if (state == STATE_SCHRODINGER) checkBox.selected=false; } override public function set data(value:Object):void { if (value != null) { super.data=value; setCheckState(myCheckBox, value, value[myTree.checkBoxStateField]); } } override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); if (super.data) { if (super.icon != null) { myCheckBox.x=super.icon.x + myTree.checkBoxLeftGap; myCheckBox.y=(height - myCheckBox.height) / 2; super.icon.x=myCheckBox.x + myCheckBox.width + myTree.checkBoxRightGap; super.label.x=super.icon.x + super.icon.width + 3; } else { myCheckBox.x=super.label.x + myTree.checkBoxLeftGap; myCheckBox.y=(height - myCheckBox.height) / 2; super.label.x=myCheckBox.x + myCheckBox.width + myTree.checkBoxRightGap; } setCheckState(myCheckBox, data, data[myTree.checkBoxStateField]); if (myTree.checkBoxEnableState && data[myTree.checkBoxStateField] == STATE_SCHRODINGER) { fillCheckBox(true); trace(myTree.checkBoxEnableState); trace(data[myTree.checkBoxStateField]); } else fillCheckBox(false); } } protected function fillCheckBox(isFill:Boolean):void { myCheckBox.graphics.clear(); if (isFill) { var myRect:Rectangle=getCheckTreeBgRect(myTree.checkBoxBgPadding); myCheckBox.graphics.beginFill(myTree.checkBoxBgColor, myTree.checkBoxBgAlpha) myCheckBox.graphics.drawRoundRect(myRect.x, myRect.y, myRect.width, myRect.height, myTree.checkBoxBgElips, myTree.checkBoxBgElips); myCheckBox.graphics.endFill(); } } protected function getCheckTreeBgRect(checkTreeBgPadding:Number):Rectangle { var myRect:Rectangle=myCheckBox.getBounds(myCheckBox); myRect.top+=checkTreeBgPadding; myRect.left+=checkTreeBgPadding; myRect.bottom-=checkTreeBgPadding; myRect.right-=checkTreeBgPadding; return myRect; } } //end class } //end package

测试文档:

Flash Director Dreamweaver ColdFusion

测试的效果图:

FLEX 构建完美的带有CheckBox三状态的Tree控件(checkTree)_第1张图片

你可能感兴趣的:(FLEX 构建完美的带有CheckBox三状态的Tree控件(checkTree))