Publishers of technology books, eBooks, and videos for creative people

Home > Articles > Web Design & Development > Adobe AIR

Implementing Drag and Drop Between the OS and AIR

Create AIR applications that have the look and feel of more traditional desktop applications.
This chapter is from the book

The previous chapter explored the rich integration that AIR has with the Operating System (OS) clipboard. In this chapter, you will further explore integration possibilities using drag and drop, a technique familiar to most desktop application users. This technique, combined with others you will learn throughout this book, allows you to create AIR applications that have the look and feel of more traditional desktop applications.

The following sections explain the DragManager and NativeDragManager classes, and include several examples of using each. You will also explore the drag-and-drop operations used within the dpTimeTracker to gain an understanding of how these pieces can be used together in a larger application.

To use drag and drop successfully, you will need familiarity with two main classes, namely DragManager and NativeDragManager. These classes are responsible for handling all elements dragged within an application. Both are responsible for initiating, accepting, and presenting feedback for drag-and-drop operations, application wide. You will learn about the DragManager first to give you an understanding of basic drag-and-drop operations within an application. Then you will explore the NativeDragManager to learn about dragging items in and out of the application and interacting with the OS.

Drag and Drop in an Application (DragManager Class)

The DragManager is native to the Flex API and handles all the internal drag-and-drop actions in an application, but it has no effect outside of the application window. All Flex components have some level of support for drag-and-drop operations. It is up to the developer to handle the specific user actions (such as mouse down, drag enter, and so on) and properly use the DragManager to handle them. The drag-and-drop process has a few important terms and events worth noting. Keep in mind that the NativeDragManager also uses similar events and terms with slight variances, which we will discuss in the next section.

  • Drag Initiator—The interactive object that begins the drag action and also dispatches the dragStart and dragComplete events.
  • Drag Proxy—The visual representation of the item being dragged that follows your cursor. Usually it is depicted as a faded silhouette of the object, but it can be customized by the user as well. DragManager can assign any InteractiveObject to be the proxy.
  • Drop Target—A visual object where a dragged item can be dropped. The drop target makes the final decision on whether the type of object being dragged can be dropped at this location.
  • dragEnter—The event dispatched when an item is dragged over a possible drop target. As you will see, this event is often used with the DragManager.acceptDrop() method to grant an object permission to be dropped.
  • dragOver—The event dispatched repeatedly as the item is dragged over an interactive object.
  • dragExit—The event dispatched when the dragged item leaves an interactive object.
  • dragDrop—The event dispatched when the mouse is released over an eligible drop target. The event handler will be able to access the dropped data by using the event.dragSource object.
  • dragComplete—The event dispatched from the drag initiator when the drop is completed. This event allows you to gather feedback on the success of the drop as well as clean up data in the drag initiator.

This first sample shows dragging from a simple list control to another. When initiating a drag between two drag-enabled components (such as List, Tree, and DataGrid, to name a few), it is a simple process to configure the controls. Listing 1 shows the MXML tags for the List control; take note of the dragEnabled, dropEnabled, and dragMoveEnabled attributes.

Listing 1.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" >
    <mx:List
        id="list1"
        height="50%"
        dragEnabled="true"
        dropEnabled="true"
        dragMoveEnabled="true">
        <mx:dataProvider>
            <mx:String>AIR</mx:String>
            <mx:String>Flex</mx:String>
            <mx:String>Flash</mx:String>
            <mx:String>PhotoShop</mx:String>
            <mx:String>Fireworks</mx:String>
        </mx:dataProvider>
    </mx:List>
    <mx:List
        id="list2"
        height="50%"
        dragEnabled="true"
        dropEnabled="true"
        dragMoveEnabled="true">
        <mx:dataProvider>
            <mx:String>LiveCycle ES</mx:String>
            <mx:String>Blaze DS</mx:String>
            <mx:String>ColdFusion</mx:String>
        </mx:dataProvider>
    </mx:List>
</mx:WindowedApplication>

