常常会用到带有3种状态CheckBox的树形组件,比如在权限管理中,或者是地区选择中等等,如下图:
不多说费话了,直接进入主题,看看如何实现。其实在Flex中,只用自己实现一个TreeItemRenderer就可以了,代码如下:
package com.robin {
import flash.events.Event;
import flash.geom.Rectangle;
import mx.controls.CheckBox;
import mx.controls.treeClasses.TreeItemRenderer;
import mx.controls.treeClasses.TreeListData;
import mx.events.FlexEvent;
public class ThreeStatusCheckBoxTreeItemRenderer extends TreeItemRenderer {
private static var _colorForThirdState:int = 0x37BEF8;
private static var _selectedField:String = "selected";
private var checkBox:CheckBox;
public function ThreeStatusCheckBoxTreeItemRenderer() {
super();
}
override protected function createChildren():void {
super.createChildren();
checkBox = new CheckBox();
addChild(checkBox);
checkBox.addEventListener(Event.CHANGE, changeHandler);
}
/**//**
* Initial data when component initialization
*
*/
override protected function commitProperties():void {
super.commitProperties();
if (data && data.@[_selectedField] != null) {
var s:int = int(data.@[_selectedField]);
var selected:Boolean = s > 0 ? true : false;
checkBox.selected = selected;
} else {
checkBox.selected = false;
}
}
/**//**
* update dataProvider when user click CheckBox
*
*/
protected function changeHandler(event:Event):void {
if (data && data.@[_selectedField] != null) {
data.@[_selectedField] = checkBox.selected ? "1" : "0";
}
var listData:TreeListData = TreeListData(listData);
if (listData.hasChildren) {
var item:XML = XML(listData.item);
handleAllChildren(item.children());
}
handleAllParents(listData.item.parent());
}
private function handleAllChildren(children:XMLList):void {
for each (var item:XML in children) {
item.@[_selectedField] = checkBox.selected ? "1" : "0";
var children:XMLList = item.children();
if (children.length() > 0) {
handleAllChildren(children);
}
}
}
private function handleAllParents(parent:XML):void {
if (parent != null) {
var children:XMLList = parent.children();
var hasSelected1:Boolean = false;
var hasSelected2:Boolean = false;
var hasSelected0:Boolean = false;
for each (var item:XML in children) {
if (int(item.@[_selectedField]) == 1) {
hasSelected1 = true;
}
if (int(item.@[_selectedField]) == 2) {
hasSelected2 = true;
}
if (int(item.@[_selectedField]) == 0) {
hasSelected0 = true;
}
}
if (checkBox.selected == true) {
if (!hasSelected0 && !hasSelected2) {
parent.@[_selectedField] = "1";
} else {
parent.@[_selectedField] = "2";
}
} else {
if (!hasSelected1 && !hasSelected2) {
parent.@[_selectedField] = "0";
} else {
parent.@[_selectedField] = "2";
}
}
handleAllParents(parent.parent());
}
}
/**//**
* reset itemRenderer's width
*/
override protected function measure():void {
super.measure();
measuredWidth += checkBox.getExplicitOrMeasuredWidth();
}
/**//**
* re-assign layout for tree, move lable to right
* @param unscaledWidth
* @param unscaledHeight
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
var startx:Number = data ? TreeListData(listData).indent : 0;
if (disclosureIcon) {
disclosureIcon.x = startx;
startx = disclosureIcon.x + disclosureIcon.width;
disclosureIcon.setActualSize(disclosureIcon.width, disclosureIcon.height);
disclosureIcon.visible = data ? TreeListData(listData).hasChildren : false;
}
if (icon) {
icon.x = startx;
startx = icon.x + icon.measuredWidth;
icon.setActualSize(icon.measuredWidth, icon.measuredHeight);
}
checkBox.move(startx, (unscaledHeight - checkBox.height) / 2);
label.x = startx + checkBox.getExplicitOrMeasuredWidth();
var node:XML = data as XML;
if (int(node.@[_selectedField]) == 2) {
fillCheckBox(true);
} else {
fillCheckBox(false);
}
}
/**//**
* re-draw check box for the third state
* @param isFill
*/
private function fillCheckBox(isFill:Boolean):void {
checkBox.validateNow();
checkBox.graphics.clear();
if (isFill) {
var myRect:Rectangle = checkBox.getBounds(checkBox);
checkBox.graphics.beginFill(_colorForThirdState, 1);
checkBox.graphics.drawRoundRect(myRect.x, myRect.y, myRect.width, myRect.height, 1, 0x00FF00);
checkBox.graphics.endFill();
}
}
}
}
然后在tree组件中使用这个renderer就可以了。
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:robin="com.robin.*">
<fx:Declarations>
<fx:XMLList id="treeData">
<node name = "ShangHai" type="ROOT" selected ="1">
<node name = "HuangPu" type="NODE" selected = "1">
<node name = "A" type="NODE" selected = "1" />
<node name = "B" type="NODE" selected = "1" />
</node>
<node name = "PuDong" type="NODE" selected = "1"/>
</node>
<node name = "Beijing" type="ROOT" selected = "2">
<node name = "HaiDian" type="NODE" selected = "0"/>
<node name = "ChaoYang" type="NODE" selected = "1"/>
</node>
</fx:XMLList>
</fx:Declarations>
<fx:Script>
<![CDATA[
protected function getCurrentData_clickHandler(event:MouseEvent):void {
currentText.text = String(treeData);
}
]]>
</fx:Script>
<mx:Tree x = "0" y = "0" width = "232" height = "285" itemRenderer = "com.robin.ThreeStatusCheckBoxTreeItemRenderer" labelField = "@name" dataProvider = "{treeData}"/>
<s:Button x = "43" y = "293" label = "Get Current Data" id = "getCurrentData" click = "getCurrentData_clickHandler(event)"/>
<s:TextArea x = "253" y = "0" width = "459" height = "285" id = "currentText"/>
</s:Application>
就是这么简单!
posted on 2010-09-15 07:58
Robin's Programming World 阅读(5926)
评论(7) 编辑 收藏 所属分类:
Flex & Flash