Flex Multi-Drag

Have you ever been playing with the DragManager in your flex app and wondered  how to get more than one object dragging at once? DataGrid and List can do it, so why not other custom widgets? On a project I’ve been working on, we have a custom schedule component and want to drag multiple items around at once, so I did a little research and found out how it is done. The Flex SDK, which you can download for free, comes with source code! On my Mac, it was installed in the Flex Builder directory (/Applications/Adobe Flex Builder 3/sdks/3.2.0/frameworks/projects/framework/src/). Within there, I found what I was looking for in mx/controls/listClasses/ListBase.as

It turns out that DataGrid and List extend ListBase, which implements multi-drag for those components. If you look at the documentation for DragSource, it has an addHandler(..) method, that allows you to pass a collection along with the drag. When DragEvent.DRAG_DROP is being handled, you can pull that collection from the DragSource. Adding the objects from that collection is a manual process, but at least it is easy to pass all of the objects you’d like to drag along without much fuss. Here’s a bit of code that demonstrates this;

var dragSource: DragSource = new DragSource();
ds.addHandler(copySelectedItems, "items");
DragManager.doDrag(this, dragSource, event, dragImage, 0, 0, 0.5, dragMoveEnabled);

A really cool thing here is that “addHandler(..)” takes a method that provides the items. That method only gets called when the data is actually needed. So, you can defer data access until a drop is actually being performed. In the case where you have data to be added and just want to provide it up front, you can call “addData(..)” instead, which will take your array. The part of drag and drop that is a little more complicated with multi-drag is having a convincing looking drag proxy. If you don’t know, the drag proxy is what the user sees being moved around the screen during a drag. We’ve been creating bitmaps of the items we move instead of using the ghosted outline that is the default. When dragging multiple objects, we had to create a bunch of bitmaps and translation matricies that are used to create a bigger bitmap (which becomes the drag proxy).

To get the data in the DRAG_DROP handler, you can use some code like this;

if (event.dragSource.hasFormat("items"))
    var items:Array = event.dragSource.dataForFormat("items") as Array;
}

The default drag proxy is OK, but we have been creating custom bitmaps to give a nicer “drag” appearance. This got more complicated with multi-drag. The solution involves iterating through the separate drag items and creating separate bitmaps with transform matricies. Using those, and some other variables to track the bounding box for all of the items, it is possible to build a larger bitmap and paste the smaller images in (using the positional transforms). If you do this, don’t forget to apply a transform to the final drag proxy image to offset the actual click location within the larger bitmap. If you don’t your drag proxy will render with its upper left corner at the mouse, instead of where it should be.

Advertisements

2 thoughts on “Flex Multi-Drag

  1. Thanks for the post, this really helped me. My list control wasn’t firing off a completion event after I dragged an item to a custom component. This provided me with what I needed to know to call my own completion function.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s