[小站博客均为原创, 转载请保留以下信息:
作者:http://liguoliang.com 欢迎访问:Adobe上海用户组: http://riashanghai.com ]
关于Drag和Drop的基础知识与基本应用可以参见:http://livedocs.adobe.com/flex/3/html/help.html?content=dragdrop_1.html
1. 设计目标
实现Flex/AIR中的Tree,DataGrid自身或相互之间的拖动.
本例仍旧使用NoteManagement,关于NoteManagement的相关信息请参见:
1.完整Flex程序+详细解释之便条管理系统(Tree/回溯/XML/Event) Annotated Flex Sample Application: Note Management
2.使用Air与SQLite开发NoteManagement
3.Flex树形菜单动态加载 Flex Tree Dynamic Loading
通过以上三篇文章,您将对NoteManagement有一个概括性的了解.
2.概要设计:
2.1 Tree内目录拖动的实现:
如果使用Tree自带的Drag与Drop属性设定Tree,则目录之间只能实现十分局限的拖 动,如果目录不含有子目录,则其他目录无法拖动到该目录下.要解决这个问题,就必须使用自定义的itemRenderer,该itemRenderer继 承自TreeItemRenderer从而不影响Tree的其他功能的正常使用,相对来说,自定义的itemRenderer应该具有以下功能:1.在有 目录drag到itemRenderer上时他能够acceptDragDrop. 2:可以接受并处理dragDrop事件.
2.2 Note移动的实现:
使用DataGrid的属性dragEnabled属性设定DataGrid可以被drag. 当drag到目录中时,dragEnter的target acceptDragDrop,通过对相关事件的监听进行相应处理.
3.详细实现:
3.1 Tree内目录拖动:
设置Tree的属性为:dragEnabled=”true” dropEnabled=”false”
在Tree初始化完成后监听DRAG_COMPLETE事件;DragtreeCategory.addEventListener(DragEvent.DRAG_COMPLETE, onCatDragComplete);
通过使用onCatDragComplete可以阻止其默认行为preventDefault(),这样我们获得对DRAG_DROP的控制.
为 Tree建立一个自定义的itemRenderer,该itemRenderer监听DragEvent.DRAG_ENTER与 DragEvent.DRAG_DROP,通过对DRAG_ENTER的监听,控制itemRenderer是否接受Drag,通过对DRAG_DROP 的监听,将DRAG的目录加入到DROP目录中,并删除原目录,以完成整个过程.
3.2 Note的移动
设置DataGrid的属性为dragEnabled=”true”
同3.1在DataGrid初始化完成后监听DRAG_Complete,阻止默认行为并获得控制
当Drag的Note Enter到Tree中时,通过itemRenderer的监听, 控制itemRenderer是否接受DragDROP,并控制后续过程.
自定义itemRenderer的代码如下:
- package component
- {
- import com.insprise.common.sql.Connection;
- import com.insprise.common.utility.LogUtils;
- import com.insprise.common.utility.SQLUtils;
- import com.insprise.nmair.Category;
- import com.insprise.nmair.Note;
- import flash.data.SQLConnection;
- import flash.events.SQLEvent;
- import mx.controls.treeClasses.TreeItemRenderer;
- import mx.events.DragEvent;
- import mx.managers.DragManager;
- public class TreeCatItemRender extends TreeItemRenderer
- {
- public static var dragAndDropClass:int; //辨别Drag来自于Tree还是DataGrid.
- private var conn:SQLConnection = new SQLConnection();
- private var catMoved:Category;
- private var catMoveInto:Category;
- private var catEnter:Category;
- private var noteMoved:Note;
- private var noteMoveIntoCat:Category;
- private var noteEnter:Category;
- /**
- * 构造函数,每次使用该Renderer时会自动添加EventListener;
- */
- public function TreeCatItemRender() {
- super();
- this.addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
- this.addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
- }
- //在拖动到某一个Render上时,判断是否允许接受Drop;
- private function dragEnterHandler(e:DragEvent):void {
- if(e.dragSource.hasFormat(“treeItems”)) {
- dragAndDropClass = 0;
- catMoved = e.dragSource.dataForFormat(“treeItems”)[0] as Category;
- catEnter = this.data as Category;
- LogUtils.defaultLog.info(“Draged Item: ” + catMoved.label);
- LogUtils.defaultLog.info(“Enter Cat: ” + catEnter.label);
- if(catMoved.isAncestor(catEnter) || catMoved == catEnter || catMoved.parent == catEnter) {
- LogUtils.defaultLog.info(“上级目录不可移动到下级目录, 也不可移动到期自身内部”);
- return;
- }
- DragManager.acceptDragDrop(e.currentTarget as TreeCatItemRender);
- }
- else if(e.dragSource.hasFormat(“items”)) {
- dragAndDropClass = 1;
- noteMoved = e.dragSource.dataForFormat(“items”)[0] as Note;
- noteEnter = this.data as Category;
- if(noteMoved.parent == noteEnter) {
- LogUtils.defaultLog.info(“没有进行移动,不进行任何操作”);
- return;
- }
- DragManager.acceptDragDrop(this);
- trace(“Note parent.id: ” + noteMoved.parent.id );
- trace(“ Note Enter Cat id: ” + noteEnter.id);
- }
- }
- //在Drop之后 ,建立与数据库的连接,准备更新数据库.
- private function dragDropHandler(e:DragEvent):void {
- if(dragAndDropClass == 0) {
- e.preventDefault();
- catMoveInto = this.data as Category;
- LogUtils.defaultLog.info(“移动进: ” + catMoveInto.label);
- }
- else if(dragAndDropClass == 1) {
- e.preventDefault();
- noteMoveIntoCat = this.data as Category;
- LogUtils.defaultLog.info(“Note: ” + noteMoved.title + “ 被拖进了: ” + noteMoveIntoCat.label);
- }
- if(conn.connected) {
- LogUtils.defaultLog.info(“DataBase have Connected. Call UpdateDB Directly”);
- updateDB();
- return;
- }
- LogUtils.defaultLog.info(“Connect Db…..”);
- conn.addEventListener(SQLEvent.OPEN, updateDB);
- conn.openAsync(Connection.dbFile);
- }
- //建立 与数据的 连接之后Update改纪录.
- private function updateDB(e:SQLEvent=null):void {
- if(dragAndDropClass == 0) {
- var updateCatSql:String = “UPDATE Cat SET parent_ID=’” + catMoveInto.id + “‘ WHERE cat_ID
- =” + catMoved.id;
- SQLUtils.createAndExecuteStatement(conn, updateCatSql, null, updateDBSucess)
- }
- else if(dragAndDropClass == 1) {
- var updateNotesql:String = “UPDATE Note SET parent_ID=’” + noteMoveIntoCat.id +
- “‘ WHERE note_ID=” + noteMoved.id;
- SQLUtils.createAndExecuteStatement(conn, updateNotesql, null, updateDBSucess)
- }
- }
- //Update成功后,移动目录或note
- private function updateDBSucess(e:SQLEvent):void {
- if(dragAndDropClass == 0) {
- LogUtils.defaultLog.info(catMoved.label + “ 的parent_ID已成功更新为: ” + catMoveInto.id);
- catMoveInto.addSubCat(catMoved);
- LogUtils.defaultLog.info(“目录: ” + catMoveInto.label + “ 成功添加子目录: ” + catMoved.label);
- }
- else if(dragAndDropClass == 1) {
- LogUtils.defaultLog.info(noteMoved.title + “的parent_ID已成功更新为: ” + noteMoveIntoCat.id);
- noteMoveIntoCat.addNote(noteMoved);
- LogUtils.defaultLog.info(“目录: ” + noteMoveIntoCat.label + “ 成功添加Note: ” + noteMoved.title);
- }
- }
- }
- }
在move情况下,我们把目标加入到Drop target中,并从Drag initiator中删除,使用dragDrop事件的监听函数来加入目标到Drop target, 使用dragComplete事件的监听函数来删除drag initiator中的源数据.
在这个例子中,由于在 addCat()与addNote()中以含有删除功能,故我们阻止了dragComplete,使用dragDrop处理增加与删除.addCat() 与addNote通过判断源数据的parent是否等于Drop target的id来进行对应处理.
在移动后元数据的parent与Drop target中的Category是不同的,这种情况下先将其删除,修改其parent属性后再加入到Drop target的Category中.完成操作.
代码如下:
- /**
- * Adds the given child.
- * If the child has an existing parent, it will be removed from its parent first then added to this.
- */
- public function addSubCat(child:Category):void {
- if(this.subCats == null) {
- subCats = new ArrayCollection();
- }
- if(child.parent == null) { // initial
- child._parent = this;
- subCats.addItem(child);
- }else{ // not null
- if(child.parent == this) {
- throw new Error(“The parent has already been set to this: ” + toString() + “, child: ” + child);
- }else{ // change parent.
- child._parent.delCat(child);
- child._parent = this;
- subCats.addItem(child);
- }
- }
- }
- //删除子目录.须提供一个index,通过findCatIndex函数寻找.
- /**
- * Remove the given child category and set the removed category’s parent to null.
- * @throw Error if the child’s parent is not this.
- */
- public function delCat(child:Category):void {
- trace(“This.id: ” + this.id);
- trace(“child’s Parent ID: ” + child.parent.id);
- trace(child._parent.subCats.getItemIndex(child));
- if(child._parent != this) {
- throw new Error(“The parent of the child is not this: ” + toString() + “, child: ” + child);
- }
- subCats.removeItemAt(subCats.getItemIndex(child));
- child._parent = null;
- }
- /**
- * 增加Note
- * 如果category的notes为空,则新建notes
- * 如果note的parent为空,则将this赋给note的parent [Note初始化时发生]
- * 如果note的parent为this,则为重复添加.报错处理 [重复添加Note,报错]
- * 如果note的parent不等于this,则说明是移动过来的note,需要在该note原先的parent下删除该note,并将该note添加到this的notes中.
- */
- public function addNote(note:Note):void {
- if(notes == null) {
- notes = new ArrayCollection();
- } else if(note.parent == null) {
- note.parent = this;
- notes.addItem(note);
- } else{
- if(note.parent == this) {
- throw new Error(note.title + “ 的parent已经被设定为” + this.label);
- } else{
- note.parent.delNote(note);
- note.parent = this;
- notes.addItem(note);
- }
- }
- }
- /**
- * 删除note
- * 如果note的parent不为this,则报错
- * 否则删除该note
- * 并将note parent为空.
- */
- public function delNote(note:Note):void {
- if(note.parent != this) {
- throw new Error(note.title + “ note的parent不是this ” + this.label);
- }
- notes.removeItemAt(notes.getItemIndex(note));
- note.parent = null;
- }



Lovely. Great site.
Sehr gute Seite. Ich habe es zu den Favoriten.