当前位置: 首页 > 工具软件 > AsWing > 使用案例 >

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

鄢松
2023-12-01

本文原载于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事件。

                   ...
                   //part 1 drag initiator
                   dragBtn = new JButton( "拖我到下边的Pane" );
                   dragBtn.setDragEnabled(true);
                   dragBtn.addEventListener(JButton.ON_DRAG_RECOGNIZED, __dragRecognized, this);
                           ...


            /**
            * 监听到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(当拖拽组件已被拖到目标组件上,此次拖拽事件结束时触发此事件)

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


           /**
            * 监听到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方法。

         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));
         }
}
 类似资料: