您的位置:首页 > 运维架构

AsWing中自定义拖拽功能(Drag And Drop)

2009-08-29 15:10 330 查看
本文原载于FlashSeer

,文章地址:http://www.flashseer.org/bbs/viewthread.php?tid=342&extra=page%3D1


下面是我最近用到AsWing的拖拽功能,之后的一些初级经验。

目录


1 快速开始

1.1 被拖拽的组件

1.2 拖拽目标组件

2 几个基本方法

2.1 setDragEnabled

2.2 setDropTrigger

2.3 addDragAcceptableInitiator

2.4 DragManager.startDrag

3 高级话题

3.1 DraggingImage & addDragAcceptableInitiator

3.2 DragListener

3.3 getCurrentDropTargetDropTriggerComponent

1 快速开始


1.1 被拖拽的组件


首先,要拖拽的组件应该setDragEnabled( true ),保证其能发出拖动识别ON_DRAG_RECOGNIZED事件。同时应该监听此组件的ON_DRAG_RECOGNIZED事件。

CODE:
[Copy to clipboard]

...

//part 1 drag initiator

dragBtn = new JButton( "拖我到下边的Pane" );

dragBtn.setDragEnabled(true);

dragBtn.addEventListener(JButton.ON_DRAG_RECOGNIZED, __dragRecognized, this);

...

CODE:
[Copy to clipboard]

/**

* 监听到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() ));

}
1.2 拖拽目标组件


其次,拖拽目标组件应该setDropTrigger( true ),保证其能接收以下4个事件。

a. ON_DRAG_ENTER(当拖拽组件刚被拖到目标组件上时,触发此事件)、

b. ON_DRAG_OVERRING(当拖拽组件已被拖到目标组件上,每次移动时触发此事件)、

c. ON_DRAG_EXIT(与ON_DRAG_ENTER事件相反,当拖拽组件刚被拖出目标组件,触发此事件)、

d. ON_DRAG_DROP(当拖拽组件已被拖到目标组件上,此次拖拽事件结束时触发此事件)

CODE:
[Copy to clipboard]

//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);

CODE:
[Copy to clipboard]

/**

* 监听到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.append(new JButton(sourceData.getData().toString()+(pane.getComponentCount()+1)));

}

快速开始就OK啦,具体代码参见附件:[DragAndDropDemoV1源代码]
:[DragAndDropDemoV2源代码]

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方法。

CODE:
[Copy to clipboard]

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,有如下几行:

CODE:
[Copy to clipboard]

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如何识别目标组件的。

CODE:
[Copy to clipboard]

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源代码

CODE:
[Copy to clipboard]

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 源代码

CODE:
[Copy to clipboard]

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));

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: