Tree Control DataProviders

简介:

Lately I've been thinking of trees. Maybe it's because it is autumn in the northern hemisphere. So it seems an appropriate time to talk about Flex Tree controls. I'm going to publish a small series on the Flex 2.0 Tree component as there is a lot of ground to cover. In this series I'll present information on Tree dataProviders, itemRenderers, and drag-and-drop.

Data Providers

The Tree uses heirarchical data. That is, data that has levels: nodes that are branches and leaves. The DataGrid, by contrast, presents non-heirarchical data as does the List control.

XMLListCollection is an excellent dataProvider for the Tree and is the most commonly used class for this purpose. You can also use ArrayCollection and I'll go into more detail on that later in this article.

XML is a good because it is, by nature, heirarchical. Consider this simple XML:

[Bindable]
var company:XML =
<node>
    <node label="Finance" dept="200">
        <node label="John H" />
        <node label="Sam K" />
    </node>
    <node label="Engineering" dept="300">
         <node label="Erin M" />
        <node label="Ann B" />
    </node>
    <node label="Operations" dept="400" isBranch="true" />
 </node>

You can easily see the Tree structure in that XML. But also notice something else: all of the elements in the XML are <node /> elements. Every element is the same in that it has the name "node" and it has a label; branches and leaves as well. If you need to have a node that should be a branch but has no leaves, use isBranch="true" to tell the Tree the node should be treated like a branch.

The Tree likes this very much. You can give that XML to the Tree and you will see that structure without any fuss. But is this realistic to ask that all of the nodes in the data be the same? Consider this XML:

[Bindable]
var company:XML =
<list>
    <department title="Finance" code="200">
        <employee name="John H" />
        <employee name="Sam K" />
    </department>
    <department title="Engineering" code="300">
       <employee name="Erin M" />
       <employee name="Ann B" />
    </department>
    <department title="Operations" code="400" isBranch="true" />
</list>

This XML is not uniform. If you give this to a Tree component you will get the XML dumped in the control because the Tree doesn't know what to do with it without extra instructions.

This XML can be displayed in the Tree with the help of a labelFunction.

private function treeLabel( item:Object ) : String
{
     var node:XML = XML(item);
     if( node.localName() == "department" ) 
         return node.@title;
     else  
         return node.@name;
}

The labelFunction simply returns the value of the name or title attribute depending on the type of node it is.

XMLListCollection

Earlier I mentioned XMLListCollection as a good dataProvider for the Tree, but I've been using XML so far. Here is the proper way to supply the Tree with data:

[Bindable]
var companyList:XMLListCollection = new XMLListCollection( company.department );
...
<mx:Tree dataProvider="{companyList}" labelFunction="treeLabel" />

An XMLListCollection is better as a dataProvider because the Tree can manipulate it (for editing, drag-and-drop, etc.) and because changes to the XMLListCollection are reflected in the Tree. That is, if I were to change the company XML object, you would not see the change in the Tree. If change the XMLListCollection, companyList, then not only would the underlying XML be changed, but so would the Tree.

Use XMLListCollection to supply the Tree with its data; you can change the collection and both the Tree and underlying XML will get changed, too.
If you cannot supply a very uniform XML structure to the Tree, use a labelFunction (or itemRenderer, but that's coming later) to supply the label for the display.

ArrayCollection

You can also use an ArrayCollection for the Tree. You can make an ArrayCollection heirarchical by embedding one ArrayCollection inside another:

[Bindable]
private var companyData:ArrayCollection = new ArrayCollection(
[ {type:"department", title:"Finance", children:new ArrayCollection(
                                                        [ {type:"employee", name:"John H"},
                                                          {type:"employee", name:"Sam K"} ] ) },
   {type:"department", title:"Engineering", children: new ArrayCollection(
                                                       [ {type:"employee", name:"Erin M"},
                                                         {type:"employee", name:"Ann B"} ] ) },
   {type:"department", title:"Operations", children: new ArrayCollection()}
] );

With this structure you'll notice that whenever a node has children, the name of the field is children - the Tree looks for this to identify branches from leaves.

You will also need a labelFunction with this data, too, so the Tree knows what to display on each node:

private function treeLabel( item:Object ) : String
{
     if( item.type == "department" ) 
         return item.title;
     else 
         return item.name;
}

Adding Nodes

You make changes to the Tree through the dataProvider, not through the Tree control itself. When you want to add a node you add it to the dataProvider and the Tree will be changed automatically.

To add a node to the XMLListCollection you need to have a handle on the parent node. For example, to add a new department which is a top-level node, you can do that like this:

var newNode:XML = <department title="Administration" code="500" >
                                       <employee name="Mark C" />
                              </department>;
companyList.addItem(newNode);

Here is how to add a new employee to the existing Operations department:

var newNode:XML = <employee name="Beth T" />;
var dept:XMLList =company.department.(@title == "Operations");
if( dept.length() > 0 ) {
     dept[0].appendChild(newNode);
}

Once you identify a specific node and have its XML equivalent, you can use the appendChild() method.

To add a node to the ArrayCollection you just append it to whatever part of the structure requires the node. Here's how to add a new department (top-level) node:

var newNode:Object = {type:"department",title:"Administration"};
var newEmployee:Object = {type:"employee",name:"Mark C"};
newNode.children = new ArrayCollection( [newEmployee] );
companyData.addItem(newNode);

Here is how to add a new employee to the existing Operations department:

var newNode:Object = {type:"employee", name:"Beth T"};

for(var i:Number=0; i < companyData.length; i++) {
     var item:Object = companyData.getItemAt(i);
     if( item.title == "Operations" ) {
         var children:ArrayCollection = item.children;
         children.addItem(newNode);
         companyData.itemUpdated(item);
         empName.text = ""; 
         break;
     }
}

As you can see, using an ArrayCollection to add a node is a bit more complicated than using XML.

Removing Nodes

If you know you are removing a top-level node you can do that through the XMLListCollection's removeItemAt() method - but you have to know the index of the item. In the following example, all you know is the name, "Operations", so you have to loop through the nodes and when a match is found, remove the item.

var deptTitle:String = "Operations";
for(var i:Number=0; i < companyData.length; i++) {
     var item:XML = XML(companyData.getItemAt(i));
     if( item.@title == deptTitle ) {
         companyData.removeItemAt(i);
         break;
     }
}

Removing the selected top-level node little easier:

var index:Number = tree.selectedIndex;
companyData.removeItemAt(index);

Here is how to remove a leaf node:

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];
     }
}

The same technique applies for ArrayCollection in that you have to search for the item, but once you find it you can use the ArrayCollection removeItemAt() method since the index is always valid for an ArrayCollection.

Here's how to remove a leaf node if the Tree's dataProvider is an ArrayCollection:

var node:Object = tree.selectedItem;
if( node == null ) return;
if( node.type != "employee" ) return;

var children:ArrayCollection = node.parent().children() as ArrayCollection;
for(var i:Number=0; i < children.length; i++) {
     if( children[i].name == node.name ) {
         children.removeItemAt(i);
         break; 
     }
}

t is not possible to give a Collection a node of the Tree data and have the Collection remove it - you must hunt for it and delete it yourself. 




    本文转自 OldHawk  博客园博客,原文链接

http://www.cnblogs.com/taobataoma/archive/2008/01/10/1033052.html

:,如需转载请自行联系原作者


相关文章
|
机器学习/深度学习
Data Structures (五) - 二叉树Binary Tree
Data Structures (五) - 二叉树Binary Tree
Data Structures (五) - 二叉树Binary Tree
PAT (Advanced Level) Practice - 1043 Is It a Binary Search Tree(25 分)
PAT (Advanced Level) Practice - 1043 Is It a Binary Search Tree(25 分)
104 0
|
存储 算法
PAT (Advanced Level) Practice - 1151 LCA in a Binary Tree(30 分)
PAT (Advanced Level) Practice - 1151 LCA in a Binary Tree(30 分)
107 0
PAT (Advanced Level) Practice - 1127 ZigZagging on a Tree(30 分)
PAT (Advanced Level) Practice - 1127 ZigZagging on a Tree(30 分)
100 0
|
索引 Python
Data Structure_树
线段树Segment Tree 对于有一类问题,时常关注的是一个区间或者是一个线段,那么就可以使用线段树来解决。比较经典的问题,就是区间染色问题:有一面墙,长度为n,每次选择一段墙来染色,一开始4-6绘制成黄色,然后1-10绘制蓝色,2-7绘制红色,若干次绘色之后能看见多少种颜色,或者是在区间「i,j」区间里面可以看到多少种颜色。
960 0
1110. Complete Binary Tree (25)
#include #include #include #include using namespace std; struct node { int ad, l, r; }; vector visited(20, ...
959 0
|
机器学习/深度学习
1064. Complete Binary Search Tree (30)
#include #include #include using namespace std; const int maxn = 1001; vector num(maxn), cbt(maxn); int n, c...
825 0