转自:http://www.riafan.com/article/flex/spark-datagrid-with-support-for-drag-and-drop.html
上面的网址有源码,是在上面做了dragMove修复,修复了 drop到一个 button时 datagrid的 selecteditem数据会被移除的问题
和 新增 dragsouce 的 items属性 更像mx的DataGrid的drag特性呢
DNDragDataGrid.as
package com.dn.components.datagrid
{
import flash.display.DisplayObject;
import flash.geom.Point;
import mx.collections.ArrayList;
import mx.core.DragSource;
import mx.core.IFactory;
import mx.core.IFlexDisplayObject;
import mx.events.DragEvent;
import mx.managers.DragManager;
import spark.components.DataGrid;
import spark.components.Group;
import spark.components.gridClasses.CellPosition;
import spark.components.gridClasses.GridColumn;
import spark.components.gridClasses.IGridItemRenderer;
import spark.events.GridEvent;
/**
*
* @author Hugo.Wang
* 2012-6-15 17:25:25
*/
public class DNDragDataGrid extends DataGrid
{
public function DNDragDataGrid()
{
super();
addEventListener(GridEvent.GRID_MOUSE_DRAG, startDragDrop);
}
private var dropIndex:int;
private var dropIndicator:DisplayObject;
private var _dragEnabled:Boolean = false;
[Inspectable(defaultValue="false")]
public function get dragEnabled():Boolean
{
return _dragEnabled;
}
public function set dragEnabled(value:Boolean):void
{
if (value == _dragEnabled)
return;
_dragEnabled = value;
if(_dragEnabled)
{
addEventListener(DragEvent.DRAG_COMPLETE, dragCompleteHandler);
}
else
{
removeEventListener(DragEvent.DRAG_COMPLETE, dragCompleteHandler);
}
}
private var _dragMoveEnabled:Boolean = false;
[Inspectable(defaultValue="false")]
public function get dragMoveEnabled():Boolean
{
return _dragMoveEnabled;
}
public function set dragMoveEnabled(value:Boolean):void
{
_dragMoveEnabled = value;
}
private var _dropEnabled:Boolean = false;
[Inspectable(defaultValue="false")]
public function get dropEnabled():Boolean
{
return _dropEnabled;
}
public function set dropEnabled(value:Boolean):void
{
if (value == _dropEnabled)
return;
_dropEnabled = value;
if(_dropEnabled)
addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
else
removeEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
}
private var _draggableColumns:Boolean = false;
[Inspectable(defaultValue="false")]
public function get draggableColumns():Boolean
{
return _draggableColumns;
}
public function set draggableColumns(value:Boolean):void
{
_draggableColumns = value;
}
private function startDragDrop(event:GridEvent):void
{
if (DragManager.isDragging)
return;
if (event.rowIndex == -1 && event.itemRenderer)
// dragging headers
startColumnDragDrop(event);
else
startRowDragDrop(event);
}
private var dragColumn:GridColumn;
protected function startColumnDragDrop(event:GridEvent):void
{
if(!(draggableColumns))
{
return;
}
dragColumn = event.column;
var ds:DragSource = new DragSource();
ds.addData(dragColumn, "spark.components.gridClasses.GridColumn");
var factory:IFactory = dragColumn.headerRenderer;
if (!factory)
factory = columnHeaderGroup.headerRenderer;
var renderer:IGridItemRenderer = IGridItemRenderer(factory.newInstance());
renderer.visible = true;
renderer.column = dragColumn;
renderer.label = dragColumn.headerText;
var currentRenderer:IGridItemRenderer = columnHeaderGroup.getHeaderRendererAt(event.columnIndex);
renderer.width = currentRenderer.width;
renderer.height = currentRenderer.height;
renderer.x = currentRenderer.x;
renderer.y = currentRenderer.y;
renderer.prepare(false);
DragManager.doDrag(this, ds, event, renderer as IFlexDisplayObject);
renderer.owner = this;
columnHeaderGroup.addEventListener(DragEvent.DRAG_ENTER, columnDragEnterHandler)
columnHeaderGroup.addEventListener(DragEvent.DRAG_COMPLETE, columnDragCompleteHandler);
}
protected function columnDragEnterHandler(event:DragEvent):void
{
if (event.dragSource.hasFormat("spark.components.gridClasses.GridColumn"))
{
columnHeaderGroup.addEventListener(DragEvent.DRAG_OVER, columnDragOverHandler);
columnHeaderGroup.addEventListener(DragEvent.DRAG_EXIT, columnDragExitHandler);
columnHeaderGroup.addEventListener(DragEvent.DRAG_DROP, columnDragDropHandler);
showColumnDropFeedback(event);
DragManager.acceptDragDrop(columnHeaderGroup);
}
}
protected function columnDragOverHandler(event:DragEvent):void
{
if (event.dragSource.hasFormat("spark.components.gridClasses.GridColumn"))
{
showColumnDropFeedback(event);
DragManager.acceptDragDrop(columnHeaderGroup);
}
}
protected function columnDragExitHandler(event:DragEvent):void
{
columnHeaderGroup.removeEventListener(DragEvent.DRAG_OVER, columnDragOverHandler);
columnHeaderGroup.removeEventListener(DragEvent.DRAG_EXIT, columnDragExitHandler);
columnHeaderGroup.removeEventListener(DragEvent.DRAG_DROP, columnDragDropHandler);
cleanUpDropIndicator();
}
private function columnDragDropHandler(event:DragEvent):void
{
columnHeaderGroup.removeEventListener(DragEvent.DRAG_OVER, columnDragOverHandler);
columnHeaderGroup.removeEventListener(DragEvent.DRAG_EXIT, columnDragExitHandler);
columnHeaderGroup.removeEventListener(DragEvent.DRAG_DROP, columnDragDropHandler);
dropColumn(event);
}
private function columnDragCompleteHandler(event:DragEvent):void
{
columnHeaderGroup.removeEventListener(DragEvent.DRAG_ENTER, columnDragEnterHandler);
cleanUpDropIndicator();
}
private function dropColumn(event:DragEvent):void
{
if (dropIndex != dragColumn.columnIndex)
{
var oldIndex:int = dragColumn.columnIndex;
columns.removeItemAt(dragColumn.columnIndex);
if (dropIndex > oldIndex)
dropIndex--;
columns.addItemAt(dragColumn, dropIndex);
}
cleanUpDropIndicator();
}
private function showColumnDropFeedback(event:DragEvent):void
{
var pt:Point = new Point(event.stageX, event.stageY);
pt = columnHeaderGroup.globalToLocal(pt);
var newDropIndex:int = columnHeaderGroup.getHeaderIndexAt(pt.x, pt.y);
if (newDropIndex != -1)
{
var renderer:IGridItemRenderer = columnHeaderGroup.getHeaderRendererAt(newDropIndex);
if (!dropIndicator)
{
dropIndicator = new ColumnDropIndicator();
dropIndicator.height = renderer.height;
columnHeaderGroup.overlay.addDisplayObject(dropIndicator);
}
if (pt.x < renderer.x + renderer.width / 2)
dropIndicator.x = renderer.x - dropIndicator.width / 2;
else
{
dropIndicator.x = renderer.x + renderer.width - dropIndicator.width / 2;
newDropIndex++;
}
dropIndex = newDropIndex;
}
else
{
cleanUpDropIndicator();
}
}
protected function copySelectedItems(useDataField:Boolean = true):Array
{
var tmp:Array = [];
var items:Vector.<Object> = selectedItems;
for (var i:int = 0; i < items.length; i++)
{
if(useDataField){
tmp[i]=items[i];
}else{
tmp[i]=selectedIndices[i];
}
}
return tmp;
}
/**
* @private
*/
private function copySelectedItemsForDragDrop():Vector.<Object>
{
// Copy the vector so that we don't modify the original
// since selectedIndices returns a reference.
var draggedIndices:Vector.<int> = selectedIndices.slice(0, selectedIndices.length);
var result:Vector.<Object> = new Vector.<Object>(draggedIndices.length);
// Sort in the order of the data source
draggedIndices.sort(compareValues);
// Copy the items
var count:int = draggedIndices.length;
for (var i:int = 0; i < count; i++)
result[i] = dataProvider.getItemAt(draggedIndices[i]);
return result;
}
protected function startRowDragDrop(event:GridEvent):void
{
if(!dragEnabled)
return;
var newIndex:int = event.rowIndex;
var ds:DragSource = new DragSource();
ds.addHandler(copySelectedItems, "items");
ds.addHandler(copySelectedItemsForDragDrop, "itemsByIndex");
// Calculate the index of the focus item within the vector
// of ordered items returned for the "itemsByIndex" format.
var caretIndex:int = 0;
var draggedIndices:Vector.<int> = selectedIndices;
var count:int = draggedIndices.length;
for (var i:int = 0; i < count; i++)
{
if (newIndex > draggedIndices[i])
caretIndex++;
}
ds.addData(caretIndex, "caretIndex");
var proxy:Group = new Group();
proxy.width = grid.width;
DragManager.doDrag(this, ds, event, proxy as IFlexDisplayObject,
0, -rowHeight, 0.5, dragMoveEnabled);
const visibleColumnIndices:Vector.<int> = grid.getVisibleColumnIndices();
count = visibleColumnIndices.length;
const visibleRowIndices:Vector.<int> = grid.getVisibleRowIndices();
//for scrolled renderers
var rIndex:int = grid.getVisibleRowIndices().indexOf(newIndex);
for (i = 0; i < count; i++)
{
var currentRenderer:IGridItemRenderer = grid.getItemRendererAt(newIndex, visibleColumnIndices[i]);
var factory:IFactory = columns.getItemAt(i).itemRenderer;
if (!factory)
factory = itemRenderer;
var renderer:IGridItemRenderer = IGridItemRenderer(factory.newInstance());
renderer.visible = true;
if(currentRenderer)
{
renderer.column = currentRenderer.column;
renderer.rowIndex = currentRenderer.rowIndex;
renderer.label = currentRenderer.label;
renderer.x = currentRenderer.x;
renderer.y = rIndex * rowHeight;
renderer.width = currentRenderer.width;
renderer.height = currentRenderer.height;
renderer.prepare(false);
proxy.addElement(renderer);
renderer.owner = this;
}
}
proxy.height = renderer.height;
}
protected function dragEnterHandler(event:DragEvent):void
{
if (event.dragSource.hasFormat("itemsByIndex"))
{
grid.addEventListener(DragEvent.DRAG_OVER, rowDragOverHandler);
grid.addEventListener(DragEvent.DRAG_EXIT, rowDragExitHandler);
grid.addEventListener(DragEvent.DRAG_DROP, rowDragDropHandler);
showRowDropFeedback(event);
DragManager.acceptDragDrop(grid);
}
}
protected function rowDragOverHandler(event:DragEvent):void
{
if (event.dragSource.hasFormat("itemsByIndex"))
{
showRowDropFeedback(event);
DragManager.acceptDragDrop(grid);
}
}
protected function rowDragExitHandler(event:DragEvent):void
{
grid.removeEventListener(DragEvent.DRAG_OVER, columnDragOverHandler);
grid.removeEventListener(DragEvent.DRAG_EXIT, columnDragExitHandler);
grid.removeEventListener(DragEvent.DRAG_DROP, columnDragDropHandler);
cleanUpRowDropIndicator();
}
protected function rowDragDropHandler(event:DragEvent):void
{
grid.removeEventListener(DragEvent.DRAG_OVER, columnDragOverHandler);
grid.removeEventListener(DragEvent.DRAG_EXIT, columnDragExitHandler);
grid.removeEventListener(DragEvent.DRAG_DROP, columnDragDropHandler);
dropRow(event);
}
protected function dragCompleteHandler(event:DragEvent):void
{
if (event.isDefaultPrevented())
return;
// Remove the dragged items only if they were drag moved to
// a different list. If the items were drag moved to this
// list, the reordering was already handles in the
// DragEvent.DRAG_DROP listener.
if (!dragMoveEnabled ||
event.action != DragManager.MOVE ||
event.relatedObject == this)
return;
// Clear the selection, but remember which items were moved
var movedIndices:Vector.<int> = selectedIndices;
selectedIndices = new Vector.<int>();
validateProperties();
// Remove the moved items
movedIndices.sort(compareValues);
var count:int = movedIndices.length;
for (var i:int = count - 1; i >= 0; i--)
{
dataProvider.removeItemAt(movedIndices[i]);
}
dropIndex = 0;
}
private function showRowDropFeedback(event:DragEvent):void
{
DragManager.showFeedback(event.ctrlKey ? DragManager.COPY : DragManager.MOVE);
var pt:Point = new Point(event.stageX, event.stageY);
pt = grid.globalToLocal(pt);
var pos:CellPosition = grid.getCellAt(pt.x, pt.y);
var newDropIndex:int = pos ? pos.rowIndex : - 1;
if (newDropIndex != -1)
{
var renderer:IGridItemRenderer = grid.getItemRendererAt(pos.rowIndex, pos.columnIndex);
if (!dropIndicator)
{
dropIndicator = new RowDropIndicator();
dropIndicator.width = width;
grid.overlay.addDisplayObject(dropIndicator);
}
if (pt.y < renderer.y + renderer.height / 2)
dropIndicator.y = renderer.y - dropIndicator.height / 2;
else
{
dropIndicator.y = renderer.y + renderer.height - dropIndicator.height / 2;
newDropIndex++;
}
dropIndex = newDropIndex;
}
else
{
cleanUpRowDropIndicator();
}
}
private function dropRow(event:DragEvent):void
{
if(event.dragSource.hasFormat("itemsByIndex"))
{
var data:Vector.<Object> = event.dragSource.dataForFormat("itemsByIndex") as Vector.<Object>;
var count:int = data.length;
var i:int;
if (event.dragInitiator == this)
{
for (i = 0; i < count; i++)
{
var index:int = dataProvider.getItemIndex(data[i]);
dataProvider.removeItemAt(index);
if (index < dropIndex)
dropIndex--;
}
}
if(dataProvider == null)
{
dataProvider = new ArrayList();
}
for (i = 0; i < count; i++)
{
dataProvider.addItemAt(data[i], dropIndex++);
}
}
cleanUpRowDropIndicator();
}
private function cleanUpDropIndicator():void
{
if (dropIndicator)
{
dropIndex == -1;
if( columnHeaderGroup.overlay.numDisplayObjects > 0)
{
columnHeaderGroup.overlay.removeDisplayObject(dropIndicator);
dropIndicator = null;
}
}
}
private function cleanUpRowDropIndicator():void
{
if (dropIndicator)
{
dropIndex == -1;
if(grid.overlay.numDisplayObjects > 0)
{
grid.overlay.removeDisplayObject(dropIndicator);
dropIndicator = null;
}
}
}
/**
* @private
* Used to sort the selected indices during drag and drop operations.
*/
private function compareValues(a:int, b:int):int
{
return a - b;
}
}
}
RowDropIndicator.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="3">
<s:Rect left="1" right="1" top="1" bottom="1">
<s:fill>
<s:SolidColor color="0x2B333C"/>
</s:fill>
</s:Rect>
<s:Rect left="0" right="0" top="0" bottom="0">
<s:stroke>
<s:SolidColorStroke weight="1"/>
</s:stroke>
</s:Rect>
</s:Group>
ColumnDropIndicator.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:Rect width="1" height="100%" right="1">
<s:fill>
<s:SolidColor color="0x0167FF"/>
</s:fill>
</s:Rect>
</s:Group>
app.mxml
<?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"
xmlns:c="components.*"
width="800" height="600">
<s:layout>
<s:VerticalLayout horizontalAlign="center" paddingTop="30"/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.core.IUIComponent;
import mx.events.DragEvent;
import mx.managers.DragManager;
protected function addItemButton_dragDropHandler(event:DragEvent):void
{
// TODO Auto-generated method stub
try{
var obj:Object=event.dragSource.dataForFormat('items')[0];
Alert.show(obj.birthday);
}catch(er:Error){}
}
protected function button1_dragEnterHandler(event:DragEvent):void
{
// TODO Auto-generated method stub
DragManager.acceptDragDrop(IUIComponent(event.target));
}
]]>
</fx:Script>
<fx:Declarations>
<s:ArrayList id="al">
<s:DataItem birthday="07/23/1987" salary="6000" userName="Jim"/>
<s:DataItem birthday="06/12/1987" salary="5500" userName="Jane"/>
<s:DataItem birthday="12/06/1988" salary="8000" userName="Tom"/>
<s:DataItem birthday="01/12/1988" salary="6000" userName="Kite"/>
<s:DataItem birthday="05/28/1987" salary="7000" userName="Mike"/>
</s:ArrayList>
</fx:Declarations>
<s:Button
label="drop in"
dragEnter="button1_dragEnterHandler(event)"
dragDrop="addItemButton_dragDropHandler(event)"
>
</s:Button>
<mx:DataGrid width="400"
dataProvider="{new ArrayList(al.source.concat())}"
dragEnabled="true" dragDrop="true"
draggableColumns="true" rowCount="5"
allowMultipleSelection="true">
<mx:columns>
<mx:DataGridColumn dataField="userName" headerText="Name"/>
<mx:DataGridColumn dataField="birthday" headerText="Bithday"/>
<mx:DataGridColumn dataField="salary" headerText="Salary"/>
</mx:columns>
</mx:DataGrid>
<c:DataGridEx width="400" dataProvider="{al}" dragEnabled="true" draggableColumns="true"
dragMoveEnabled="true" dropEnabled="true" requestedRowCount="5" selectionMode="multipleRows">
<c:columns>
<s:ArrayList>
<s:GridColumn dataField="userName" headerText="Name"/>
<s:GridColumn dataField="birthday" headerText="Bithday"/>
<s:GridColumn dataField="salary" headerText="Salary"/>
</s:ArrayList>
</c:columns>
</c:DataGridEx>
<c:DataGridEx id="dgex" width="400" dragEnabled="true" dropEnabled="true" requestedRowCount="5">
<c:columns>
<s:ArrayList>
<s:GridColumn dataField="userName" headerText="Name"/>
<s:GridColumn dataField="birthday" headerText="Bithday"/>
<s:GridColumn dataField="salary" headerText="Salary"/>
</s:ArrayList>
</c:columns>
</c:DataGridEx>
<s:List height="90" dragEnabled="true" dropEnabled="true"
labelField="userName"/>
</s:Application>