您的位置:首页 > 其它

FLEX 构建完美的带有CheckBox三状态的Tree控件(checkTree)[附测试下载]

2014-06-18 18:08 513 查看
不用说什么了,需要两个文件:

CheckTree.as
package ht
{
	import mx.controls.Tree;
	import mx.core.ClassFactory;
	import mx.events.ListEvent;
	/**
	 * 三状态复选框树控件
	 * <br /><br />
	 */
	
	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 <b>f</b>lash.events.MouseEvent;
	import <b>f</b>lash.geom.Rectangle;
	import <b>f</b>lash.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;
	/**
	 * 三状态复选框树控件
	 *  <br /><br />
	 */ 
	public class CheckTreeRenderer extends TreeItemRenderer
	{
		protected var myCheckBox:CheckBox;
		/**
		 * STATE_SCHRODINGER : 部分子项选中 <br />
		 * STATE_CHECKED :     全部子项选中 <br />
		 * STATE_UNCHECKED :   全部子项未选中 <br />
		 */
		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

测试文档

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  fontSize="12" xmlns:controls="ht.*"
  creationComplete="initApp()" layout="horizontal">
	<mx:Script>
		<!--[CDATA[
			import mx.collections.*;
			import ht.*;
			import mx.collections.ArrayCollection;
			[Bindable]
			public var arrarc:ArrayCollection=new ArrayCollection([
				{state:0,label:"有效值"},
				{state:0,label:"平均值"},
				{state:0,label:"峰值"},
				{state:0,label:"峰峰值"},
				{state:0,label:"X1"},
				{state:2,label:"频带",
					children:[
						{state:0, label:"频带1"},
						{state:1, label:"频带2"},
						{state:0, label:"频带3"},
						{state:0, label:"频带4"},
						{state:0, label:"频带5"},
					]
				}
				]);
			[Bindable]
			public var folderList:XMLList=
				<>
					<folder state="0" label="Marketing Collateral">
						<folder state="0" label="Media,PR,and Communications" >
							<folder state="0" label="Article Reprint Disclaimers" />
							<folder state="0" label="Articles Reprints" />
							<folder state="0" label="Interviews and Transcripts" />
							<folder state="0" label="Press Kits" />
							<folder state="0" label="Press Releases" />
							<folder state="0" label="Quick Hits" />
							<folder state="0" label="Rep Talking Points" />
							<folder state="0" label="Special Updates" />
							<folder state="0" label="White Papers" />
						</folder>
						<folder state="0" label="Forms and Applications" >
							<folder state="0" label="Applications" />
							<folder state="0" label="Forms" />
						</folder>
					</folder>
				</>
			;
			[Bindable]
			public var folderCollection:XMLListCollection;
			override protected function initializationComplete():void
			{
				super.initializationComplete();
				folderCollection=new XMLListCollection(folderList);
			}
			protected function initApp():void
			{
				this.callLater(test);
			}
			protected function test():void
			{
						tree3.checkBoxOpenItemsOnCheck=true;
						tree3.checkBoxCascadeOnCheck=true;
						tree3.checkBoxEnableState=false;
						tree3.itemDClickSelect=true;
						
						tree2.checkBoxOpenItemsOnCheck=true;
						tree2.checkBoxCascadeOnCheck=true;
						tree2.checkBoxEnableState=true;
						tree2.checkBoxBgColor=0x000000;
			}
		]]-->
	</mx:Script>
	<mx:Panel width="166" height="100%" layout="absolute">
		<mx:Form x="0" y="0" width="146" height="100%">
			<mx:CheckBox label="取消收回子项" id="checkBoxCloseItemsOnUnCheck" selected="true"/>
			<mx:CheckBox label="选中展开子项" id="checkBoxOpenItemsOnCheck"/>
			<mx:CheckBox label="是否三状态" id="checkBoxEnableState" selected="true"/>
			<mx:CheckBox label="是否关联父子" id="checkBoxCascadeOnCheck" selected="true"/>
			<mx:FormItem label="样式" direction="vertical">
				<mx:ColorPicker id="checkBoxBgColor" selectedColor="#009900"/>
				<mx:HSlider width="61" id="checkBoxBgAlpha" allowTrackClick="true" minimum="0" maximum="1" snapInterval="0.1" value="1"/>
			</mx:FormItem>
			<mx:FormItem label="填充边距">
				<mx:NumericStepper id="checkBoxBgPadding" value="3" minimum="0" maximum="6" stepSize="1"/>
			</mx:FormItem>
			<mx:FormItem label="填充弧度">
				<mx:NumericStepper id="checkBoxBgElips" value="2" minimum="0" maximum="6" stepSize="1"/>
			</mx:FormItem>
			<mx:FormItem label="左边距">
				<mx:NumericStepper id="checkBoxLeftGap" value="8" minimum="0" maximum="20" stepSize="1"/>
			</mx:FormItem>
			<mx:FormItem label="右边距">
				<mx:NumericStepper id="checkBoxRightGap" value="20" minimum="0" maximum="40" stepSize="1"/>
			</mx:FormItem>
			<mx:CheckBox label="双击是否展开项" id="itemDClickSelect" selected="true"/>
		</mx:Form>
		<mx:ControlBar height="46" y="321">
			<mx:ToggleButtonBar>
			
	<mx:dataProvider>
	    <mx:Array>
	        <mx:String>Flash</mx:String>
	        <mx:String>Director</mx:String>
	        <mx:String>Dreamweaver</mx:String>
	        <mx:String>ColdFusion</mx:String>
	    </mx:Array>
	</mx:dataProvider></mx:ToggleButtonBar>
		</mx:ControlBar>
	</mx:Panel>

	<controls:CheckTree id="tree1" checkBoxStateField="@state" labelField="@label" dataProvider="{folderCollection}" width="100%" height="100%"
						checkBoxCloseItemsOnUnCheck="{checkBoxCloseItemsOnUnCheck.selected}"
						checkBoxOpenItemsOnCheck="{checkBoxOpenItemsOnCheck.selected}"
						checkBoxEnableState="{checkBoxEnableState.selected}"
						checkBoxCascadeOnCheck="{checkBoxCascadeOnCheck.selected}"
						checkBoxBgColor="{checkBoxBgColor.selectedColor}"
						checkBoxBgAlpha="{checkBoxBgAlpha.value}"
						checkBoxBgPadding="{checkBoxBgPadding.value}"
						checkBoxBgElips="{checkBoxBgElips.value}"
						checkBoxLeftGap="{checkBoxLeftGap.value}"
						checkBoxRightGap="{checkBoxRightGap.value}"
						itemDClickSelect="{itemDClickSelect.selected}"
						/>
	<controls:CheckTree id="tree2" 
						width="100%"
						labelField="label"
						checkBoxStateField="state"
						dataProvider="{arrarc}"
						height="100%"/>
	<controls:CheckTree id="tree3"
						width="100%"
						labelField="label"
						checkBoxStateField="state"
						dataProvider="{arrarc}"
						height="100%"/>
</mx:Application>


测试的效果图:



测试工程[下载地址]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: