...
//part 1 drag initiator
dragBtn = new JButton( "拖我到下边的Pane" );
dragBtn.setDragEnabled(true);
dragBtn.addEventListener(JButton.ON_DRAG_RECOGNIZED, __dragRecognized, this);
...
2 几个基本方法
2.1 addDragAcceptableInitiator
setDragEnabled(b : Boolean)
Sets whether this component can fire ON_DRAG_RECOGNIZED event.(此段注释为
AsWing 自带,下同)
设置是否发出拖动识别(ON_DRAG_RECOGNIZED)事件。
默认设为false。
2.2 setDropTrigger
setDropTrigger(b : Boolean)
Sets whether this component can trigger dragging component to fire drag events when dragging over to this component.
设置此组件是否能触发拖动组件发出拖动事件,当拖动组件被拖动到此组件上时(参见高级话题3.3)。
2.3 setDropTrigger
addDragAcceptableInitiator(com : Component)
Adds a component to be the acceptable drag initiator to this component.It is not meanning that the DnD events will not be fired when the initiator is dragging enter/over/exit/drop on this component.It is meanning that you can have a convenient way to proccess that events from the method
isDragAcceptableInitiator later, and the default dragging image will take advantage to present a better picture when painting.
* @param com the acceptable drag initiator
添加一个组件为当前组件可接受的拖动初始组件。但这不意味着当拖动初始组件被拖动到此组件上时,此组件不会发出拖拽事件。它意味着你可以用
isDragAcceptableInitiator 方法判断一个component是否为当前组件可接受的拖动初始组件,同时默认的拖动图像也可借此方法更合理的被描绘(参见高级话题3.1)。
2.4 DragManager.startDrag
DragManager.startDrag(dragInitiator : Component, sourceData : SourceData, dragImage : DraggingImage, dragListener : DragListener)
Starts dragging a initiator, with dragSource, a dragging Image, and a listener. The drag action will be finished at next Mouse UP/Down Event(Mouse UP or Mouse Down, generally you start a drag when mouse down, then it will be finished when mouse up, if you start a drag when mouse up, it will be finished when mouse down).
* @param dragInitiator the dragging initiator
* @param sourceData the data source will pass to the listeners and target components
* @param dragImage (optional)the image to drag, default is a rectangle image.
* @param dragListener (optional)the listener added to just for this time dragging action, default is null(no listener)
指定sourceData , dragImage(可选), dragListener(可选)3个参数开始拖动初始组件(dragInitiator)。这个拖动事件将在下一个鼠标的UP/Down时结束。
* @param dragInitiator 拖动初始组件
* @param sourceData 传给监听者和目标组件的数据。
* @param dragImage (可选),拖动时显示的图片,默认是一个矩形框(参见高级话题3.1)。
* @param dragListener (可选),为此次拖动事件添加监听者。默认为null(没有监听者)(参见高级话题3.2)。
3 高级话题
3.1 DraggingImage & addDragAcceptableInitiator
3.1.1 自定义WindowsDragImage --Windows风格的拖动图像
参照org.aswing.dnd.DefaultDragImage和org.aswing.dnd.ListDragImage,我们写一个自己的 DragImage。其效果如同拖动windows“资源管理器”里的图标一样。主要是实现interface DraggingImage的几个方法,较简单请看代码注释及下节3.1.2对DraggingImage的描述。
3.1.2 interface DraggingImage
setCanvas(target : MovieClip)
* Paints the image for normal state of dragging.
* 传入用来描绘拖动中的图像的MovieClip。
switchToAcceptImage()
* Paints the image for accept state of dragging.(means drop allowed)
* 表现拖动组件被目标组件接受时的图像。
switchToRejectImage()
* Paints the image for reject state of dragging.(means drop not allowed)
* 表现拖动组件被目标组件不被接受时的图像。
3.1.3 addDragAcceptableInitiator
DragManager中onMouseMove方法。
private static function onMouseMove():Void{
...
if(dropC != enteredComponent){
if(enteredComponent != null){
//一般情况下,先将拖动图像switchToRejectImage()--参见DraggingImage的方法: switchToRejectImage()
s_dragImage.switchToRejectImage();
fireDragExitEvent(s_dragInitiator, s_sourceData, globalPos, enteredComponent);
enteredComponent.fireDragExitEvent(s_dragInitiator, s_sourceData, globalPos);
}
if(dropC != null){
//*********
下边这句就是addDragAcceptableInitiator的关键所在,当鼠标移动时,DragManager会判断目标组件是否接受拖动组件, 如接受就使用拖动图像DraggingImage的switchToAcceptImage()描绘成可接受状态.同时如果我们没有使用 addDragAcceptableInitiator,DragManager将不会自动识别拖动组件是否为目标组件可接受,亦不会调用 DraggingImage的对应方法.
//*********
if(dropC.isDragAcceptableInitiator(s_dragInitiator)){
//在目标组件接受拖动组件的情况下,将拖动图像switchToAcceptImage()--参见DraggingImage的方法: switchToAcceptImage()
s_dragImage.switchToAcceptImage(); }
fireDragEnterEvent(s_dragInitiator, s_sourceData, globalPos, dropC);
dropC.fireDragEnterEvent(s_dragInitiator, s_sourceData, globalPos);
}
enteredComponent = dropC;
}
...
3.2 DragListener
观察DragManager中的几个fireDrag*****Event,有如下几行:
var lis:DragListener = DragListener(listeners[i]);
lis.onDragStart(dragInitiator, sourceData, pos);
var lis:DragListener = DragListener(listeners[i]);
lis.onDragEnter(dragInitiator, sourceData, pos, targetComponent);
var lis:DragListener = DragListener(listeners[i]);
lis.onDragOverring(dragInitiator, sourceData, pos, targetComponent);
var lis:DragListener = DragListener(listeners[i]);
lis.onDragExit(dragInitiator, sourceData, pos, targetComponent);
var lis:DragListener = DragListener(listeners[i]);
lis.onDragDrop(dragInitiator, sourceData, pos, targetComponent);
这几个onDrag***方法不就是DragListener所定义的那几个方法么?
那么在1.DragManager.startDrag()方法 及 2.DragManager.addDragListener()方法传入的
DragListener就可以监听到拖动组件的一举一动 啦。
3.3 getCurrentDropTargetDropTriggerComponent
研究它的用处在于我们可以更清楚地了解DragManager如何识别目标组件的。
public static function getCurrentDropTargetDropTriggerComponent():Component{
//*************
//这个(dragProxyMC)就是DraggingImage传入的target.用以描绘组件的拖动图像.
return getDropTargetDropTriggerComponent(dragProxyMC);
}
public static function getDropTargetDropTriggerComponent(draggingMC:MovieClip):Component{
var c:Component = getDropTargetComponent(draggingMC);
//*************
//注意这个获取的c组件,如果它不为null且c.isDropTrigger()==false (说明此组件的setDropTrigger(false),参见第2.2节),那么就取其父//组件,此处while循环可以追溯c的祖先,直至找到一 个setDropTrigger(true)的组件.
while(c != null && !c.isDropTrigger()){
c = c.getParent();
}
return c;
}
public static function getDropTargetComponent(draggingMC:MovieClip):Component{
var mc:MovieClip = getDropTargetMovieClip(draggingMC);
if(mc != null){
//*************
//找到目标MC后,取得拥有此MC的组件,返回之.
return Component.getOwnerComponent(mc);
}
return null;
}
public static function getDropTargetMovieClip(draggingMC:MovieClip):MovieClip{
var target = getDropTarget(draggingMC);
if(target == null){
return null;
}else if(target instanceof MovieClip || typeof(target) == "movieclip"){
//*************
//如果目标是MC,则返回之
return target;
}else{
//*************
//如果目标不是MC,则取其父
return target._parent;
}
}
public static function getDropTarget(draggingMC:MovieClip){
if(draggingMC == null){
return null;
}else{
draggingMC.startDrag(false);
//*************
//最终找到我们的目标组件是使用MovieClip._droptarget 属性获取的.
var target = eval(draggingMC._droptarget);
draggingMC.stopDrag();
return target;
}
}
DragAndDropDemo源代码
import org.aswing.ASColor;
import org.aswing.border.LineBorder;
import org.aswing.BorderLayout;
import org.aswing.colorchooser.ColorRectIcon;
import org.aswing.Component;
import org.aswing.dnd.DragManager;
import org.aswing.dnd.SourceData;
import org.aswing.FlowLayout;
import org.aswing.geom.Point;
import org.aswing.JButton;
import org.aswing.JFrame;
import org.aswing.JPanel;
/**
* @author Msun
*/
class DragAndDropDemo extends JFrame {
private var pane : JPanel ;
private var dragBtn : JButton;
public function DragAndDropDemo(){
super("Drag And Drop Demo");
init();
}
private function init() : Void{
//part 1 drag initiator
dragBtn = new JButton( "拖我到下边的Pane" );
var palletteIcon : ColorRectIcon = new ColorRectIcon(20, 20);
palletteIcon.setColor(ASColor.RED);
dragBtn.setIcon( palletteIcon );
dragBtn.setDragEnabled(true);
dragBtn.addEventListener(JButton.ON_DRAG_RECOGNIZED, __dragRecognized, this);
//part 2 drag target
pane = new JPanel(new FlowLayout());
pane.setDropTrigger( true );
pane.addDragAcceptableInitiator( dragBtn );
pane.addEventListener(JPanel.ON_DRAG_ENTER, __dragEnter, this);
pane.addEventListener(JPanel.ON_DRAG_OVERRING, __dragOverring, this);
pane.addEventListener(JPanel.ON_DRAG_EXIT, __dragExit, this);
pane.addEventListener(JPanel.ON_DRAG_DROP, __dragDrop, this);
//add these component into container
pane.setBorder(new LineBorder(null, new ASColor(0xFF6600), 2, 8));
var wapperPane : JPanel = new JPanel(new FlowLayout());
wapperPane.append(dragBtn);
this.getContentPane().append(wapperPane, BorderLayout.NORTH);
this.getContentPane().append(pane, BorderLayout.CENTER);
setSize(450,270);
show();
}
/**
* 监听到dragBtn的ON_DRAG_RECOGNIZED事件,将拖拽事件托管给DragManager。
* @param dragInitiator 此例中是指dragBtn。
* @param touchedChild 被鼠标拖住的组件,此例中亦是dragBtn。
*/
private function __dragRecognized( dragInitiator : Component, touchedChild : Component ) : Void{
DragManager.startDrag( dragBtn , new SourceData("dragData", JButton(dragInitiator).getText() ), new WindowsDragImage( dragBtn ));
}
/**
* 监听到dragBtn的ON_DRAG_ENTER事件 。
*/
private function __dragEnter(source : Component, dragInitiator : Component, sourceData : SourceData, mousePos : Point) : Void{
__trace("ON_DRAG_ENTER", source, dragInitiator, sourceData, mousePos);
pane.setBorder(new LineBorder(null, new ASColor(0x0), 1, 8));
}
/**
* 监听到dragBtn的ON_DRAG_OVERRING事件 。
*/
private function __dragOverring(source : Component, dragInitiator : Component, sourceData : SourceData, mousePos : Point) : Void{
//__trace("ON_DRAG_OVERRING", source, dragInitiator, sourceData, mousePos);
}
/**
* 监听到dragBtn的ON_DRAG_EXIT事件 。
*/
private function __dragExit(source : Component, dragInitiator : Component, sourceData : SourceData, mousePos : Point) : Void{
__trace("ON_DRAG_EXIT", source, dragInitiator, sourceData, mousePos);
pane.setBorder(new LineBorder(null, new ASColor(0xFF6600), 2, 8));
}
/**
* 监听到dragBtn的ON_DRAG_DROP事件,一般为处理拖拽事件的关键点。
*/
private function __dragDrop(source : Component, dragInitiator : Component, sourceData : SourceData, mousePos : Point) : Void{
__trace("ON_DRAG_DROP", source, dragInitiator, sourceData, mousePos);
pane.setBorder(new LineBorder(null, new ASColor(0xFF6600), 2, 8));
pane.append(new JButton(sourceData.getData().toString()+(pane.getComponentCount()+1)));
}
/**
* 内部方法,减少重复代码用。
*/
private function __trace(eventName : String, source : Component, dragInitiator : Component, sourceData : SourceData, mousePos : Point ) : Void{
trace(eventName +":/n source:"+source
+"/n dragInitiator:"+dragInitiator
+"/n sourceData:"+sourceData
+"/n mousePos:"+mousePos);
}
public static function main() : Void{
Stage.scaleMode = "noScale";
var dndDemo : DragAndDropDemo = new DragAndDropDemo();
}
}
WindowsDragImage 源代码
import org.aswing.ASColor;
import org.aswing.Component;
import org.aswing.dnd.DraggingImage;
import org.aswing.graphics.Graphics;
import org.aswing.graphics.Pen;
import org.aswing.graphics.SolidBrush;
import flash.display.BitmapData;
/**
* The Windows Style drag image.
* 参考DefaultDragImage
* @author Msun
*/
class WindowsDragImage implements DraggingImage {
private var initiator : Component;
private var target : MovieClip;
private var dragImgMC : MovieClip;
private var myBitmapData : BitmapData ;
private var targetRejectMC : MovieClip;
private var targetBmpMC : MovieClip;
public function WindowsDragImage(dragInitiator : Component){
initiator = dragInitiator;
//以下几行是为了取得拖动Comonent的图像,并cacheAsBitmap,然后新建一个描绘此图像的BitmapData。
var o = dragInitiator;
dragImgMC = o.root_mc;
dragImgMC.cacheAsBitmap = true;
myBitmapData = new BitmapData(getImageWidth(), getImageHeight(), false, 0x00CCCC00);
}
private function getImageWidth() : Number {
return initiator.getWidth();
}
private function getImageHeight() : Number {
return initiator.getHeight();
}
public function setCanvas(target : MovieClip) : Void {
this.target = target;
}
/**
* 表现拖动组件被目标组件接受时的图像。
*/
public function switchToAcceptImage() : Void {
__clear();
attachBmp(myBitmapData, dragImgMC);
}
/**
* 表现拖动组件被目标组件不被接受时的图像。
*/
public function switchToRejectImage() : Void {
__clear();
attachBmp(myBitmapData, dragImgMC);
//新建targetRejectMC用以描绘“拒绝拖动的标志”
targetRejectMC = target.createEmptyMovieClip("targetRejectMC", target.getNextHighestDepth());
drawRejectIcon(new Graphics( targetRejectMC ), (getImageWidth() - 16), (getImageHeight() - 16)/2);
}
/**
* 将拖动组件的图像描绘在setCanvas()传入的target MovieClip上。
*/
private function attachBmp(bmpData : BitmapData, drawMC : MovieClip) : Void{
targetBmpMC = target.createEmptyMovieClip("targetBmpMC", target.getNextHighestDepth());
targetBmpMC._alpha = 75;
targetBmpMC.attachBitmap(bmpData, targetBmpMC.getNextHighestDepth(), "auto", true);
bmpData.draw( drawMC );
}
/**
* 清除上次描绘的图像
*/
private function __clear() : Void{
targetRejectMC.clear();
targetBmpMC.removeMovieClip();
target.clear();
}
/**
* 画出类似于Windows中拒绝拖动的标志,一个圆及其中间一个向左倾斜45度的直线。
*/
private function drawRejectIcon(g : Graphics, x : Number, y : Number) : Void{
var R : Number = 8.5; //reject circle radius is 8.5px
g.fillCircleRing(new SolidBrush(ASColor.BLACK ), x+R, y+R, R, R-2 );
g.drawLine(new Pen(ASColor.BLACK , 2, 100),
Math.round( x+ 0.3*R ),
Math.round( y+ 0.3*R ),
Math.round( x+ 1.7*R ),
Math.round( y+ 1.7*R));
}
}