随笔-9  评论-15  文章-0  trackbacks-0

20.Working with Tree Controls使用Tree控件
初次翻译,错误之处必然不少,敬请见谅。
翻译日期:2008-03-01
译者:ShiLiangShuai(http://hi.baidu.com/shiliangshuai)
Flex版本:3
原文地址:http://www.adobe.com/devnet/flex/quickstart/working_with_tree/
所处章节:Flex Developer Center -> Flex Quick Starts -> Working with Tree controls
要看程序运行效果请查看原文,或自己手工编译程序。

Tree控件是一个枝和叶节点分层次的机构。树中没每一个条目叫做节点,节点既可以作为枝也可以作为叶。枝节点可以包含叶或枝节点,或者为空。一个叶节点就是一个树的末梢。本快速指南包含一些开发者在使用Treecontrols经常会遇到的一些挑战。
使用XMLLISTCOLLECTION 和ARRAYCOLLECTION对象的对比。
你也许想知道,在运行时从远程或本地得来的数据被动态修改的时候,应该使用XMLListCollection对象还是ArrayCollection对象作为Tree空间的数据提供者。
如果你使用的数据源提供成形的XML,并且,你想在Tree控件中操作 XML数据。你应该使用XMLListCollection对象作为数据提供者。当使用MXML标记时,如果数据源是XMLList对象,你应该把它绑定到XMLLsitCollection对象的source属性上,然后把 XMLListCollection对象绑定到Tree控件的dataProvider属性上。当你想要动态改变对象值时,不要使用XMLList或XML对象直接绑定到Tree控件的dataProvider属性上。
当数据源是RPC(远程过程调用)服务的lastResult属性,并且你想使用XML数据,确保RPC组件的resultFormat属性被设置成e4x,当你使用e4x结果格式,最总结果就是XMLList,可以绑定在XMLListCollection对象上。这里 有一个例子。
为例数据被动态改变,使用ArrayCollection对象作为Tree控件的数据提供器。当使用MXML标记时,如果你期望动态的改变Arrayl,你不应该把Array对象直接绑定到Tree控件的dataProvider属性上。作为代替,你应该绑定Array到一个ArrayCollection对象的source属性上,然后再把ArrayCollection对象绑定到Tree控件的dataProvider属性上。
当数据源是RPC(远程过程调用)服务的lastResult对象,并且RPC组件的resultFormat属性被成object,你应该使用ArrayUtil.toArray()方法来确保对象是一个Array。然后绑定到ArrayCollection对象上,就像下边的例子所示:
<mx:ArrayCollection
    id="employeeAC"
    source= "{ArrayUtil.toArray(employeeSrv.lastResult.employees.employee)}"/>
在运行时增加和删除叶子节点
你可以在运行时为Tree控件增加或删除叶子节点。下边的例子包含的代码来实现这种改变。这个程序使用预定义的枝和叶来初始化,表现公司部门和员工。你可以向任意枝节点增加叶节点在运行时。你也可以删除预定义的叶节点和你在运行时增加的节点。
在这个例子中的XML包含两种不同的元素名字,department和employee。Tree控件的label函数,决定根据元素的类型应该显示那些文本。它使用了E4X语法来返回department的title,或者employee的name。然后,这些语法在addEmployee()和removeEmployee()中会用到。
为了增加员工到业务部门,addEmployee()方法使用E4X语法,通过title属性的值获得业务部门的节点,并把它保存到XMLList类型的变量dept中。然后,通过调用dept.appendChild()方法向操作节点添加子结点。
remove方法保存当前被选择的元素到变量node中,node的类型是XML。调用node.localName()方法确定被选择的元素是否是employee节点。如果是employee节点,删除它。
Example
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">
  
    <mx:Script>
        <![CDATA[            import mx.collections.XMLListCollection;
          
            [Bindable]
            private var company:XML =
              <list>
                <department title="Finance" code="200">
                    <employee name="John H"/>
                    <employee name="Sam K"/>
                </department>
                <department title="Operations" code="400">
                    <employee name="Bill C"/>
                    <employee name="Jill W"/>
                </department>                  
                <department title="Engineering" code="300">
                    <employee name="Erin M"/>
                    <employee name="Ann B"/>
                </department>                              
              </list>;
          
            [Bindable]
            private var companyData:XMLListCollection = new XMLListCollection(company.department);
          
            private function treeLabel(item:Object):String
            {
                var node:XML = XML(item);
                if( node.localName() == "department" )
                    return node.@title;
                else
                    return node.@name;
            }
            private function addEmployee():void
            {
                var newNode:XML = <employee/>;
                newNode.@name = empName.text;
                var dept:XMLList =company.department.(@title == "Operations");
                if( dept.length() > 0 ) {
                    dept[0].appendChild(newNode);
                    empName.text = "";
                }
            }
            private function removeEmployee():void
            {
                var node:XML = XML(tree.selectedItem);
                if( node == null ) return;
                if( node.localName() != "employee" ) return;
          
                var children:XMLList = XMLList(node.parent()).children();
                for(var i:Number=0; i < children.length(); i++) {
                    if( children[i].@name == node.@name ) {
                        delete children[i];
                    }
                }
            }
        ]]>
    </mx:Script>
  
    <mx:Tree id="tree" top="72" left="50" dataProvider="{companyData}"
        labelFunction="treeLabel"
         height="224" width="179"/>
    <mx:HBox>      
        <mx:Button label="Add Operations Employee" click="addEmployee()"/><mx:TextInput id="empName"/>
    </mx:HBox>
    <mx:Button label="Remove Selected Employee" click="removeEmployee()"/>  
</mx:Application>
在运行时添加一个空的枝节点
可以在运行时向Tree控件添加空的枝节点。下边的例子展示了通过数据提供器(data provider)API和数据描述器(data descriptor )API添加枝节点。通常,添加枝节点的首选途径是通过数据提供器(data provider)API。
addEmptyBranthDP()方法通过数据提供器API向使用XML数据提供器的Tree组件增加一个空节点,这个方法为新节点创建一个XML类型的变量,并且设置这个节点的isBranch属性为true来创建一个枝节点。然后这个方法调用Tree控件的dataProvider.addItemAt()方法来向Tree控件的数据提供器增加新的元素。
addEmptyBranchDP2()方法通过数据提供器API向使用对象数据提供器的Tree组件增加一个空节点,这个方法使用children属性创建一个新的对象,使用children属性能够确保isBranch()方法返回true。然后,这个方法调用Tree控件的dataProvider.addItemAt()方法来向Tree控件的数据提供器增加新的对象。
addEmptyBranchDD()方法通过数据描述器(data descripter)API。这个方法创建一个XML类型的变量,并且设置isBranch属性为true来创建一个枝节点。然后,这个方法调用Tree控件的dataDescriptor.addChildAt()方法来向Tree控件的数据描述器添加一个新的子节点。
Example
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">    <mx:Script>
        <![CDATA[
            [Bindable]
            private var dataX:XML =
                <item label="Top">
                <item label="Child One"/>
                <item label="Child Two" />
            </item>;
      
            [Bindable]
            private var dataObj:Object =
                [{label:"Top", children:
                [
                {label:"Child One"}, {label: "Child Two"}
                ]
                }];
      
            // Adding a branch by going through the Tree control's dataProvider. This is
            // the preferred method.
            // Toggling the isBranch attribute to true causes DefaultDataDescriptor.isBranch()
            // to return true and the Tree treats the node as a branch.
            private function addEmptyBranchDP():void
            {
                var newNode:XML = <item label='Middle' isBranch="true"></item>;
                xmlBound2Tree.dataProvider.addItemAt(newNode, 1);
            }
      
            // For an object graph, the key point is that the children property needs to be defined,
            // even if it is empty.
            // This causes isBranch() to return true and the Tree treats the new node as a branch.
            private function addEmptyBranchDP2():void
            {
                var newObj:Object = {label:"Middle", children:[]};
                objGraphBound2Tree.dataProvider.addItemAt(newObj, 1);
            }
      
            // Adding a branch by going through the Tree control's dataDescriptor.
            private function addEmptyBranchDD():void
            {
                var newNode:XML = <item label='Child 4' isBranch="true"></item>;
                xmlBound2Tree.dataDescriptor.addChildAt(dataX, newNode, 2, dataX);
            }
          ]]>
    </mx:Script>
    <mx:Label text="Tree with XML data"/>
    <mx:Tree id="xmlBound2Tree" dataProvider="{dataX}" labelField="@label" showRoot="true" width="200"/>
    <mx:Button label="Add Empty Branch through the dataProvider" click="addEmptyBranchDP();"/>
    <mx:Button label="Add Empty Branch through the dataDescriptor" click="addEmptyBranchDD();"/>
    <mx:Spacer height="10"/>
    <mx:Label text="Tree with object data"/>
    <mx:Tree id="objGraphBound2Tree" dataProvider="{dataObj}" width="200"/>
    <mx:Button label="Add Empty Branch through the dataProvider" click="addEmptyBranchDP2();"/>  
</mx:Application>
打开树到指定的节点
默认的,Tree控件在初始化后是收缩的,你也许不确定如何初始化控件时展开数,并且选定指定的节点。下边的例子,展示了如何实现它。在这个程序中,initTree()方法,在Tree控件被创建后调用。这个方法展开Tree控件的根节点,并且设置selectedIndex属性为指定节点的索引号。
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">    <mx:Script>
        <![CDATA[
            import flash.events.*;
            import mx.events.*;
            import mx.controls.*;
            private function initTree():void {
                XMLTree1.expandItem(MailBox.getItemAt(0), true);
                XMLTree1.selectedIndex = 2;
            }
        ]]>
    </mx:Script>
    <mx:Tree id="XMLTree1" width="150" height="170"
             labelField="@label" creationComplete="initTree();">
        <mx:XMLListCollection id="MailBox">
            <mx:XMLList>
                <node label="Mail" data="100">
                    <node label="Inbox" data="70"/>
                    <node label="Personal Folder" data="10">
                        <node label="Business" data="2"/>
                        <node label="Demo" data="3"/>
                        <node label="Saved Mail" data="5" />
                    </node>
                    <node label="Sent" data="15"/>
                    <node label="Trash" data="5"/>
                 </node>
            </mx:XMLList>
        </mx:XMLListCollection>
</mx:Tree>
</mx:Application>
读取多节点名XML文档
你可以从具有多个节点名字的XML文档中组装Tree 控件。下边的例子实现了这个功能。Tree控件的数据提供者是一个XMLListCollection,它组装自一个包含folder和Pfolder元素的XMLList。Tree控件的labelField属性被设置为label属性,不管元素叫什么名字,这个属性对XMLList中的所有属性都是公共的。
Example
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="src/index.html">
    <mx:Tree id="tree1" dataProvider="{MailBox}" labelField="@label" showRoot="true" width="160"/>
    <mx:XMLListCollection id="MailBox" source="{Folders}"/>
     <mx:XMLList id="Folders">
        <folder label="Mail">
            <folder label="INBOX"/>
            <folder label="Personal Folder">
                <Pfolder label="Business" />
                <Pfolder label="Demo" />
                <Pfolder label="Saved Mail" />
            </folder>

            <folder label="Sent" />
            <folder label="Trash" />
        </folder>
    </mx:XMLList>   
</mx:Application>
当数据提供器更新时保持Tree控件打开
默认地,当数据提供器更新数据时Tree控件收缩。下边的例子展示了当数据提供器更新时保持Tree控件打开的方法。
在这个应用程序中,当一个用户单击Button控件时changeProvider()方法更新数据提供器。通常,这会导致Tree控件收缩。然而,Tree控件的渲染事件处理器,renderTree()方法,放置收缩的发生。当changerProvider()方法被调用,当前状态是打开的元素被保存到对象open变量中。当数据被刷新时,被命名为refreshData的Boolean类型的变量被置为true。renderTree()方法调用Tree控件的invalidateList()方法来刷新树的行。然后置refreshDate属性为false,并且重置Tree控件的打开元素属性为open对象变量,这个变量在刷新前就包含了状态是打开的元素。
Example
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" initialize="initTree()" viewSourceURL="srcview/index.html">

    <mx:Script>
        <![CDATA[
            [Bindable]
            public var open:Object = new Object();
            [Bindable]

            public var refreshData:Boolean = false;
            [Bindable]
            public var switchObj:Object = new Object();
            [Bindable]

            public var firstObj:Object = new Object();
            [Bindable]

            public var firstObj1:Object = new Object();
            [Bindable]

            public var firstObj2:Object = new Object();
            [Bindable]

            public var provider:String = "firstObj";

            private function initTree():void

            {

                firstObj = new Object();
                firstObj.label = "Foods";
                firstObj.children = new Array();
                firstObj1.label = "Fruits";
                firstObj1.children = new Array();
                firstObj2.label = "Oranges";
                firstObj1.children[0] = firstObj2;
                firstObj.children[0] = firstObj1;
                switchObj = firstObj;
            }

            public function changeProvider():void
            {
                open = SampleTree.openItems;
                refreshData = true;
                if (provider == "firstObj")

                {
                    provider = "switchObj";
                    SampleTree.dataProvider = switchObj;
                }
                else

                {
                    provider = "firstObj";
                    SampleTree.dataProvider = firstObj;
                }
            }

            public function renderTree():void{
                if(refreshData){

                    // Refresh all rows on next update.
                    SampleTree.invalidateList();
                    refreshData = false;
                    SampleTree.openItems = open;
                    // Validate and update the properties and layout
                    // of this object and redraw it, if necessary.
                    SampleTree.validateNow();
                }

            }
        ]]>
    </mx:Script>
    <mx:Tree id="SampleTree" render="renderTree()" width="250" dataProvider="{firstObj}" labelField="label" />

    <mx:Button label="Change Data Provider" click="changeProvider()"/>
</mx:Application>

posted on 2008-11-21 09:57 LaoH 阅读(1309) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: