Adobe Flex 3 Help

Manually adding drag-and-drop support

The list-based controls have built-in support for drag and drop, but you can use drag and drop with any Flex component. To support drag-and-drop operations with non-list-based components, or to explicitly control drag and drop with list-based controls, you must handle the drag and drop events.

Classes used in drag-and-drop operations

You use the following classes to implement the drag-and-drop operation:

Class

Function

DragManager

Manages the drag-and-drop operations; for example, its doDrag() method starts the drag operation.

DragSource

Contains the data being dragged. It also provides additional drag management features, such as the ability to add a handler that is called when data is requested.

DragEvent

Represents the event object for all drag-and-drop events.

Drag-and-drop events for a drag initiator

A component that acts as a drag initiator handles the following events to manage the drag-and-drop operation:

Drag initiator
event

Description

Handler
required

Implemented
by list controls

mouseDown and
mouseMove

The mouseDown event is dispatched when the user selects a control with the mouse and holds down the mouse button. The mouseMove event is dispatched when the mouse moves.

Yes, for nonlist controls

No

dragStart

Dispatched by a list-based component when a drag operation starts. This event is used internally by the list-based controls; you do not handle it when implementing drag and drop.

If you want to control the start of a drag-and-drop operation, use the mouseDown or mouseMove event.

Yes, for list controls

Yes

dragComplete

Dispatched when a drag operation completes, either when the drag data drops onto a drop target, or when the drag-and-drop operation ends without performing a drop operation.

You can use this event to perform any final cleanup of the drag-and-drop operation. For example, if a user moves data from one component to another, you can use this event to delete the item from the drag initiator. For an example, see Example: Moving and copying data for a nonlist-based control.

No

Yes

When adding drag-and-drop support to a component, you must implement an event handler for either the mouseDown or mouseMove event, and optionally for the dragComplete event. When you set the dragEnabled property to true for a list-based control, Flex automatically adds event handlers for the dragStart and dragComplete events.

Note: Do not add an event handler for the dragStart event. That is an internal event handled by Flex.

Drag-and-drop events for a drop target

To use a component as a drop target, you handle the following events:

Drop target
event

Description

Handler required

Implemented
by list controls

dragEnter

Dispatched when a drag proxy moves over the drop target from outside the drop target.

A component must define an event handler for this event to be a drop target. The event handler determines whether the data being dragged is in an accepted format. To accept the drop, the event handler calls the DragManager.acceptDragDrop() method. You must call the DragManager.acceptDragDrop() method for the drop target to receive the dragOver, dragExit, and dragDrop events.

In the handler, you can change the appearance of the drop target to provide visual feedback to the user that the component can accept the drag operation. For example, you can draw a border around the drop target, or give focus to the drop target. For an example, see Example: Simple drag-and-drop operation for a nonlist-based control.

Yes

Yes

dragOver

Dispatched while the user moves the mouse over the target, after the dragEnter event.

You can handle this event to perform additional logic before allowing the drop operation, such as dropping data to various locations within the drop target, reading keyboard input to determine if the drag-and-drop operation is a move or copy of the drag data, or providing different types of visual feedback based on the type of drag-and-drop operation. For an example, see Example: Handling the dragOver and dragExit events for the drop target.

No

Yes

dragDrop

Dispatched when the user releases the mouse over the drop target.

Use this event handler to add the drag data to the drop target. For an example, see Example: Simple drag-and-drop operation for a nonlist-based control.

Yes

Yes

dragExit

Dispatched when the user moves the drag proxy off of the drop target, but does not drop the data onto the target.

You can use this event to restore the drop target to its normal appearance if you modified its appearance in response to a dragEnter event or other event. For an example, see Example: Handling the dragOver and dragExit events for the drop target.

No

Yes

When adding drag-and-drop support to a nonlist-based component, you must implement an event handler for the dragEnter and dragDrop events, and optionally for the other events. When you set the dropEnabled property to true for a list-based control, Flex automatically adds event handlers for all events.

The drag-and-drop operation

The following steps define the drag-and-drop operation.

  1. A component becomes a drag-and-drop initiator in either of the following ways:
    • List-based components with dragEnabled=true

      Flex automatically makes the component an initiator when the user clicks and moves the mouse on the component.

    • Nonlist-based components, or list-based components with dragEnabled=false

      The component must detect the user's attempt to start a drag operation and explicitly become an initiator. Typically, you use the mouseMove or mouseDown event to start the drag-and-drop operation.

      The component then creates an instance of the mx.core.DragSource class that contains the data to be dragged, and specifies the format for the data.

      The component then calls the mx.managers.DragManager.doDrag() method, to initiate the drag-and-drop operation.

  2. While the mouse button is still pressed, the user moves the mouse around the application. Flex displays the drag proxy image in your application. The DragManager.defaultDragImageSkin property defines the default drag proxy image.

    You can define your own drag proxy image. For more information, see Example: Specifying the drag proxy.

    Note: Releasing the mouse button when the drag proxy is not over a target ends the drag-and-drop operation. Flex generates a DragComplete event on the drag initiator, and the DragManager.getFeedback() method returns DragManager.NONE.

  3. If the user moves the drag proxy over a Flex component, Flex dispatches a dragEnter event for the component.
    • List-based components with dropEnabled=true

      Flex checks to see if the component can be a drop target.

    • Nonlist-based components, or list-based components with dropEnabled=false

      The component must define an event handler for the dragEnter event to be a drop target.

    The dragEnter event handler can examine the DragSource object to determine whether the data being dragged is in an accepted format. To accept the drop, the event handler calls the DragManager.acceptDragDrop() method. You must call the DragManager.acceptDragDrop() method for the drop target to receive the dragOver, dragExit, and dragDrop events.

    • If the drop target does not accept the drop, the drop target component's parent chain is examined to determine if any component in the chain accepts the drop data.
    • If the drop target or a parent component accepts the drop, Flex dispatches the dragOver event as the user moves the proxy over the target.
  4. (Optional) The drop target can handle the dragOver event. For example, the drop target can use this event handler to set the focus on itself.
  5. (Optional) If the user decides not to drop the data onto the drop target and moves the drag proxy outside of the drop target without releasing the mouse button, Flex dispatches a dragExit event for the drop target. The drop target can optionally handle this event; for example, to undo any actions made in the dragOver event handler.
  6. If the user releases the mouse while over the drop target, Flex dispatches a dragDrop event on the drop target.
    • List-based components with dropEnabled=true

      Flex automatically adds the drag data to the drop target. If this is a copy operation, you have to implement the event handler for the dragDrop event for a list-based control. For more information, see Example: Copying data from one List control to another List control.

    • Nonlist-based components, or list-based components with dropEnabled=false

      The drop target must define an event listener for the dragDrop event handler to add the drag data to the drop target.

  7. (Optional) When the drop operation completes, Flex dispatches a dragComplete event. The drag initiator can handle this event; for example, to delete the drag data from the drag initiator in the case of a move.
    • List-based components with dragEnabled=true

      If this is a move operation, Flex automatically removes the drag data from the drag initiator.

    • Nonlist-based components, or list-based components with dragEnabled=false

      The drag initiator completes any final processing required. If this was a move operation, the event handler must remove the drag data from the drag initiator. For an example of writing the event handler for the dragComplete event, see Example: Moving and copying data for a nonlist-based control.

Example: Simple drag-and-drop operation for a nonlist-based control

The following example lets you set the background color of a Canvas container by dropping either of two colors onto it. You are not copying or moving any data; instead, you are using the two drag initiators as a color palette. You then drag the color from one palette onto the drop target to set its background color.

The drag initiators, two Canvas containers, implement an event handler for the mouseDown event to initiate the drag and drop operation. This is the only event required to be handled by the drag initiator. The drop target is required to implement event handlers for the dragEnter and dragDrop events.

<?xml version="1.0"?>
<!-- dragdrop\DandDCanvas.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    backgroundColor="white">

    <mx:Script>
        <![CDATA[

        import mx.core.DragSource;
        import mx.managers.DragManager;
        import mx.events.*;
        import mx.containers.Canvas;

        // Initializes the drag and drop operation.
        private function mouseMoveHandler(event:MouseEvent):void {
            
            // Get the drag initiator component from the event object.
            var dragInitiator:Canvas=Canvas(event.currentTarget);
            
            // Get the color of the drag initiator component.
            var dragColor:int = dragInitiator.getStyle('backgroundColor');

            // Create a DragSource object.
            var ds:DragSource = new DragSource();

            // Add the data to the object.
            ds.addData(dragColor, 'color');

            // Call the DragManager doDrag() method to start the drag. 
            DragManager.doDrag(dragInitiator, ds, event);
        }

        // Called when the user moves the drag proxy onto the drop target.
        private function dragEnterHandler(event:DragEvent):void {

            // Accept the drag only if the user is dragging data 
            // identified by the 'color' format value.
            if (event.dragSource.hasFormat('color')) {

                // Get the drop target component from the event object.
                var dropTarget:Canvas=Canvas(event.currentTarget);
                // Accept the drop.
                DragManager.acceptDragDrop(dropTarget);
            }
        }
                
        // Called if the target accepts the dragged object and the user 
        // releases the mouse button while over the Canvas container. 
        private function dragDropHandler(event:DragEvent):void {

            // Get the data identified by the color format 
            // from the drag source.
            var data:Object = event.dragSource.dataForFormat('color');
            // Set the canvas color.
            myCanvas.setStyle("backgroundColor", data);
        }    
        ]]>
    </mx:Script>

    <!-- A horizontal box with red and green canvases that the user can drag. -->
    <mx:HBox>
        <mx:Canvas 
            width="30" height="30" 
            backgroundColor="red" 
            borderStyle="solid" 
            mouseMove="mouseMoveHandler(event);"/>
        <mx:Canvas 
            width="30" height="30" 
            backgroundColor="green" 
            borderStyle="solid" 
            mouseMove="mouseMoveHandler(event);"/>
    </mx:HBox>

    <mx:Label text="Drag a color onto the Canvas container."/>

    <!-- Handles dragEnter and dragDrop events to allow dropping. -->
    <mx:Canvas id="myCanvas" 
        width="100" height="100" 
        backgroundColor="#FFFFFF" 
        borderStyle="solid" 
        dragEnter="dragEnterHandler(event);" 
        dragDrop="dragDropHandler(event);"/>
        
    <mx:Button id="b1" 
        label="Clear Canvas" 
        click="myCanvas.setStyle('backgroundColor', '0xFFFFFF');"
    />        
</mx:Application>

The executing SWF file for the previous example is shown below:

The following sections describe the event handlers for the mouseDown, dragEnter, and dragDrop events.

Writing the mouseDown event handler

The event handler that initiates a drag-and-drop operation must do two things.

  1. Create a DragSource object and initialize it with the drag data and the data format.

    The DragSource object contains the drag data and a description of the drag data, called the data format. The event object for the dragEnter and dragDrop events contains a reference to this object in their dragSource property, which allows the event handlers to access the drag data.

    You use the DragSource.addData() method to add the drag data and format to the DragSource object, where the addData() method has the following signature:

    addData(data:Object, format:String):void
    
    

    The format argument is a text string such as "color", "list data", or "employee record". In the event handler for the dragEnter event, the drop target examines this string to determine whether the data format matches the type of data that the drop target accepts. If the format matches, the drop target lets users drop the data on the target; if the format does not match, the target does not enable the drop operation.

    One example of using the format string is when you have multiple components in your application that function as drop targets. Each drop target examines the DragSource object during its dragEnter event to determine if the drop target supports that format. For more information, see Handling the dragEnter event.

    Note: List controls have predefined values for the format argument. For all list controls other than the Tree control, the format String is "items". For the Tree control, the format String is "treeItems". For more information, see Using drag-and-drop with list-based controls.

    If you drag large or complex data items, consider creating a handler to copy the data, and specify it by calling the DragSource.addListener() method instead of using the DragSource.addData() method. If you do this, the data does not get copied until the user drops it, which avoids the processing overhead of copying the data if a user starts dragging data but never drops it. The implementation of the list-based classes use this technique.

  2. Call the DragManager.doDrag() method to start the drag-and-drop operation.

    The doDrag() method has the following signature:

    doDrag(dragInitiator:IUIComponent, dragSource:DragSource, mouseEvent:MouseEvent,
    dragImage:IFlexDisplayObject = null, xOffset:Number = 0, yOffset:Number = 0,
    imageAlpha:Number = 0.5, allowMove:Boolean = true):void

    The doDrag() method requires three arguments: a reference to the component that initiates the drag operation (identified by the event.currentTarget object); the DragSource object that you created in step 1, and the event object passed to the event handler.

    Optional arguments specify the drag proxy image and the characteristics of the image. For an example that specifies a drag proxy, see Example: Specifying the drag proxy.

Handling the dragEnter event

Flex generates a dragEnter event when the user moves the drag proxy over any control. A control must define a handler for a dragEnter event to be a drop target. The event handler typically performs the following actions:

  • Use the format information in the DragSource object to determine whether the drag data is in a format accepted by the drop target.
  • If the drag data is in a compatible format, the handler must call the DragManager.acceptDragDrop() method to enable the user to drop the data on the drop target. If the event handler does not call this method, the user cannot drop the data and the drop target will not receive the dragOver, dragExit, and dragDrop events.
  • Optionally, perform any other actions necessary when the user first drags a drag proxy over a drop target.

The value of the action property of the event object for the dragEnter event is DragManager.MOVE, even if you are doing a copy. This is because the dragEnter event occurs before the drop target recognizes that the Control key is pressed to signal a copy.

The Flex default event handler for the dragOver event for a list-based control automatically sets the action property. For nonlist-based controls, or if you explicitly handle the dragOver event for a list-based control, use the DragManager.showFeedback() method to set the action property to a value that signifies the type of drag operation: DragManager.COPY, DragManager.LINK, DragManager.MOVE, or DragManager.NONE. For more information on the dragOver event, see Example: Handling the dragOver and dragExit events for the drop target.

Handling the dragDrop event

The dragDrop event occurs when the user releases the mouse to drop data on a target, and the dragEnter event handler has called the DragManager.acceptDragDrop() method to accept the drop. You must define a handler for the event to add the drag data to the drop target.

The event handler uses the DragSource.dataForFormat() method to retrieve the drag data. In the previous example, the drag data contains the new background color of the drop target. The event handler then calls setStyle() to set the background color of the drop target.

Example: Handling drag and drop events in a list-based control

Flex automatically defines default event handlers for the drag-and-drop events when you set dragEnabled or dropEnabled property to true for a list-based control. You can either use these default event handlers, which requires you to do no additional work in your application, or define your own event handlers.

There are three common scenarios for using event handlers with the list-based controls:

Use the default event handlers 

When you set dragEnabled to true for a drag initiator, or when you set dropEnabled to true for a drop target, Flex handles all drag-and-drop events for you for a move. You only have to define your own dragDrop event handler when you want to copy data as part of the drag-and-drop operation. For more information, see Moving and copying data.



Define your own event handlers 

If you want to control the drag-and-drop operation for a list-based control, you can explicitly handle the drag-and-drop events, just as you can for any component. In this scenario, set the dragEnabled property to false for a drag initiator, or set the dropEnabled property to false for a drop target. For more information on handling these events, see Example: Simple drag-and-drop operation for a nonlist-based control.



Define your own event handlers and use the default event handlers 

You might want to add your own event handler for a drag-and-drop event, and also use the build in drag-and-drop handlers. In this case, your event handler executes first, then the default event handler provided by Flex executes. If, for any reason, you want to explicitly prohibit the execution of the default event handler, call the Event.preventDefault() method from within your event handler.



Note: If you call Event.preventDefault() in the event handler for the dragComplete or dragDrop event for a Tree control when dragging data from one Tree control to another, it prevents the drop.

Because of the way data to a Tree control is structured, the Tree control handles drag and drop differently from the other list-based controls. For the Tree control, the event handler for the dragDrop event only performs an action when you move or copy data in the same Tree control, or copy data to another Tree control. If you drag data from one Tree control and drop it onto another Tree control to move the data, the event handler for the dragComplete event actually performs the work to add the data to the destination Tree control, rather than the event handler for the dragDrop event, and also removes the data from the source Tree control. This is necessary because to reparent the data being moved, Flex must remove it first from the source Tree control.

Therefore, if you call Event.preventDefault() in the event handler for the dragDrop or dragComplete events, you implement the drop behavior yourself. For more information, see Example: Moving and copying data for a nonlist-based control.

The following example modifies the example shown in the section Example: Moving and copying data for a nonlist-based control to define an event handler for the dragDrop event that accesses the data dragged from one DataGrid control to another. This event handler is executed before the default event handler for the dragDrop event to display in an Alert control the Artist field of each DataGrid row dragged from the drag initiator to the drop target:

<?xml version="1.0"?>
<!-- dragdrop\SimpleDGToDGAlert.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    creationComplete="initApp();">

    <mx:Script>
        <![CDATA[        
            import mx.events.DragEvent; 
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;
            
            private function initApp():void {
              srcgrid.dataProvider =  new ArrayCollection([
                {Artist:'Carole King', Album:'Tapestry', Price:11.99},
                {Artist:'Paul Simon', Album:'Graceland', Price:10.99},
                {Artist:'Original Cast', Album:'Camelot', Price:12.99},
                {Artist:'The Beatles', Album:'The White Album', Price:11.99}
              ]);
                
                destgrid.dataProvider = new ArrayCollection([]);
            }

            // Define the event listener.
            public function dragDropHandler(event:DragEvent):void {    
                // dataForFormat() always returns an Array 
                // for the list-based controls 
                // in case multiple items were selected.
                var dragObj:Array=
                    event.dragSource.dataForFormat("items") as Array; 

                // Get the Artist for all dragged albums.
                var artistList:String='';
                for (var i:Number = 0; i < dragObj.length; i++) { 
                    artistList+='Artist: ' + dragObj[i].Artist + '\n';
                }
                
                Alert.show(artistList);                
            }           
        ]]>
    </mx:Script>

    <mx:HBox>
        <mx:VBox>
            <mx:Label text="Available Albums"/>
            <mx:DataGrid id="srcgrid" 
                allowMultipleSelection="true" 
                dragEnabled="true" 
                dropEnabled="true" 
                dragMoveEnabled="true">                
                <mx:columns>
                    <mx:DataGridColumn dataField="Artist"/>
                    <mx:DataGridColumn dataField="Album"/>
                    <mx:DataGridColumn dataField="Price"/>
                </mx:columns>    
            </mx:DataGrid>
        </mx:VBox>

        <mx:VBox>
            <mx:Label text="Buy These Albums"/>
            <mx:DataGrid id="destgrid" 
                allowMultipleSelection="true" 
                dragEnabled="true" 
                dropEnabled="true" 
                dragMoveEnabled="true" 
                dragDrop="dragDropHandler(event);">                
                <mx:columns>
                    <mx:DataGridColumn dataField="Artist"/>
                    <mx:DataGridColumn dataField="Album"/>
                    <mx:DataGridColumn dataField="Price"/>
                </mx:columns>    
            </mx:DataGrid>
        </mx:VBox>
    </mx:HBox>

    <mx:Button id="b1" 
        label="Reset"
        click="initApp()"
    />

</mx:Application>

The executing SWF file for the previous example is shown below:

Notice that the dataForFormat() method specifies an argument value of "items". This is because the list-based controls have predefined values for the data format of drag data. For all list controls other than the Tree control, the format String is "items". For the Tree control, the format String is "treeItems".

Notice also that the return value of the dataForFormat() method is an Array. The dataForFormat() method always returns an Array for a list-based control, even if you are only dragging a single item, because list-based controls let you select multiple items.