Tree 中的拖放 第一部分
这篇文章是关于如何放叶子节点——或者更确切地说是如何拖放叶子节点的。
因为这是一个有点复杂的主题而blog的文章不应该长达几页,所以我将这个主题分成了几篇文章。我将会讲述在一个Tree控件内的拖放,从一个Tree控件到其他地方的拖放,以及从其他地方到一个Tree控件的拖放。
如果你正在使用一个Tree控件那么你肯定已经确定了使用哪一种类型的数据:XMLListCollection 或者 ArrayCollection(请看Tree 控件的DataProviders,(这篇我已经翻译过了,译注)).不管你使用哪一种Tree的结构都是分等级的。这对XML来说非常理想,而对于ArrayCollections你则需要使用包含ArrayCollections子节点的ArrayCollections来提供这种结构。
我之所以提到这些,是为了让那些以前没有使用过Tree控件的人熟悉一下如何为Tree提供数据。由于我相信多数程序都使用XML作为Tree的数据,所以这些拖放的例子也将使用XML。
在一个Tree内进行拖放
让一个Tree控件允许用户进行拖拽节点来重新排列是非常简单的事情。想一下这样一个文件浏览器,你可以将文件从一个文件夹拖拽到另一个文件夹中。
这样设定你的Tree控件:
程序代码
<mx:Tree x="162" y="122" width="279" height="278"
dataProvider="{treeDataList}"
labelField="@label"
dragEnabled="true"
dragMoveEnabled="true"
dropEnabled="true"
/>
通过将dragMoveEnabled 和 dropEnabled 设定为 true,Tree中的节点就可以被拖拽了。
DragSource
在讨论拖放之前,理解DragSource是很重要的。在拖拽事件处理器的事件(mx.events.DragEvent)参数中提供了一个该类的实例。DragSource包含了很多东西,其中包括对拖拽操作的启动控制,数据的格式以及通过格式对数据的访问。
比如,如果你从一个目录里拖拽了一个条目,DragSource的数据可能是该条目的一个图像以及关于该条目的数据。所以DragSource有两种格式:图像和数据项(items)。
在下面的这些例子中你将会看到 ”items” 被用来作为格式的名字来访问DragSource中的数据。像Tree,DataGrid,以及List等Flex控件在自动创建一个DragSource的时候,都是用 ”item” 作为格式的名字的。
拖拽到一个Tree
使用 dropEnabled="true" 可以使得Tree控件接收拖拽事件并且监听下面的事件:
程序代码
<mx:Tree x="162" y="122" width="279" height="278"
dataProvider="{treeDataList}"
labelField="@label"
dropEnabled="true"
dragEnter="onDragEnter(event)"
dragOver="onDragOver(event)"
dragDrop="onDragDrop(event)"
/>
当鼠标将对象拖拽到Tree上时会分派dragEnter事件。Tree必须确定是否接受该拖拽。这是因为设定了dragEnabled并不是说所有的拖拽都会被接受。此外,dragEnter事件还可以利用事件中的信息——比如拖拽的启动控制(叫做dragInitiator)或者被拖拽的数据。
这里有一个简单的dragEnter事件处理器:
程序代码
private function onDragEnter( event:DragEvent ) : void
{
DragManager.acceptDragDrop(UIComponent(event.currentTarget));
}
当鼠标将对象拖拽进入Tree的框架内的时候会分派dragOver事件。你可以忽略这个事件,但是你也可以使用它来为用户提供反馈。比如,可以将鼠标下的节点设置为高亮。你甚至可以查看正在被拖拽的节点和鼠标下节点的数据来判断这次拖拽是否被允许。例如,如果一个Tree是关于汽车经销的,现在你将一辆跑车拖到Tree上面,如果将跑车拖到了小型货车目录上面的话你可以改变拖拽的鼠标指针来通知用户那里不允许进行此次拖拽。
下面是一个dragOver事件触发器,它判定哪一个节点在鼠标下并给出相应信息:
程序代码
private function onDragOver( event:DragEvent ) : void
{
// r is the visible index in the tree
var dropTarget:Tree = Tree(event.currentTarget);
var r:int = dropTarget.calculateDropIndex(event);
tree.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 = tree.selectedItem as XML;
if( node.@type == "minivan" ) {
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);
}
}
当放开鼠标的时候会分派dragDrop事件。Tree也可以忽略这个事件(因为用户可能错误地在小型货车目录上放开了鼠标),但是这个事件将被拖拽的数据复制给Tree。你可以利用全部或部分数据,也可以不利用。你可以创建节点或者替换节点甚至创建新的分支——这些取决于你的程序设计。
程序代码
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. 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 = 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();
}
// 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";
tree.dataDescriptor.addChildAt(p, insert, r+i);
}
}
dragComplete事件是在拖拽启动器(例如:一个列表)中注册的,当拖拽操作结束的时候会调用它 —— 在拖拽被接受并处理时,或拖拽被拒绝时,或者在用户将对象拖拽到一个不允许拖拽的区域中时。
在下面的例子中,所作的唯一一件事情就是清除dragOver 和dragDrop 操作在tree中做的选择。
private function onDragComplete( event:DragEvent ) : void
{
tree.selectedIndex = -1;
}
总结
将信息拖拽到一个Tree控件时需要确定该拖拽是否会被接受。这个可以在dragEnter事件的开始检测,也可以在dragOver事件中被拖拽对象移动到Tree控件上面时动态地检测。
[文章热度:]
下一页:Tree 中的拖放2