With dragEnabled, dropEnabled, and dragMoveEnabled attributes set to true, the Lists will allow users to move items from one List control to the other by clicking it and dragging it. If you want the user to copy from one to the other, instead of moving, change the dragMoveEnabled attribute from true to false, or remove the attribute entirely (false is the default value). The List will automatically update the drop target’s (the destination List’s) data provider. Using this technique, you do not have control over the appearance of the item as it is being dragged, or any fine-grained control over the operation. However, using this approach you can very quickly enable basic drag-and-drop operations in an application.

Listing 2 shows dragging from a List to any other type of UI control, in this case, a Label. Much like the List control from the previous example, the dragEnabled and dragMoveEnabled properties remain true on the List. However, the dropEnabled property is no longer needed and has been removed (so it will have the default value of false).

Listing 2.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
    <![CDATA[
    import mx.managers.DragManager;
    import mx.events.DragEvent;
    protected function handleDragEnter( event : DragEvent ) : void{
        DragManager.acceptDragDrop( event.target as Label );
    }
    protected function handleDrop ( event : DragEvent ) : void{
        var dropItem:Object = event.dragSource.dataForFormat( "items" );
        dropLbl.text = dropItem.toString();
    }
    ]]>
    </mx:Script>
    <mx:Label id="dropLbl"
        text="Drop on Me"
        dragDrop="handleDrop( event )"
        dragEnter="handleDragEnter( event )"/>

    <mx:List id="list1"
        height="50%"
        dragEnabled="true"
        dragMoveEnabled="true">
        <mx:dataProvider>
            <mx:String>AIR</mx:String>
            <mx:String>Flex</mx:String>
            <mx:String>Flash</mx:String>
            <mx:String>PhotoShop</mx:String>
            <mx:String>Fireworks</mx:String>
        </mx:dataProvider>
    </mx:List>

</mx:WindowedApplication>

Unlike the List from Listing 1, the Label class does not have a dropEnabled property (only a few classes, such as List, DataGrid, and Tree do), so for it to accept the drop, the user must create the event handlers to deal with this action. Notice that a dragEnter event handler has been added to the Label. This event fires when the user drags a component over the Label. When this happens, the handleDragEnter() function will execute.

In the handleDragEnter() function, the DragManager is instructed to allow the drop on this target. To do this, handleDragEnter() calls DragManager.acceptDragDrop() and passes the element on which the drop will be allowed (in this case the Label). In more complex examples, a conditional statement would determine if the item being dragged is the proper type and if it is allowed by the current target. In this simple example, all dragged elements are allowed to be dropped.

When dropping an element on the target, the target’s dragDrop event fires. In this example, the handleDrop() function is registered to handle the dragDrop event. In the handleDrop() function you will change the text displayed in dropLbl, which is the name of your Label control in Listing 2. The text property will be set using the data from the drag event.

Internally, DragManager keeps all the data being dragged in an instance of the DragSource class. This DragSource instance contains one or more copies of the data in different formats. For example, the same data could be dragged as text, as an image, or perhaps as HTML. When the dragged item is dropped, the instance of the DragSource class containing this data is available via the dragSource property of the DragEvent event.

The data inside dragSource is retrieved by using the dataForFormat() function of the dragSource, which accepts a string as an argument. When data is dragged from a dragenabled List control, it is available in a format named “items.” In this case, the data provider contains only a collection of strings, so it can easily be set as the text property of the Label.

In this last example for this section, you will learn to use the DragManager to copy a simple “person” object, created from data in a Label, into a List control without using any of the native drag-and-drop behaviors of the List.

Listing 3.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.core.IUIComponent;
    import mx.core.DragSource;
    import mx.managers.DragManager;
    import mx.events.DragEvent;

    private function handleDragBegin( event : MouseEvent ):void {
        var person : Object = new Object();
        person.nameAge = Label(event.currentTarget).text;
        person.comment = "We are dragging " + person.nameAge;
        var dSource : DragSource = new DragSource();
        dSource.addData( person, "people" );
        var label:Label = new Label();
        label.text = person.comment;
        DragManager.doDrag( event.currentTarget as Label, dSource, event,
        ccc.giflabel, 0 , 0, .5);

    }
    private function handleDragEnter( event:DragEvent ):void {
        if ( event.dragSource.hasFormat("people") ) {
            DragManager.acceptDragDrop( IUIComponent(
            ccc.gifevent.currentTarget ) );
            DragManager.showFeedback( DragManager.COPY );
        }
    }
    private function handleDrop( event : DragEvent ):void {
        if(!list1.dataProvider){
            list1.dataProvider = new ArrayCollection();
        }
        list1.dataProvider.addItem( event.dragSource.dataForFormat(
        ccc.gif"people") );
    }
    ]]>
</mx:Script>
<mx:HBox>
    <mx:Label
        text="Frank, 26"
        mouseDown="handleDragBegin( event )"/>
    <mx:Label
        text="Mike, 33"
        mouseDown="handleDragBegin( event )"/>
    <mx:Label
        text="Jeff, 37"
        mouseDown="handleDragBegin( event )"/>
</mx:HBox>
<mx:List
    id="list1"
    height="50%"
    labelField="nameAge"
    dragEnabled="false"
    dropEnabled="false"
    dragDrop="handleDrop( event )"
    dragEnter="handleDragEnter( event )"/>

</mx:WindowedApplication>

The handleDragBegin() function is registered to handle the mouseDown event on any of the three labels. When a mouseDown event occurs on one of these labels, the dragging process begins. Look at the following handleDragBegin() function from Listing 3.

private function handleDragBegin( event : MouseEvent ):void {
    var person : Object = new Object();
    person.nameAge = Label(event.currentTarget).text;
    person.comment = "We are dragging " + person.nameAge;
    var dSource : DragSource = new DragSource();
    dSource.addData( person, "people" );
    var label:Label = new Label();
    label.text = person.comment;
    DragManager.doDrag( event.currentTarget as Label, dSource, event,
    ccc.giflabel, 0 , 0, .5);
}

In the handleDragBegin() function, several different things need to take place to prepare the drag. First, an object is created and the nameAge property is set to the text of the label that is being dragged. Next, the comment property is set to the string “We are dragging” followed by whatever the text was in the selected label, so it will read “We are dragging Mike, 33,” when the middle label is dragged. Next a DragSource instance called dSource is created. As the previous example explained, this is where the data related to the drag operation will be stored.

var dSource : DragSource = new DragSource();
dSource.addData( person, "people" );

The addData() function on dSource adds the person object. The addData() function requires an argument of type Object and a format of type String. In this case, the person object will be the data and the format will be the string “people”.

The next piece of this function involves making a drag proxy image that will represent the drag when you’re moving your cursor. This step is optional.

var label:Label = new Label();
label.text = person.comment;

If you decide to create a proxy, you’ll need a visual component to represent the dragged data. This example uses a label, with the text “you are dragging” followed by whatever text the dragged label contained.

Now you’re ready to start the drag, is done by using the static function DragManager.doDrag().

DragManager.doDrag( event.currentTarget as Label, dSource, event, label,0 ,0,.5);

Notice that the doDrag() function requires several arguments. The first argument is the dragInitiator—the item that is being dragged; this can usually be obtained by using the event.currentTarget. The second argument is the DragSource; this can simply be set to the dSource instance discussed earlier. The third argument is the mouseEvent that started the drag; this would simply be the event parameter passed into this function.

protected function handleDragBegin(event : MouseEvent):void

The next four arguments are for the dragImage, xOffset, yOffset, and imageAlpha, and all are optional. These are all related to the proxy that is shown when the label is being dragged around. In this example, the dragImage is the newly created label “you are dragging.” The xOffset and yOffset determine where to place the image in relation to your mouse cursor as you are dragging. Lastly, the imageAlpha defines the opacity of the proxy image, with 1 indicating that it should be fully opaque and 0 indicating that it should be completely transparent (to the point of invisibility). The value of .5 offers a half–faded-out label as the proxy.

Figure 1

Figure 1 By using a drag proxy, the elements shown during a drag are customized.

That covers the events to begin the drag operations. Next you will explore the events on the drop target, dragEnter and dragDrop. Look at the drop target section of Listing 3 that follows.

<mx:List
    id="list1"
    height="50%"
    labelField="nameAge"
    dragEnabled="false"
    dropEnabled="false"
    dragDrop="handleDrop( event )"
    dragEnter="handleDragEnter( event )"/>

Notice that the dragEnabled and dropEnabled properties are disabled and that event handlers for dragEnter and dragDrop have been added. The handleDragEnter() is the listener function for the dragEnter event. This function determines if the item being dragged is allowed to be dropped onto this List. It does so by checking the format (type) of data in the dragSource. If it matches an acceptable format, it will accept the drop.

Listing 4.

private function handleDragEnter(event:DragEvent):void {
    if ( event.dragSource.hasFormat("people") ) {
        DragManager.acceptDragDrop( IUIComponent( event.currentTarget ) );
        DragManager.showFeedback( Dragmanager.COPY );
    }
}

In this case, the conditional statement is looking for data with the format “people”. If the dragSource has a format (type) of “people”, then DragManager.acceptDrop() is called and passes the currentTarget (the List) as the drop target. The List will now accept the drop should you release the mouse.

The next statement marks the first of a few divergences between Flex applications running in the web browser and in AIR. When running from a web browser, the DragManager.showFeedback( feedback : String) changes the mouse cursor. This technique is often used along with keyboard shortcuts (such as the Ctrl or Shift key) to indicate if the data is to be copied or moved. Flex offers four built-in cursors related to drag operations to show that the item will be moved, copied, linked, or not allowed to be dropped. In this example, passing DragManager.COPY to the showFeedback() method changes the mouse pointer to a green plus sign, giving you a visual confirmation that the drop is allowed. The four possible cursors are DragManager.COPY, DragManager.MOVE, DragManager.LINK, and DragManager.NONE. The following figures shows the possible cursors.

Figure 2

Figure 2 The DragManager.COPY feedback

Figure 3

Figure 3 The DragManager.MOVE feedback

Figure 4

Figure 4 The DragManager.LINK feedback

Figure 5

Figure 5 The DragManager.NONE feedback, indicating you are not over an acceptable drop target

Unfortunately, at this time, these feedback options do not work by default in AIR, only in the web browser, due to a difference in the DragManager implementation used in these two environments. This information has been included as it is likely this limitation will disappear in future AIR releases.

The final step to complete the drag-and-drop operation is to handle the drop event using the handleDrop listener function. Listing 4 adds the person object to the dragSource using the “people” format. This object will be copied into the list’s dataProvider when the drop operation completes successfully. Using the event.dragSource.dataForFormat("people"), you can retrieve the person object that was created when the mouse was first clicked and moved above the Label. The following function is from Listing 3.

private function handleDrop ( event : DragEvent ) : void{
    if(!list1.dataProvider){
        list1.dataProvider = new ArrayCollection();
    }
    list1.dataProvider.addItem( event.dragSource.dataForFormat("people") );
}

This function checks if list1’s dataProvider exists. If it does not, the function creates a new ArrayCollection and provides it to the dataProvider property of the list. Lastly, it adds the data from the dragged label to the list’s dataProvider.

The drag operation is currently making a copy of the data, meaning that you could perform this operation multiple times and have duplicate data in the list. If you are interested in moving the item rather than copying it, you could use the dragComplete event to remove the drag initiator from its parent. The following code sample shows you how to go about removing the dragged label using the dragComplete handler.

private function dragCompleteHandler(event:DragEvent):void {
    var draggedLabel:Label = event.dragInitiator as Label;
    var dragParent: Object = draggedLabel.parent;
    if (event.action == DragManager.MOVE)
        dragParent.removeChild( draggedLabel );
}

You now have an understanding of how to drag simple objects using the DragManager, using both drag-enabling properties and custom drag functions.

Peachpit Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from Peachpit and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about Peachpit products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites; develop new products and services; conduct educational research; and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email ask@peachpit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by Adobe Press. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.peachpit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020