Simple Flex Drag and Drop

Skill

Simple Flex Drag and Drop

Posted in:

Today I am going to run through a smallish tutorial on creating and using drag and drop in Flex using the DragManager class, which is a utility provided to make drag and drop easy. I should also mention, right off the bat, that some things like lists already have various drag and drop features built in. I however will be showing an example that is useful for any custom drag jobs you might need to do.

The application below shows the functionality that I will be building today. It is a very simple demo that has a few games up at the top that can be added to your shopping cart by dragging them down into the basket area. Once dropped into the "basket" they will show up in the shopping cart list. The interface is simple and the code is simple - and you can grab that code using this link: Drag and Drop Source Code.

Get Adobe Flash player

Like most Flex tutorials I am going to quickly take a glance at the user interface which includes a couple canvases, labels, and a datagrid. The most important pieces are the images of the games and the basket drop canvas. As seen below, all the images have the MouseDown event hooked up and the basket canvas has the dragEnter and dragDrop events setup. The handlers for these events are going to do all the work to make the drag and drop to run nicely.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="absolute" width="374" height="406">
  <mx:Label x="0" y="210" text="Games" width="118" height="42"
     fontSize="28" color="#818181"/>
  <mx:Image name="Bioshock" x="2" y="2" source="{bioshock_icon}"
     mouseDown="doDrag(event)" />
  <mx:Image name="Crysis" x="120" y="2" source="{crysis_icon}"
     mouseDown="doDrag(event)" />
  <mx:Image name="Halo" x="240" y="2" source="{halo_icon}"
     mouseDown="doDrag(event)" />
  <mx:Image name="Neverwinter Nights" x="50" y="110"
     source="{neverwinter_icon}" mouseDown="doDrag(event)" />
  <mx:Image name="World of Warcraft" x="200" y="110"
     source="{wow_icon}" mouseDown="doDrag(event)" />
  <mx:Canvas x="0" y="255" width="174" height="151"
     borderStyle="solid" backgroundColor="#12976A"
     dragEnter="dragAccept(event)" dragDrop="dragDrop(event)">
    <mx:Label x="0" y="0" text="Basket" width="118" height="42"
       fontSize="28" color="#FFFFFF"/>
  </mx:Canvas>
  <mx:DataGrid dataProvider="{cartContents}" x="173" y="255"
     width="201" height="151">
    <mx:columns>
      <mx:DataGridColumn headerText="Name" dataField="name"/>
      <mx:DataGridColumn headerText="Quantity" dataField="num" width="65"/>
    </mx:columns>
  </mx:DataGrid>
  <mx:Label x="272" y="235" text="Shopping Cart" color="#3A3A3A"
     fontWeight="bold" fontSize="12"/>
</mx:Application>

One of the first things you might notice in the above code is the references to the icons as the source for the images. Well we are going to embed these into the application. To do this we are going to add a Script tag to our application and embed the images into the appropriate variables of type Class. The first iteration of our Script tag is below.

<mx:Script>
 <![CDATA[

 [Embed("assets/bioshock_small.png")]
 private var bioshock_icon:Class;
 
 [Embed("assets/crysis_small.png")]
 private var crysis_icon:Class;
 
 [Embed("assets/halo_small.png")]
 private var halo_icon:Class;
 
 [Embed("assets/neverwinternights_small.png")]
 private var neverwinter_icon:Class;
 
 [Embed("assets/wow_small.png")]
 private var wow_icon:Class;
 ]]>
</mx:Script>

The datagrid in the interface has the dataProvider property bound to the variable called cartContents which also needs to be added to our list of variables. We will later add the items dropped in our basket to the cartContents ArrayCollection.

[Bindable]
private var cartContents:ArrayCollection = new ArrayCollection();

Getting into the meat of the tutorial we are going to look at the functions that take care of creating and accepting the drag and drop actions. First we look at the function doDrag which starts the drag and drop action.

private function doDrag(event:MouseEvent):void
{
  var img:Image = event.currentTarget as Image;
  var dragImg:Image = new Image();
  dragImg.source = img.source;
 
  var dsource:DragSource = new DragSource();
  dsource.addData(img, 'img');
 
  DragManager.doDrag(img, dsource, event, dragImg);
}

Starting off I first get the image that is being clicked on. This is pulled simply by using the currentTarget of the event. We then create an image to use for the drag indicator and set the source to same thing as the image being dragged. Next I create a DragSource which is an object to hold data that needs to be passed with the drag event. I add a single piece of data which is a reference to the image being clicked and name the data "img" - which is the name I will later pull it out with. All that is left to do is actually start the drag event using the function doDrag on the DragManager class. I need to pass the object that is initializing the drag, the data source, the mouse event, and image for the drag indicator. That takes care of starting the drag.

We now want to allow the game to be dropped into the canvas that is labeled "basket". This is going to be done using the dragEnter event on the canvas. Which will fire when the item being dragged enters the canvas area. This function is simply going to add the canvas to the list of acceptable drop areas by adding itself using the function acceptDragDrop on the DropManager class.

private function dragAccept(event:DragEvent):void
{
  var dropTarget:Canvas = event.currentTarget as Canvas;
  DragManager.acceptDragDrop(dropTarget);
}

Once an item is dropped onto the canvas we probably want to do something. This is accomplished using the dragDrop event on the canvas. Once the drop happens we get the image from the data source that we passed along with the drag action and second we add the game to our shopping cart. This is done using the helper function addToCart which check to see if the game is in the cart and if so it increase the quantity and otherwise adds the game to the cart. I did however create a Game class (included in the source) to hold the name of the game and the number in the cart - done for data binding reasons. Both of the functions follow.

private function dragDrop(event:DragEvent):void
{
  var img:Image = event.dragSource.dataForFormat('img') as Image;
  addToCart(img);
}

private function addToCart(img:Image):void
{
  for(var i:int = 0; i < cartContents.length; i++)
  {
    if(cartContents[i].name == img.name)
    {
      cartContents[i].num++;
      return;
    }
  }
  cartContents.addItem(new Game(img.name, 1));
}

That takes care of drag and drop in Flex. Yes, it's that easy to do simple drag and drop and also very easy to expand to complex situations using the same techniques. I also need to give props to Belia0166 over at deviantArt for creating the icons that I used in the application. If anyone has any questions feel free to leave a comment. Also don't forget about the Drag and Drop Source Code.

Brad Simo
08/14/2008 - 11:48

Greetings:
I'm developing a Flex website and am trying to figure out the best way to integrate a shopping cart into it. I would rather not have to build one from scratch. On your blog, I looked at some of your examples that could be used as parts of a cart, but obviously I would have to add a bunch.

Do you have any info on what would be the best what to do develop a shopping cart for a flex site or is there company that sells a shopping cart that can integrate into a Flex site?

I would even be open to integrating with Yahoo, ebay or Amazon if there was a simple solution to do that. I'm just looking for a simple way to do this.

Any thoughts for suggestions would be GREATLY appreciated.

Thanks,
Brad

reply

Anonymous
10/21/2008 - 07:58

很棒,我也在学习FLEX,共同进步!

reply

Vidya
12/10/2008 - 00:21

Hi, i have two advanced datagrids.
and i want to do drag & drop between two datagrids. but the problem is with groupingCollection data.
wenever i try to drag item frm 1 datagrid to another it doesn’t get grouped into another datagrid.
i tried to refresh groupingCollection, dataprovider & also called valiadetNow() but it still remains non-grouped.
Could you please tell me wher problem lies?

reply

Anonymous
03/05/2009 - 20:50

共同进步

reply

Jimmy
03/11/2009 - 09:12

I am getting the error / warning

"Data binding will not be able to detect assignments to "bioshock_icon"

Can anybody tell me how to solve this

reply

The Fattest
03/11/2009 - 09:15

You can solve this by adding [Bindable] to that variable. However, you do not need it because we are only updating the class once with the Embed so we don't need to update when the icon changes.

reply

Mike
03/18/2009 - 23:10

How can I apply each item with a price so that I can display that also in the DataGrid?

reply

Mike
03/19/2009 - 00:52

Oops, I am ok. I forgot to work on Game.as Thanks.

reply

Asprilla
06/02/2009 - 09:26

This tutorial is great but I'm getting an error in the drapDrop function.

1119: Call to a possibly undefined property dragSource through a reference with static type flash.events:Event.

I'm using the code in an Air application, could that be the problem?

reply

gopal
07/29/2009 - 00:50

hi the fattest!
i am a big fan of yours,
plz help me out with datagrid problem that i am facing.

i want to build a datagrid in which drag and drop may be possibly like in MS Excel i.e. we just drag a cell and copy its value in the corresponding dragged over cells.
and also a blank editable datagrid with editable cell mode

reply

SKJai
10/14/2009 - 01:30

It's Well And Amazing Work Friend

reply

SKJai
10/14/2009 - 01:33

It's Superb and Amazing Work Friend

reply

Ronnie
04/13/2010 - 03:35

Hi,
I want to display the image in the basket once i drag and drop it on the basket. How do i do it?

reply

Ronnie
04/13/2010 - 05:29

I have a list of images in an accordion. I have drag drop enabled all the images. I have a Panel which has been enabled to accept drop. But as i drop the image on the Panel i want to see the image on the Panel. Please find the code changes i have made in handleDrop() function (dragdrop() function equivalent)... How shud i enable the panel to display the image?

Code :
handleDrop() function:

public function handleDrop(dragEvent:DragEvent):void{
                               
//var dragInitiator:Image = dragEvent.dragInitiator;

var dragInitiator:Image = dragEvent.dragSource.dataForFormat('img') as Image;

var dropTarget:Panel = dragEvent.currentTarget as Panel;
                           
                             
Alert.show(" You dropped the image on the screen");
                           
Image(dragEvent.dragInitiator).x =
            Panel(dragEvent.currentTarget).mouseX;

Image(dragEvent.dragInitiator).y =
            Panel(dragEvent.currentTarget).mouseY;

                               
}

reply

Ronnie
04/13/2010 - 06:33

Plz find the entire code below and let me know what i am missing?

Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">

<mx:Script>
        <![CDATA[
       
                import mx.core.DragSource;
                import mx.core.IUIComponent;
                import mx.managers.DragManager;
                import mx.events.DragEvent;
                import mx.controls.Alert;
                import mx.controls.Image;
                import flash.display.*;
                import flash.events.MouseEvent;

               
               
                public function init():void{
                               
                                // a mouseDown event will start the drag
                                this.rec.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
                                this.roundRec.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
                                this.linux.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
                               
                                // a mouseMove event will draw the lines
                                //this.stage.addEventListener(MouseEvent.MOUSE_MOVE, handleMove);
                               
                                // accepting a drag drop operation
                                this.networkStage.addEventListener(DragEvent.DRAG_ENTER, acceptDrop);
                               
                                // handling the drop
                                this.networkStage.addEventListener(DragEvent.DRAG_DROP, handleDrop);
                               
                        }
                       
       
                public function beginDrag(mouseEvent:MouseEvent):void{
                               
                               
                                // the img is the object being dragged(target of the mouse event)
                                var dragInitiator:Image = mouseEvent.currentTarget as Image;
                                var dragImg:Image = new Image();
                                dragImg.source = dragInitiator.source;
                                 
                                // drag source contains data about what is being dragged  
                                var dragSource:DragSource = new DragSource();
                                // add some data to the dragSource
                                dragSource.addData(dragInitiator, 'img');
                                 
                                // ask the drag manager to begin the drag  
                                DragManager.doDrag(dragInitiator, dragSource, mouseEvent, dragImg);
                               
                        }
                       
                        public function acceptDrop(dragEvent:DragEvent):void{
                               
                                var dropTarget:Panel = dragEvent.currentTarget as Panel;
                                 //var dropTarget:IUIComponent = dragEvent.currentTarget as IUIComponent;
                                 var dragSource:DragSource = dragEvent.dragSource;
                                 
                                // accept the drop
                                DragManager.acceptDragDrop(dropTarget) ;
                               
                                // show feeedback
                                DragManager.showFeedback(DragManager.LINK);
                               
                        }
                       
                        public function handleDrop(dragEvent:DragEvent):void{
                               
                                //var dragInitiator:Image = dragEvent.dragInitiator;
                                var dragInitiator:Image = dragEvent.dragSource.dataForFormat('img') as Image;

                                var dropTarget:Panel = dragEvent.currentTarget as Panel;
                           
                             
                                Alert.show(" You dropped the rectangle on the screen");
                           
                            Image(dragEvent.dragInitiator).x =
                   Panel(dragEvent.currentTarget).mouseX;
               Image(dragEvent.dragInitiator).y =
                   Panel(dragEvent.currentTarget).mouseY;

                               
                        }
               
               
        ]]>
</mx:Script>





        <mx:Canvas width="100%" height="100%">
        <mx:HBox width="100%" height="100%">
       
                <mx:Panel width="30%" height="100%" title="">
                        <mx:Accordion width="100%" height="100%" id="Components" selectedIndex="0" historyManagementEnabled="false">
                                <mx:HBox label="Shapes" horizontalAlign="left" verticalAlign="top" width="100%"
                                 height="100%">
                                        <mx:Image name="Rectangle" source="assets/images/rec.jpg" id="rec"/>
                                        <mx:Image name="Round Rectangle" source="assets/images/roundrec.gif" id="roundRec"/>
                                        <mx:Image name="Linux" source="assets/images/linux.png" id="linux"/>
                                </mx:HBox>
                                <mx:HBox label="Links/Arrows" horizontalAlign="left" verticalAlign="top" width="100%"
                                 height="100%">
                                        <mx:Image source="assets/images/link_icon.png" id="link"/>
                                        <mx:Image source="assets/images/ArrowDelta.png" id="arrowDel"/>
                                        <mx:Image source="assets/images/ArrowDiamond.png" id="arrowDiam"/>
                                </mx:HBox>
                                <mx:HBox label="Arrows" horizontalAlign="left" verticalAlign="top"
                                 width="100%" height="100%">
                                       
                                </mx:HBox>
                        </mx:Accordion>
                </mx:Panel>
                <mx:Panel id="networkStage" width="100%" height="100%" title="Drawing Stage">
                       
                </mx:Panel>
                       
        </mx:HBox>
               
        </mx:Canvas>
       
</mx:Application>

reply

The Fattest
04/15/2010 - 11:25

Couple quick thoughts, first are you wanting to display the image on the panel and keep it inside the accordion? If this is the case just pull the image source and create a new one to put in the panel. You can not have the same component on two surfaces. If your just moving it, make sure to remove it first from the accordion and then just add it as a child of panel, placing it where you want.

reply

Ronnie
04/19/2010 - 01:37

Hi Fattest,
Thx for the reply. After displaying the image, i want to be able to consider it as a component and be able to drag and drop it anywhere in the panel. I also nee d to connect such images by clicking on one image and drag over to the other image and release the mouse. Any insights on this one would be really helpful..
Thanks in advance :)

reply

Ronnie
04/19/2010 - 03:58

Hi Fattest,
I have been able to display the image now on the panel. The changed dropIt() function is as follows:

private function dropIt(event:MouseEvent):void
{

// Get the drag initiator component from the event object.

var dragInitiator:Image = event.currentTarget as Image;
   
// Create a DragSource object.

var dragSource:DragSource = new DragSource();
   
   
// Create a copy of the image to use as a drag proxy.

var dragProxy:Image = new Image();
dragProxy.source = event.currentTarget.source;
dragProxy.setActualSize(event.currentTarget.width,event.currentTarget.height)
               
}

Now once this image is displayed, i wanna be able to drag them anywhere on the panel, and connect different images by lines/arrows.
Your insights would be much appreciated. Thanks in advance :)

reply

The Fattest
04/19/2010 - 08:31

Well dragging them around shouldn't be too hard just enable dragging for the images and when the drag starts listen for mouse move updating the position of the image as it is dragged. Alternative is to listen for mouse down on it and enable mouse move on that.

As for the drawing lines, I'm not sure how you want to handle that. I mean drawing straight lines should be fairly easy. Maybe have a line drawing mode where you click and drag a line from one image to another following the same method as above but drawing a line from the start point to the end point (or current move point). Then when you are over another image you complete the line/arrow.

reply

sasi kumar
05/17/2010 - 03:28

HI fattest i am new for flex i started to learn flex just a month b4...
now i want to add a component dynamically to HBox at run time time can u say any idea for it...

waiting for u...
thx in advance

reply

The Fattest
05/17/2010 - 15:52

What you need to do is make sure HBox has an id ("myhbox" in this example) and then in your actionscript where you create the component you just have to call myhbox.addChild(newcomponent); that should take care of it for you.

reply

sasi kumar
05/24/2010 - 06:37

yeah..i have done it...thank u fattest..
i like to say abt me..
i just completed my mca n jointed in company(touchpoint)as a trainee developer.
now i am flex project name of the project is wallboard..
now i dont have any doubt in flex when i face any probs ill try it first else plz when u free help me fattest.
really thx a lot for u r b4 reply fattest.

reply

sasi kumar
05/24/2010 - 07:21

public function setInitialConfiguration():void {
                                frameChanger.delay = 5000;
                                //messageRefresher.delay = 500;
                                statisticsRotater.delay = statisticsRefreshRate;
                                if (effectStyle == "NONE") {
                                        /*firstFrame.setStyle("showEffect", noEffectShow);
                                        firstFrame.setStyle("hideEffect", noEffectHide);
                                        secondFrame.setStyle("showEffect", noEffectShow);
                                        secondFrame.setStyle("hideEffect", noEffectHide);
                                        frameChanger.refreshFunction = changeFrameWithNoEffect;*/

                                        frameChanger.refreshFunction = changeData;
                                        effectAvailable = "NO";
                                       
                                } else if (effectStyle == "WIPE") {
                                        frameChanger.refreshFunction = changeFrameWithNoEffect;
                                        firstFrame.setStyle("showEffect", wipeShow);
                                        firstFrame.setStyle("hideEffect", wipeHide);
                                        secondFrame.setStyle("showEffect", wipeShow);
                                        secondFrame.setStyle("hideEffect", wipeHide);
                                        effectAvailable = "YES";
                                } else if (effectStyle.toUpperCase() == "GLOW") {
                                        frameChanger.refreshFunction = changeFrameWithNoEffect;
                                        firstFrame.setStyle("showEffect", glowEffect);
                                        firstFrame.setStyle("hideEffect", unglowEffect);
                                        secondFrame.setStyle("showEffect", glowEffect);
                                        secondFrame.setStyle("hideEffect", unglowEffect);
                                        effectAvailable = "YES";
                                } else if (effectStyle == "CUBE") {
                                        frameChanger.refreshFunction = changeFrameWithRotateEffect;
                                        effectAvailable = "YES";
                                } else if (effectStyle == "FLIP") {
                                        frameChanger.refreshFunction = changeFrameWithFlipEffect;
                                        effectAvailable = "YES";
                                } else {
                                        /*firstFrame.setStyle("showEffect", noEffectShow);
                                        firstFrame.setStyle("hideEffect", noEffectHide);
                                        secondFrame.setStyle("showEffect", noEffectShow);
                                        secondFrame.setStyle("hideEffect", noEffectHide);
                                        frameChanger.refreshFunction = changeFrameWithNoEffect;*/

                                        frameChanger.refreshFunction = changeData;
                                        effectAvailable = "NO";
                                       
                                }
                                /*if(effectAvailable == "NO") {
                                        frameChanger.refreshFunction = changeData;                                     
                                }*/

hi fattest the above coding is the part of my function which change my two frames one after another and its working well too but what is the requirement is i want to show my first frame from 5am-12pm and my second frame from 12pm-6pm i have tried this by using date class and conditions but not getting it...do u have any idea fattest.
i think i am confusing u..but try to help me plz..
waiting for u r guide..

reply

sasi kumar
05/24/2010 - 07:27

fattest if u free do catch me at sasikumar@touchpointindia.com

reply

sasi kumar
05/26/2010 - 09:27

hi fattest do u know how to create log file in flex...
if s plz help me

reply

Ronnie
06/07/2010 - 06:17

Hi Fattest,
I wanna drag and drop buttons from a list to a canvas. Imagine u have a set of images that u can drag and drop onto a canvas. In place of these images i want buttons. I tried but when i drag and drop, the button disappears from the list. Please let me know how i can just replicate the button in the list onto the canvas when i drag and drop. Please check my code below:

public function dragButton(e:MouseEvent):void
{
if(e.buttonDown)
{
var button:Button = e.currentTarget as Button;
var buttonProxy:Button = new Button();
buttonProxy.width = button.width;
buttonProxy.height = button.height;
var dragSource:DragSource = new DragSource();
dragSource.addData(button, ‘button’);
DragManager.doDrag(button, dragSource, e);
}
}
public function dragEnter(event:DragEvent): void
{
var target:Canvas = event.currentTarget as Canvas;
if (event.dragSource.hasFormat(‘button’))
{
DragManager.acceptDragDrop(target);
DragManager.showFeedback(DragManager.COPY);
}
}
public function dragDrop(event:DragEvent): void
{
var target:Canvas = event.currentTarget as Canvas;
var button:Button = event.dragSource.dataForFormat(‘button’) as Button;
button.x = event.localX;
button.y = event.localY;
networkStage.addChild(button);
}

<mx:VBox height="100%" width="100%">
                       
<mx:Accordion width="100%" height="60%" id="Components" selectedIndex="0"
                historyManagementEnabled="false">
             
<mx:HBox id="butt">    
        <mx:Button contextMenu="{buttonMenu}" name="Trans" icon="{transIcon}"
                                                        id="transBut" buttonMode="true" useHandCursor="true" />
        <mx:Button contextMenu="{buttonMenu}" name="IsoTrans" icon="{recIcon}"
                                                        id="recBut" useHandCursor="true" buttonMode="true" />
        <mx:Button contextMenu="{buttonMenu}" name="UP" icon="{linuxIcon}"
                                                        id="linuxBut" useHandCursor="true" buttonMode="true" />
        <mx:Button contextMenu="{buttonMenu}" name="PD" icon="{vmIcon}"
                                                        id="vmBut" useHandCursor="true" buttonMode="true" />
</mx:HBox>
</mx:Accordion>

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.

Sponsors