1.首先得明白一点,FLEX4的TREE接受的是XML类型的数据,所以无论以何种方式获得XML数据,TREE通过dataProvider=XMLDATA和labelField=@viewname都可以显示出来一棵树
第一种方式,读取本地或远程XML文件
XML文件的格式,大致如下
<?xml version="1.0" encoding="UTF-8"?>
<node label='所有分类'>
<node label='中国' value="http://www.baidu.com">
<node label='河南' value="http://www.youdao.com" >
<node label='信阳' />
<node label='南阳'/>
</node>
<node label='河北'>
<node label='保定'/>
<node label='衡水'/>
</node>
<node label='湖南' >
<node label='长沙'/>
<node label='湘潭'/>
</node>
<node label='湖北'>
<node label='武汉'/>
<node label='仙桃'/>
</node>
</node>
</node>
针对上面这个XML格式的文件,Flex4的TREE解析后显示的话会从第二个节点开始解析也即中国那个节点 这种方式的代码我贴出来,大家看下
<?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"
creationComplete="SrvTreeList.send();init()">
<fx:Style>
Tree {
folderClosedIcon: ClassReference(null);
folderOpenIcon: ClassReference(null);
}
</fx:Style>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
var XMLTreeList:XML;
protected function treeService_resultHandler(event:ResultEvent):void
{
//先把数据取出来交给XML,再交给dataProvider,因为dataProvider不能直接解析String为XML
XMLTreeList=XML(SrvTreeList.lastResult.toString());
MusicTypeTree.dataProvider=XMLTreeList;
}
//这里我写了一个右键菜单
public function init():void{
var item: ContextMenuItem=new ContextMenuItem("添加");
var menu:ContextMenu=new ContextMenu();
menu.customItems.push(item);
MusicTypeTree.contextMenu=menu;
}
protected function tree1_clickHandler(event:MouseEvent):void
{
if(MusicTypeTree.selectedItem.hasOwnProperty("@value" ))
{ //如果某节点中含有VALUE属性,那么就是先跳转页面
navigateToURL(new URLRequest(MusicTypeTree.selectedItem.@value));
} else
{
//没有那就展开,如果展开了就收缩
MusicTypeTree.expandItem(MusicTypeTree.selectedItem,!MusicTypeTree.isItemOpen(MusicTypeTree.selectedItem),true);
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<s:HTTPService id="SrvTreeList" url="data/tree.xml" result="treeService_resultHandler(event)" useProxy="false" resultFormat="xml" />
</fx:Declarations>
<!--@label这个非常重要,指定要显示的标题为XML重的label属性值。记住要显示树,httpService的send方法要在组件创建完成后被调用-->
<mx:Tree x="20" y="10" click="tree1_clickHandler(event)" id="MusicTypeTree"
left="5" right="5"
showRoot="false"
labelField="@label"
bottom="5" top="40"
></mx:Tree>
</s:Application>
第二种方式:将XML内容写到<fx:mxl>标签里面 这种方式我们来看看
<?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"
creationComplete="init()">
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ICollectionView;
import mx.events.ListEvent;
private function tree_itemClick(evt:ListEvent):void {
var item:Object = Tree(evt.currentTarget).selectedItem;
if (tree.dataDescriptor.isBranch(item)) {
tree.expandItem(item, !tree.isItemOpen(item), true);
}
}
private function tree_labelFunc(item:XML):String {
var children:ICollectionView;
var suffix:String = "";
if (tree.dataDescriptor.isBranch(item)) {
children = tree.dataDescriptor.getChildren(item);
suffix = " (" + children.length + ")";
}
return item[tree.labelField] + suffix;
}
]]>
</fx:Script>
<fx:Declarations>
<fx:XML id="dp">
<root>
<folder label="One">
<folder label="One.A">
<item label="One.A.1" />
<item label="One.A.2" />
<item label="One.A.3" />
<item label="One.A.4" />
<item label="One.A.5" />
</folder>
<item label="One.1" />
<item label="One.2" />
</folder>
<folder label="Two">
<item label="Two.1" />
<folder label="Two.A">
<item label="Two.A.1" />
<item label="Two.A.2" />
</folder>
</folder>
</root>
</fx:XML>
</fx:Declarations>
<mx:Tree id="tree"
dataProvider="{dp}"
showRoot="false"
labelField="@label"
labelFunction="tree_labelFunc"
width="742"
rowCount="6"
itemClick="tree_itemClick(event);" x="14" y="12" height="359"/>
</s:Application>
itemClick方法可以和labelFuntion可以不写,正常的话不写方法就能显示TREE的树形结构了
第三:再看一个例子
<?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">
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<fx:XMLList id="treeData">
<node label="Mail Box">
<node label="Inbox">
<node label="Marketing"/>
<node label="Product Management"/>
<node label="Personal"/>
</node>
<node label="Outbox">
<node label="Professional"/>
<node label="Personal"/>
</node>
<node label="Spam"/>
<node label="Sent"/>
</node>
</fx:XMLList>
</fx:Declarations>
<fx:Script>
<![CDATA[
[Bindable]
public var selectedNode:XML;
// Event handler for the Tree control change event.
public function treeChanged(event:Event):void {
selectedNode=Tree(event.target).selectedItem as XML;
}
]]>
</fx:Script>
<mx:Panel title="Tree Control Example" height="75%" width="75%"
paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
<mx:Label width="100%" color="blue"
text="Select a node in the Tree control."/>
<mx:HDividedBox width="100%" height="100%">
<mx:Tree id="myTree" width="50%" height="100%" labelField="@label"
showRoot="false" dataProvider="{treeData}" change="treeChanged(event)"/>
<mx:TextArea height="100%" width="50%"
text="Selected Item: {selectedNode.@label}"/>
</mx:HDividedBox>
</mx:Panel>
</s:Application>
第四,到目前为止,应该可以看出来了XML的显示格式了,如果获取XML文件那么结果要转换成为 var xmlList:XML=XML(event.result.toString()); mytree.dataProvider=xmlList; 要么就是<mx:Tree dataProvider="{xmlList}" > 那么就是 <fx:xml id="xmlid"></fx:xml> <mx:Tree dataProvider="{xmlid}">
这么多的方式都可以把数据填充到TREE中去
第五:来一个增删拖拽展开,收缩的示例,这里先不涉及到后台,下一篇文章会讲到TREE与JAVA后台数据库的交互操作
<?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"
creationComplete="SrvTreeList.send();init()">
<fx:Style>
Tree {
folderClosedIcon: ClassReference(null);
folderOpenIcon: ClassReference(null);
}
</fx:Style>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.core.DragSource;
import mx.core.UIComponent;
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.rpc.events.ResultEvent;
var XMLTreeList:XML;
protected function treeService_resultHandler(event:ResultEvent):void
{
//先把数据取出来交给XML,再交给dataProvider,因为dataProvider不能直接解析String为XML
XMLTreeList=XML(SrvTreeList.lastResult.toString());
MusicTypeTree.dataProvider=XMLTreeList;
}
public function init():void{
var item: ContextMenuItem=new ContextMenuItem("添加");
var menu:ContextMenu=new ContextMenu();
menu.customItems.push(item);
MusicTypeTree.contextMenu=menu;
}
protected function tree1_clickHandler(event:MouseEvent):void
{
if(MusicTypeTree.selectedItem.hasOwnProperty("@value" ))
{
var u:URLRequest=new URLRequest(MusicTypeTree.selectedItem.@value);
//navigateToURL(new URLRequest(MusicTypeTree.selectedItem.@value));
navigateToURL(u);
} else
{
//没有那就展开,如果展开了就收缩
MusicTypeTree.expandItem(MusicTypeTree.selectedItem,!MusicTypeTree.isItemOpen(MusicTypeTree.selectedItem),true);
}
}
//添加兄弟节点
protected function addBefore():void
{
var xml:XML=MusicTypeTree.selectedItem as XML;
var text:String=nextName.text;
if(xml!=null && text.length>0) {
var parent:XML=xml.parent();
if(parent!=null) {
var child:XML=new XML("<node foddersortName=\"\" foddersortId=\"\" parentid=\"\" />");
child.@foddersortName=text;
parent.insertChildBefore(xml,child);
} else {
Alert.show("不能选中根节点");
}
} else {
Alert.show("需要先选中节点和填入文字");
}
}
protected function addAfter():void
{
var xml:XML=MusicTypeTree.selectedItem as XML;
var text:String=nextName.text;
if(xml!=null && text.length>0) {
var parent:XML=xml.parent();
if(parent!=null) {
var child:XML=new XML("<node foddersortName=\"\" foddersortId=\"\" parentid=\"\" />");
child.@foddersortName=text;
parent.insertChildAfter(xml,child);
} else {
Alert.show("不能选中根节点");
}
} else {
Alert.show("需要先选中节点和填入文字");
}
}
protected function addSon():void
{
var xml:XML=MusicTypeTree.selectedItem as XML;
var text:String=nextName.text;
if(xml!=null && text.length>0) {
var parent:XML=xml.parent();
var child:XML=new XML("<node foddersortName=\"\" foddersortId=\"\" parentid=\"\" />");
child.@foddersortName=text;
xml.appendChild(child);
MusicTypeTree.expandChildrenOf(xml,true);
} else {
Alert.show("需要先选中节点和填入文字");
}
}
protected function editNode():void
{
var xml:XML=MusicTypeTree.selectedItem as XML;
var text:String=nextName.text;
if(xml!=null && text.length>0) {
xml.@foddersortName=text;
} else {
Alert.show("需要先选中节点和填入文字");
}
}
protected function deleteNode():void
{
var xml:XML=MusicTypeTree.selectedItem as XML;
if(xml!=null) {
var list:Array=MusicTypeTree.selectedItems as Array;
for(var k:int=0;k<list.length;k++) {
xml=list[k] as XML;
var parent:XML=xml.parent();
if(parent!=null) {
var children:XMLList=parent.children();
for(var i:int=0;i<children.length();i++) {
if(children[i]==xml) {
delete children[i];
break;
}
}
} else {
Alert.show("不能选中根节点");
}
}
} else {
Alert.show("需要先选中节点");
}
}
protected function selectNode():void
{
var text:String=nextName.text;
if(text.length>0) {
var items:Array=[];
var list:XMLList=new XMLList();
list[0]=MusicTypeTree.dataProvider[0];
searchItems(list,text,items);
MusicTypeTree.selectedItems=items;
} else {
Alert.show("输入查找的文字");
}
}
private function searchItems(list:XMLList,find:String,items:Array):void {
for(var i:int=0;i<list.length();i++) {
var one:XML=list[i];
var label:String=one.@foddersortName;
if(label!=null && label.indexOf(find)>=0) {
items.push(one);
}
searchItems(one.children(),find,items);
}
}
protected function closeAll():void{
MusicTypeTree.openItems=[];
}
protected function openAll():void{
MusicTypeTree.expandChildrenOf(MusicTypeTree.selectedItem,true);
}
protected function MusicTypeTree_dragEnterHandler(event:DragEvent):void
{
Alert.show(event.target.@foddersortName);
DragManager.acceptDragDrop(UIComponent(event.currentTarget));
}
protected function MusicTypeTree_dragOverHandler(event:DragEvent):void
{
// r is the visible index in the tree
var dropTarget:Tree = Tree(event.currentTarget);
var r:int = dropTarget.calculateDropIndex(event);
MusicTypeTree.selectedIndex = r;
// retrieving the newly selected node, you can examine it and decide to tell
// the user the drop is invalid by changing the feedback.
var node:XML = MusicTypeTree.selectedItem as XML;
if( node.@foddersortName == "中国" ) {
DragManager.showFeedback(DragManager.NONE);
return;
}
// the type of drop - copy, link, or move can be reflected in the feedback as well.
// Here the control and shift keys determine that action.
if (event.ctrlKey)
DragManager.showFeedback(DragManager.COPY);
else if (event.shiftKey)
DragManager.showFeedback(DragManager.LINK);
else {
DragManager.showFeedback(DragManager.MOVE);
}
}
protected function MusicTypeTree_dragDropHandler(event:DragEvent):void
{
var xml:XML=MusicTypeTree.selectedItem as XML;
Alert.show(xml.@foddersortName);
// var ds:DragSource = event.dragSource;
// var dropTarget:Tree = Tree(event.currentTarget);
// // retrieve the data associated with the "items" format. This will be the data that
// // the dragInitiator has copied into the DragSource.
// var items:Array = ds.dataForFormat("items") as Array;
// // determine where in the tree the drop occurs and select that node by the index; followed by
// // retrieving the node itself.
// var r:int = MusicTypeTree.calculateDropIndex(event);
// MusicTypeTree.selectedIndex = r;
// var node:XML = MusicTypeTree.selectedItem as XML;
// var p:*;
// // if the selected node has children (it is type==city),
// // then add the items at the beginning
// if( MusicTypeTree.dataDescriptor.hasChildren(node) ) {
// p = node;
// r = 0;
// } else {
// p = node.parent();
// }
// // taking all of the items in the DragSouce, insert them into the
// // tree using parent p.
// for(var i:Number=0; i < items.length; i++) {
// var insert:XML = <node />;
// insert.@foddersortName= items[i];
// //insert.@type = "restaurant";
// MusicTypeTree.dataDescriptor.addChildAt(p, insert, r+i);
// }
}
protected function MusicTypeTree_dragCompleteHandler(event:DragEvent):void
{
MusicTypeTree.selectedIndex = -1;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<s:HTTPService id="SrvTreeList" url="data/tree.xml" result="treeService_resultHandler(event)" useProxy="false" resultFormat="xml" />
</fx:Declarations>
<!--@label这个非常重要,指定要显示的标题为XML重的label属性值。记住要显示树,httpService的send方法要在组件创建完成后被调用-->
<mx:Tree click="tree1_clickHandler(event)" id="MusicTypeTree"
left="5" right="845"
showRoot="false"
labelField="@foddersortName"
bottom="243" top="40"
dragEnabled="true"
dropEnabled="true"
allowMultipleSelection="true"
allowDragSelection="true"
dragDrop="MusicTypeTree_dragDropHandler(event)"
dragEnter="MusicTypeTree_dragEnterHandler(event)"
></mx:Tree>
<s:TextInput id="nextName" x="432" y="40"/>
<s:Button x="443" y="82" label="增加为哥" click="addBefore()"/>
<s:Button x="443" y="111" label="增加为弟" click="addAfter()"/>
<s:Button x="444" y="144" click="addSon()" label="增加为孩子"/>
<s:Button x="444" y="178" click="editNode()" label="修改节点"/>
<s:Button x="444" y="211" click="deleteNode()" label="删除节点"/>
<s:Button x="443" y="244" click="selectNode()" label="选择节点"/>
<s:Button x="443" y="277" click="closeAll()" label="全部收缩"/>
<s:Button x="443" y="306" click="openAll()" label="全部展开"/>
</s:Application>
这次要说的是Flex的树组件的拖动效果,从树组件拖动到其他组件如List,DataGrid或者从其他组件拖动到Tree组件中,其实主要就是处理drag相关事件
第一:从Tree到List
示例一
<?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">
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<fx:XML id="myData">
<data>
<item label="ActionScript">
<item label="Flash" />
<item label="Flex" />
</item>
<item label="Mirage">
</item>
<item label="JavaScript"/>
</data>
</fx:XML>
<fx:XML id="copyData">
<data>
<item label="JavaScript"/>
</data>
</fx:XML>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Button;
import mx.core.IUIComponent;
import mx.core.DragSource;
import mx.managers.DragManager;
import mx.events.DragEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
//拖动对象进入时
private function onDragOver( event:DragEvent ) : void
{
var dropTarget:Tree = Tree(event.currentTarget);
var r:int = dropTarget.calculateDropIndex(event);
lbl.text = '当前位置:'+r.toString();//哪一个节点在鼠标下并给出相应信息
tree2.selectedIndex = r; //显示位置
var node:XML = sourceTree.selectedItem as XML;
lbl2.text = '当前的拖动对象是:'+node.@label;//拖动对象的名字
if( node.@label == "ActionScript" ) {
DragManager.showFeedback(DragManager.NONE);
return;
}
// 键盘控制
if (event.ctrlKey)
DragManager.showFeedback(DragManager.COPY);//复制
else if (event.shiftKey)
DragManager.showFeedback(DragManager.LINK);//剪切
else {
DragManager.showFeedback(DragManager.MOVE);//移动
}
}
//拖动对象被抛出后
private function onDragDrop( event:DragEvent ) : void
{
// var ds:DragSource = event.dragSource;
var dropTarget:Tree = Tree(event.currentTarget);
// retrieve the data associated with the "items" format.
//var items:Array = ds.dataForFormat("items") as Array;
var r:int = tree2.calculateDropIndex(event);
tree2.selectedIndex = r;//当拖放完成后选定相应的节点
var node:XML = tree2.selectedItem as XML;
var p:*;
//tree2.dataDescriptor.hasChildren(node)判断有没有子节点,如果有就返回true
if( tree2.dataDescriptor.hasChildren(node) ) {
p = node;
r = 0;
trace('有子节点');
} else {
p = node.parent();
trace('没有子节点');
}
// taking all of the items in the DragSouce, insert them into the
// tree using parent p.
// for(var i:Number=0; i < items.length; i++) {
// var insert:XML = <node/>;
// insert.@label = items[i];
// insert.@type = "restaurant";
// tree2.dataDescriptor.addChildAt(p, insert, r+i);
// }
}
private function onDragComplete(event:DragEvent) : void
{
trace('stop');
tree2.selectedIndex = 0;
}
]]>
</fx:Script>
<mx:Label text="Label" id="lbl" x="439" y="120"/>
<mx:Tree dropEnabled="true" dragEnabled="true" allowMultipleSelection="true" id="sourceTree"
dataProvider="{myData.item}" labelField="@label" x="114" y="146"/>
<mx:Tree dropEnabled="true" id="tree2" dataProvider="{copyData.item}" labelField="@label"
dragOver="onDragOver(event)" dragDrop="onDragDrop(event)" dragComplete="onDragComplete(event)" x="382" y="146"/>
<mx:Label x="382" y="94" text="Label" width="274" id="lbl2" height="29"/>
<mx:Label x="218" y="62" text="Tree与Tree之间的拖动" width="139" height="19"/>
</s:Application>
示例二
<?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">
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<!-- 这里定义班组树的结构和内容 -->
<fx:XMLList id="treeData">
<node label="Mail Box">
<node label="工区1">
<node label="工地1">
<node label="班组1.1" data="111"/>
<node label="班组1.2"/>
</node>
<node label="工地2">
<node label="班组2.1"/>
<node label="班组2.2"/>
</node>
<node label="工地3">
<node label="班组3.1"/>
<node label="班组3.2"/>
</node>
</node>
<node label="工区2">
<node label="Professional"/>
<node label="Personal"/>
</node>
</node>
</fx:XMLList>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Label;
import mx.core.IUIComponent;
import mx.core.DragSource;
import mx.managers.DragManager;
import mx.events.DragEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]
public var list:ArrayCollection=new ArrayCollection();
//拖动初始器
private function dragSource(e:MouseEvent,format:String):void
{
var iu:IUIComponent = e.currentTarget as IUIComponent;
var ds:DragSource=new DragSource();
ds.addData(myTree.selectedItem,format);//为myTree设置一个标号forma
var lbl:Label=new Label();
lbl.text="开始拖动";
lbl.x = e.stageX;
lbl.y = e.stageY;
//lbl拖动的影子,默认为自己doDrag(拖动的对象,拖动器,事件,拖动影子,x,y)
DragManager.doDrag(iu,ds,e,lbl,e.stageX,e.stageY);//开始拖动这个物体
}
//当拖进去时
private function doDragEnter(e:DragEvent,format:String):void
{
var len:int=(mylist.dataProvider as ArrayCollection).length;//判断list中有多少个数据
var selectnode:XML = myTree.selectedItem as XML;//选择的节点名
for(var i:int=0;i<len;i++)
{
if(validateIsEqual((mylist.dataProvider as ArrayCollection).getItemAt(i),selectnode))
{
Alert.show("该班组已经存在!");
}
}
if(e.dragSource.hasFormat(format)){//如果标号为format则接受拖来的物体
DragManager.acceptDragDrop(IUIComponent(e.target));
}
}
//当拖完成时
private function onDragDrop(e:DragEvent,format:String):void{
var row:Object=e.dragSource.dataForFormat(format);
list.addItem(row);//list的数据源添加数据
}
//判断选中的节点是否和List中的内容一样
private function validateIsEqual(obj1:Object,obj2:Object):Boolean
{
if(obj1==obj2)//条件未判断
{
return true;
}
else
{
return false;
}
}
]]>
</fx:Script>
<mx:Tree id="myTree" labelField="@label" dragEnabled="true" mouseDown="dragSource(event,'stringFormat')"
showRoot="true" dataProvider="{treeData}" height="331" horizontalCenter="-120" verticalCenter="7" width="190"/>
<mx:List height="331" labelField="@label" dragEnter="doDragEnter(event,'stringFormat')"
dataProvider="{list}" dragDrop="onDragDrop(event,'stringFormat')" width="162" id="mylist" horizontalCenter="114" verticalCenter="7"></mx:List>
<mx:Label x="282.5" y="97" text="Tree与list的拖动" width="152"/>
</s:Application>
第二:从Tree到DataGrid
<?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">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<fx:XML id="treeData" xmlns="">
<root>
<node label="Massachusetts" type="state" data="MA">
<node label="Boston" type="city" >
<node label="Smoke House Grill" type="restaurant" />
<node label="Equator" type="restaurant" />
<node label="Aquataine" type="restaurant" />
<node label="Grill 23" type="restaurant" />
</node>
<node label="Provincetown" type="city" >
<node label="Lobster Pot" type="restaurant" />
<node label="The Mews" type="restaurant" />
</node>
</node>
<node label="California" type="state" data="CA">
<node label="San Francisco" type="city" >
<node label="Frog Lane" type="restaurant" />
</node>
</node>
</root>
</fx:XML>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.controls.Label;
import mx.controls.List;
import mx.collections.ArrayCollection;
import mx.core.DragSource;
import mx.controls.Tree;
import mx.controls.DataGrid;
import mx.controls.listClasses.ListBase;
import mx.events.DragEvent;
import mx.containers.Canvas;
import mx.managers.DragManager;
import mx.core.UIComponent;
[Bindable]
private var dataGridProvider:ArrayCollection = new ArrayCollection();
/**
* Handles the dragEnter event on the DataGrid control.
* If the dragInitiator is the Tree control, then only nodes of type "restaurant"
* are permitted to be dropped.
* Here you can see that by examining the dragSource you can determine if
* the control should accept the drop. The DataGrid control would not
* know how to treat a branch+children from the Tree control, so only leaf (restaurant)
* nodes are accepted.
*/
private function onDragEnter( event:DragEvent ) : void
{
if( event.dragInitiator is Tree ) {
var ds:DragSource = event.dragSource;
if( !ds.hasFormat("treeItems") ) return; // no useful data
var items:Array = ds.dataForFormat("treeItems") as Array;
for(var i:Number=0; i < items.length; i++) {
var item:XML = XML(items[i]);
if( item.@type != "restaurant" ) return; // not what we want
}
}
// If the Tree control passes or the dragInitiator is not a Tree control,
// accept the drop.
DragManager.acceptDragDrop(UIComponent(event.currentTarget));
}
/**
* Handles the dragOver event on the DataGrid control.
* If the dragInitiator is the Tree control, only copy is allowed. Otherwise, a move
* or link can take place from the List control.
*/
private function onDragOver( event:DragEvent ) : void
{
if( event.dragInitiator is Tree ) {
DragManager.showFeedback(DragManager.COPY);
} else {
if (event.ctrlKey)
DragManager.showFeedback(DragManager.COPY);
else if (event.shiftKey)
DragManager.showFeedback(DragManager.LINK);
else {
DragManager.showFeedback(DragManager.MOVE);
}
}
}
/**
* Handles the dragExit event on the drop target and just hides the
* the drop feedback.
*/
private function onDragExit( event:DragEvent ) : void
{
var dropTarget:ListBase=ListBase(event.currentTarget);
dropTarget.hideDropFeedback(event);
}
/**
* Handles the dragDrop event on the DataGrid when the
* drag proxy is released.
*/
private function onGridDragDrop( event:DragEvent ) : void
{
var ds:DragSource = event.dragSource;
var dropTarget:DataGrid = DataGrid(event.currentTarget);
var arr:Array;
if( ds.hasFormat("items") ) {
arr = ds.dataForFormat("items") as Array;
} else if( ds.hasFormat("treeItems") ) {
arr = ds.dataForFormat("treeItems") as Array;
}
for(var i:Number=0; i < arr.length; i++) {
var node:XML = XML(arr[i]);
var item:Object = new Object();
item.label = node.@label;
item.type = node.@type;
dataGridProvider.addItem(item);
}
onDragExit(event);
}
/**
* Intercepts the dragComplete event on the Tree control
* and prevents the default behavior from happening. This is necessary
* if the item being dragged from the Tree control is dropped on a non-Tree
* object, such as the DataGrid.
*/
private function onTreeDragComplete(event:DragEvent):void {
event.preventDefault();
}
/**
* Selects all of the items in the List if Ctrl+A is picked when the List control
* has focus.
*/
private function selectAllMaybe( event:KeyboardEvent ) : void
{
if( event.ctrlKey && event.keyCode == 65 ) {
var l:List = List(event.currentTarget);
var allItems:Array = new Array(l.dataProvider.length);
for(var i:Number=0; i < allItems.length; i++) {
allItems[i] = i;
}
l.selectedIndices = allItems;
}
}
]]>
</fx:Script>
<mx:Label x="34" y="40" text="Drag items from this Tree"/>
<mx:Label x="34" y="55" text="(items are copied)"/>
<mx:Tree x="34" y="81" width="181" height="189"
dataProvider="{treeData.node}"
labelField="@label"
dropEnabled="false"
dragEnabled="true"
dragComplete="onTreeDragComplete(event)"
dragMoveEnabled="false"
/>
<mx:Label x="291" y="55" text="Drop items from Tree here"/>
<mx:DataGrid x="291" y="81" height="189"
dragEnabled="true"
dataProvider="{dataGridProvider}"
dragEnter="onDragEnter(event)"
dragOver="onDragOver(event)"
dragDrop="onGridDragDrop(event)"
dragExit="onDragExit(event)">
<mx:columns>
<mx:DataGridColumn headerText="Label" dataField="label"/>
<mx:DataGridColumn headerText="Type" dataField="type"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
第三:从List到Tree
<?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">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
<fx:XML id="treeData" xmlns="">
<root>
<node label="Massachusetts" type="state" data="MA">
<node label="Boston" type="city" >
<node label="Smoke House Grill" type="restaurant" />
<node label="Equator" type="restaurant" />
<node label="Aquataine" type="restaurant" />
<node label="Grill 23" type="restaurant" />
</node>
<node label="Provincetown" type="city" >
<node label="Lobster Pot" type="restaurant" />
<node label="The Mews" type="restaurant" />
</node>
</node>
<node label="California" type="state" data="CA">
<node label="San Francisco" type="city" >
<node label="Frog Lane" type="restaurant" />
</node>
</node>
</root>
</fx:XML>
<fx:Array id="listData">
<fx:String>Johnny Rocket's</fx:String>
<fx:String>Jet Pizza</fx:String>
<fx:String>Steve's Greek</fx:String>
<fx:String>Sonsie</fx:String>
<fx:String>The Border Cafe</fx:String>
</fx:Array>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.DragEvent;
import mx.managers.DragManager;
import mx.core.DragSource;
import mx.core.UIComponent;
import mx.controls.Tree;
/**
* Called as soon as the dragProxy enters the target. You can add logic
* to determine if the target will accept the drop based on the
* dragInitiator, the data available in the dragSource.
* Here the drop is blindly accepted.
*/
private function onDragEnter( event:DragEvent ) : void
{
DragManager.acceptDragDrop(UIComponent(event.currentTarget));
}
/**
* Called while the dragProxy is over the drop target. You can
* use this function to determine the type of feedback to show.
* Since the List is set to allow MOVE (the item is deleted
* once dropped), different feedback possibilities are given.
*
* Also, for this application, the Tree control node the dragProxy is
* over is selected. As the dragProxy moves, the Tree control's
* selection changes.
*
* For a bit more complication, the drop is being allowed
* only over nodes whose type is NOT 'state'.
* The feedback is removed.
*/
private function onDragOver( event:DragEvent ) : void
{
var dropTarget:Tree = Tree(event.currentTarget);
var r:int = dropTarget.calculateDropIndex(event);
tree.selectedIndex = r;
var node:XML = tree.selectedItem as XML;
if( node.@type == "state" ) {
DragManager.showFeedback(DragManager.NONE);
return;
}
if (event.ctrlKey)
DragManager.showFeedback(DragManager.COPY);
else if (event.shiftKey)
DragManager.showFeedback(DragManager.LINK);
else {
DragManager.showFeedback(DragManager.MOVE);
}
}
/**
* Called when the dragProxy is released
* over the drop target. The information in the dragSource
* is extracted and processed.
*
* The target node is determined and
* all of the data selected (the List has allowMultipleSection
* set) is added.
*/
private function onDragDrop( event:DragEvent ) : void
{
var ds:DragSource = event.dragSource;
var dropTarget:Tree = Tree(event.currentTarget);
var items:Array = ds.dataForFormat("items") as Array;
var r:int = tree.calculateDropIndex(event);
tree.selectedIndex = r;
var node:XML = tree.selectedItem as XML;
var p:*;
// if the selected node has children (it is type==city),
// then add the items at the beginning
if( tree.dataDescriptor.hasChildren(node) ) {
p = node;
r = 0;
} else {
p = node.parent();
}
for(var i:Number=0; i < items.length; i++) {
var insert:XML = <node />;
insert.@label = items[i];
insert.@type = "restaurant";
tree.dataDescriptor.addChildAt(p, insert, r+i);
}
}
/**
* Called when the drag operation completes, whether
* successfully or not. The tree is cleared of its
* selection.
*/
private function onDragComplete( event:DragEvent ) : void
{
tree.selectedIndex = -1;
}
]]>
</fx:Script>
<mx:Panel x="48" y="125" width="447" height="351" layout="absolute" title="Drag onto Tree">
<mx:Tree width="186" left="10" top="10" bottom="10" id="tree"
labelField="@label"
dataProvider="{treeData.node}"
dropEnabled="false"
dragMoveEnabled="false"
dragEnter="onDragEnter(event)"
dragOver="onDragOver(event)"
dragDrop="onDragDrop(event)">
</mx:Tree>
<mx:List width="188" height="206" right="10" bottom="10" id="list"
allowMultipleSelection="true"
dataProvider="{listData}"
dragEnabled="true"
dragMoveEnabled="true"
dragComplete="onDragComplete(event)">
</mx:List>
<mx:Text x="229" y="10" text="Drag from the list below to the tree" width="188" height="39"/>
<mx:Label x="229" y="69" text="restaurants"/>
</mx:Panel>
</s:Application>
第四:Tree 到Tree及综合拖动示例
<?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:com="com.*">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.controls.listClasses.ListBase;
import mx.core.UIComponent;
import mx.controls.Tree;
import mx.collections.ArrayCollection;
import mx.core.DragSource;
import mx.managers.DragManager;
import mx.events.DragEvent;
import mx.events.TreeEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.Event;
import mx.utils.ObjectUtil;
[Bindable]
public var selectedNode:Object;
[Bindable]
public var description:String = "Directions:\n\nTo see the effect of the Spring Loaded Folders select " +
"an item in the tree and drag the item over the folders wait, hovering over the folder and " +
"it'll open.\n\nIf a folder opens and you did not want it to open move the mouse out of " +
"the tree, and it'll restore the original state. \n\nPlay around with the delay to get a " +
"desired delay.Hitting spacebar while dragging over a closed folder will open it immediately.";
public function treeChanged(event:Event):void {
selectedNode=event.currentTarget.selectedItem;
}
private function onDragOver(event:DragEvent):void{
try{
if( event.dragInitiator is ListBase ){
var list:ListBase = event.dragInitiator as ListBase;
if( event.currentTarget != event.dragInitiator){
//do what?
//trace(mx.utils.ObjectUtil.toString('[currentTarget]'+event.currentTarget));
}
if(list.indexToItemRenderer(list.calculateDropIndex(event)) != null){
var currTree:Tree = Tree(event.currentTarget);
var currNodeOver:Object;
var rowIndex:int = currTree.calculateDropIndex(event);
var hoverTarget:Object = currTree.indexToItemRenderer(rowIndex).data;
var parent:Object = currTree.getParentItem(hoverTarget);
var tattlerStr:String = new String();
var halfRow:int = currTree.rowHeight/2;
var certerRowY:int = (rowIndex*currTree.rowHeight)+halfRow;
var bottomRowY:int = (rowIndex+1)*currTree.rowHeight;
currNodeOver = currTree.indexToItemRenderer(rowIndex).data;
DragManager.showFeedback(DragManager.MOVE);
currTree.showDropFeedback(event);
//trace(ObjectUtil.toString(parent));
if( parent != null )
trace('[currTree is a tree]');
//parent.label = 'currTree is a tree';
//parentObject = currTree.getParentItem(hoverTarget);
else
trace('[currTree is a tree]');
//parent.label = 'currTree is not a tree';
//parentObject.label = 'currTree is not a tree';
tattlerStr = "Selected Item: " + selectedNode + "\n" + "Over Target: " + hoverTarget.level
+ "\n" + "Target Parent: " + 'test'//parent.label
+ "\n"
+ "calculateDropIndex " + rowIndex
+ "\n"
+ "halfRow " + halfRow.toString()
+ "\n"
+ "certerRowY " + certerRowY.toString()
+ "\n"
+ "bottomRowY " + bottomRowY.toString()
+ "\n"
+ "mouseY " + currTree.mouseY.toString()
+ "\n"
+ "isItemOpen " + currTree.isItemOpen(currNodeOver).toString()
+ "\n" + "\n";
tattler.text = tattlerStr;
}else{
tattler.text = "No Drop Buddy";
}
}
}catch(err:Error){
trace('[error]'+err);
}
}
private function onDragDrop(event:DragEvent):void{
try{
var target:Tree = Tree(event.currentTarget);
var list:ListBase = event.dragInitiator as ListBase;
var ds:DragSource = event.dragSource;
var rowIndex:int = target.calculateDropIndex(event);
var hoverTarget:Object = target.indexToItemRenderer(rowIndex).data;
var parent:Object = target.getParentItem(hoverTarget);
var items:Array = ds.dataForFormat("items") as Array;
var i:int;
//trace(event.dragInitiator);
if( event.dragInitiator is DataGrid ){
//do what?
//trace(mx.utils.ObjectUtil.toString('[currentTarget]'+event.currentTarget));
for (i=0; i < items.length; i++){
var tempObj:Object = {};
tempObj = items[i];
parent.children.addItem(tempObj);
}
event.preventDefault();
}
}catch(err:Error){
trace('[onDragDropError]'+err);
}
}
private function onDragEnter(event:DragEvent):void{
DragManager.acceptDragDrop(UIComponent(event.currentTarget));
}
[Bindable]
private var treeData:ArrayCollection = new ArrayCollection(
[ {label:"Curriculum", level:"Curr", children:new ArrayCollection(
[ {label:"cert1", level:"Cert", children:new ArrayCollection(
[{label:"c1", level:"Course", type:"prereq"},
{label:"c2", level:"Course", type:"prereq"}
])}
])},{label:"Curriculum", level:"Curr", children:new ArrayCollection(
[ {label:"cert1", level:"Cert", children:new ArrayCollection(
[{label:"c1", level:"Course", type:"prereq"},
{label:"c2", level:"Course", type:"prereq"}
])}
])}
]);
[Bindable]
private var secondTreeData:ArrayCollection = new ArrayCollection(
[ {label:"Curriculum", level:"Curr", children:new ArrayCollection(
[ {label:"cert1", level:"Cert", children:new ArrayCollection(
[{label:"c1", level:"Course", type:"prereq"},
{label:"c2", level:"Course", type:"prereq"}
])}
])},{label:"Curriculum", level:"Curr", children:new ArrayCollection(
[ {label:"cert1", level:"Cert", children:new ArrayCollection(
[{label:"c1", level:"Course", type:"prereq"},
{label:"c2", level:"Course", type:"prereq"}
])}
])}
]);
[Bindable]
private var gridDP:ArrayCollection = new ArrayCollection(
[{label:"c5", level:"Course", type:"prereq"},
{label:"c6", level:"Course", type:"prereq"},
{label:"c7", level:"Course", type:"prereq"}]);
]]>
</fx:Script>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
</fx:Declarations>
<mx:VBox width="100%" height="100%">
<mx:Canvas backgroundColor="#f3d7ab" borderColor="#000000" borderStyle="outset" width="100%" x="10" height="50%" y="10" horizontalScrollPolicy="off" verticalScrollPolicy="off">
<mx:HBox width="100%" height="100%" >
<com:SpringLoadedTree id="tree1" width="35%" height="100%"
autoCloseOpenNodes="{autoCloseOpenNodes.selected}"
autoCloseOnDrop="{autoCloseOnDrop.selected}"
autoOpenTimerMS="{DelayOpen.value}"
autoCloseTimerMS="{DelayClose.value}"
showOpeningIndication="{showOpenIdication.selected}"
autoCloseOnExit="{autoCloseOnExit.selected}"
dataProvider="{treeData}"
mouseDown="treeChanged(event)"
fontWeight="bold" color="#000000"
dragEnabled="true"
dragOver="onDragOver(event)"
dragMoveEnabled="true"
dropEnabled="true"
labelField="label" wordWrap="true"
fontSize="8" variableRowHeight="true"
x="41" y="20"/>
<com:SpringLoadedTree id="tree2" width="35%" height="100%"
autoCloseOpenNodes="{autoCloseOpenNodes.selected}"
autoCloseOnDrop="{autoCloseOnDrop.selected}"
autoOpenTimerMS="{DelayOpen.value}"
autoCloseTimerMS="{DelayClose.value}"
showOpeningIndication="{showOpenIdication.selected}"
autoCloseOnExit="{autoCloseOnExit.selected}"
dataProvider="{secondTreeData}"
mouseDown="treeChanged(event)"
fontWeight="bold" color="#000000"
dragEnabled="true"
showRoot="false"
dragDrop="onDragDrop(event)"
dragEnter="onDragEnter(event)"
dragOver="onDragOver(event)"
dragMoveEnabled="true"
dropEnabled="true"
labelField="label" wordWrap="true"
fontSize="8" variableRowHeight="true"
x="41" y="20"/>
<mx:DataGrid dataProvider="{gridDP}" id="grid1"
dragEnabled="true"
dragMoveEnabled="true" height="100%">
</mx:DataGrid>
<mx:Text text="{description}" id="Directions" enabled="true" height="100%" width="30%"/>
</mx:HBox>
</mx:Canvas>
<mx:HBox width="100%" height="50%">
<mx:TextArea x="10" y="368" width="50%" height="100%" id="tattler"/>
<mx:Canvas width="50%" height="100%" y="446" x="470">
<mx:CheckBox id="autoCloseOnDrop" selected="true" label="Return to original state on drop" left="10" right="10" bottom="96"/>
<mx:HSlider value="1000" tickInterval="200" snapInterval="200" maximum="2000" allowTrackClick="true" minimum="200" id="DelayOpen" left="255" bottom="174" width="190"/>
<mx:Label text="Folder auto open delay ms:{DelayOpen.value}" left="10" bottom="174" textAlign="left" width="248"/>
<mx:CheckBox id="showOpenIdication" selected="true" label="Show opening indication" left="10" right="10" bottom="122"/>
<mx:HSlider value="200" tickInterval="100" snapInterval="100" maximum="1000" allowTrackClick="true" minimum="100" id="DelayClose" bottom="200" width="190" left="255"/>
<mx:Label text="Folder auto close delay ms:{DelayClose.value}" left="10" bottom="200" textAlign="left" width="248"/>
<mx:CheckBox id="autoCloseOpenNodes" selected="true" label="Auto open/close folders on drag over/out" left="10" right="10" bottom="148"/>
<mx:CheckBox id="autoCloseOnExit" selected="true" label="Auto close folders on tree exit" left="10" right="10" bottom="70"/>
</mx:Canvas>
</mx:HBox>
</mx:VBox>
</s:Application>