Dragging and Dropping new windows from an AIR application

Drag and drop new windows from an AIR application.

Recently I was tasked with writing an AIR application that had tear-off windows. The more I tried to use the DragManager and the NativeDragManager, the more frustrated I became. For the reasons outlined below, I was forced to come up with a custom dragging solution to get the proper tear-off behavior.

Adobe’s AIR and Flex support drag-and-drop though the use of two drag drop managers; the DragManager (supported in Flex and AIR) and the NativeDragManager (supported in AIR). What isn’t well documented is the various flavors of drag-and-drop these managers can enable. I am going to discuss three of those flavors. The first and most common is intra-application drag and drop - this method can be used in Flex and AIR. The next two methods are AIR-only: IO-based and tear-off.

This sample AIR app demonstrates each of the three behaviors.

Intra-application dragging is the act of reordering items in a list, or anything else having to do with dragging within the same application. In order to accomplish this you will need to use the DragManager. The DragManager is a great tool in the Flex coder’s bag of tricks. The manager needs to know what the original drag target is, and which objects can accept the DragEvent.DRAG_DROP  event. There are additional parameters that allow you to use custom drag proxies (images) but the default behavior is good enough for this discussion.

public function startFlexDragevent MouseEvent ) : void
// Set up the drag target and image of it
dragItem UIComponentevent.currentTarget );
dragImg getImagedragItem );
dsource:DragSource = new DragSource();

When using the DragManager, my drag proxy would come out of my application and look great. The cursor on the drag proxy would give negative feedback if I dragged my item outside the AIR application. But what if the user wants to drag something outside the application window? I can create a window at this spot – but DragManager would make the proxy animate back to the item’s original location. If there is any way to tell the desktop that the user’s selected drop spot is a valid drop target, I would love to know.

IO dragging is the act of dragging files between your host machine and an AIR application. In order to enable this behavior, you will need to use the NativeDragManager. The NativeDragManager, like the DragManager, needs to know the drag target. Since the NativeDragManager interacts with the host machine, it does not need to know what objects can accept drop events. It does, however, need a Clipboard  with a file attached, and and a set of NativeDragOptions. The Clipboard holds the data to be moved to/from the application/host machine. NativeDragOptions are Booleans that describe what drag options are available for this data – examples are allowCopy, allowLink, and allowMove.

public function startNativeDragevent MouseEvent ) : void
// Set up the drag target and image of it
dragItem UIComponentevent.currentTarget );
dragImg getImagedragItem );
// Make something to add to the clipboard
var dummyFile:File = new File("/");
// This establishes an offset from where the mouse is and where the drag image will be
    // by default the mouse it at the top left corner of the image
var offset Point = new Point( -event.localX, -event.localY);
clip Clipboard = new Clipboard();
bd BitmapData = new BitmapDatadragItem.widthdragItem.height );
bd.drawdragItem );
dragOptions NativeDragOptions = new NativeDragOptions();
dragOptions.allowCopy true;
dragOptions.allowLink true;
dragOptions.allowMove false;
dragItem.addEventListenerNativeDragEvent.NATIVE_DRAG_COMPLETEstopNativeDrag );
NativeDragManager.doDragdragItemclipbdoffsetdragOptions );

When using the NativeDragManager, the drag proxy will interact with windows and applications it’s dragged over. In the demo, be sure to drag your panels over several applications and look at the cursor feedback. In some, you’ll see applications react to the drag proxy. In my case, this wasn’t acceptable, as I was trying to drag a window to the desktop, not into an application.

Enter the custom tear-off drag behavior. In a nutshell, with this solution, you do away with the drag proxy, creating a NativeWindow in its place. Like the proxy, the Native Window needs to know the original drag target. Once the user starts dragging a new NativeWindow, your code adds a child to its stage. The child you add is the Flex/AIR component you want to populate the window. Once the window has been created and activated, you need to call startDrag on it. That will make the window follow the mouse until the user lets go of the mouse button.
There is a slight hiccup here as I have been unable to capture the actual MouseEvent.MOUSE_UP event. Again I turn to you, if you know how, when or where to catch this event, that would be great. My workaround is to attach a MouseEvent.MOUSE_MOVE event to the window. Once that event fires, you will need to remove it and handle the dropping logic. In the sample application, I delete the window if it hasn’t moved more than 15px. Your applications may have other logic, letting each window be dragged one time or only allow items be dragged in certain directions.

public function startCustomDragevent MouseEvent ) : void
// Set up the drag target and image of it
dragItem UIComponentevent.currentTarget );
dragImg getImagedragItem );
// Figure out where the new window should be placed on the screen
startPos dragItem.localToGlobal( new Point() );
startPos stage.nativeWindow.globalToScreenstartPos );
// Create the actual container for the window
var viewer ItemWindow = new ItemWindow();
viewer.width    dragItem.width;
viewer.height    dragItem.height;
// This is needed in order to makes the dragCanvas.stage not null
// Just setting the fill colors, this will be more meaningful data in your case
viewer.itemViewer.startColor ItemViewer(dragItem).startColor;
viewer.itemViewer.endColor ItemViewer(dragItem).endColor;
// Create the final window to sit on the desktop
dragWin createWindowdragItem.widthdragItem.heightstartPos);
dragWin.stage.align StageAlign.TOP_LEFT;
dragWin.stage.scaleMode StageScaleMode.NO_SCALE;
// This lets the new window be moved around the stage after it has been initially placed
Event ) : void{; });

dragWin.stage.addEventListenerMouseEvent.MOUSE_MOVEthis.stopCustomDrag );

public function stopCustomDragevent MouseEvent ) : void
// Here is where you decide if it was a valid drag.
    // How far did it move, is it over something meaningful, things like that...
dragWin.stage.removeEventListenerMouseEvent.MOUSE_MOVEstopCustomDrag );
delta Number Point.distancestartPos, new PointdragWin.xdragWin.));
delta 15 )

I’ve gone through three methods of drag-and-drop behavior in ActionScript. The first and most common was intra-application dragging for AIR and Flex;  the second and third, which are AIR-only, are the IO dragging and the custom tear-off methods. I encourage you to take a look at the sample application and let me know what you think.


My comments is for both source code and website look and feel.Very nice. I feel i am in 1990 while looking on this site.

Posted by Poondi thasan on Jan 10, 2011

Hi the drag and drop code works fine….
How to do this in the case of mp3 or Wav files. and also i want to drag an mp3 file from AIR application to system desktop.

Posted by karthik on Jan 21, 2011

Enter a comment - moderated

Commenting is not available in this weblog entry.