Objectives of the Week


Drag and Drop Terminology

A Drag and Drop operation takes place by selecting an object with the mouse and carrying the object to another location on the form. This statement describes what the user sees when a Drag and Drop operation is taking place, but it does not reflect the programming that is necessary to implement such an operation.

The Source Object is almost a non-player here. The majority of the significant programming is done using Target event handlers, with the source object being passed as a parameter.

The Target Event handlers are fired when the source object is dragged over and dropped on the target.

Private Sub Control_DragOver(Source As Control, X As Single, Y As Single, State As Integer)

Private Sub Control_DragDrop(Source As Control, X As Single, Y As Single)

The DragOver Event State parameter has three possible values and describes whether the object is being dragged is entering, leaving, or being dragged over the target. These values are represented using VB constants.

By default the DragMode is Manual, which means that the application must initiate the Drag operation, but if you set a controls DragMode property to Automatic, the user can drag the control to any location on the form. Initiating a Drag operation is related to the Source object. It is the Target Events that will "Listen" for the Source Object to be dropped.

The DragIcon property can be set at design time, but is often modified by the potential targets at run time. The Drag Icon can provide a visual to the user indicating if the target will accept the source in a DragDrop event.

The specifics will be detailed in the examples below.

OLE Drag and Drop

The operations described above are all used to perform operations from WITHIN an application. VB provides a very similar set up events to communicate with other programs. The OLEDragDrop and OLEDragOver events work like the local counterparts. Additional events are required to provide the hooks necessary to build the data structure used to pass the information between applications.


Drag and Drop - Automatic

 Because the DragMode for the controls is set to automatic, this example only has to handle the Target control events. These are the DragOver and the DragDrop events.

UIEX01.jpg (7132 bytes)

 

In this example, when the Source object containing the Place is dropped on the PictureBox Target, the Picture changes.

Private Sub picTarget_DragDrop(Source As Control, X As Single, Y As Single)
    picTarget.Picture = imgDrop.Picture
    lblMessage.Caption = Source.Name & " was dropped on the Picture Box"

End Sub

But if an attempt to drop the place on the Form or the Label, you see a different result.

Private Sub Form_DragDrop(Source As Control, X As Single, Y As Single)
    Source.Visible = True
    lblMessage.Caption = "The form is not a valid Target"

End Sub

Private Sub lblMessage_DragDrop(Source As Control, X As Single, Y As Single)
    Source.Visible = True
    Source.DragIcon = Source.Picture

    lblMessage.Caption = "The Label is not a valid Target"

End Sub

In effect, the DragDrop Event handlers for the Form and the Label indicate that you cannot drop the object here as these objects are not valid targets.

When a Drag Event is initiated, most of the time, the first DragOver event fired is for the Source object itself. To provide a good visual for the user, you must consider these event handlers. In this example, when the DragOver indicates a First Time condition (State = vbEnter), hide the original object letting the DragIcon simulate movement, but be sure to restore the Source Object if the object is dropped on itself.

Private Sub imgSource_DragDrop(Source As Control, X As Single, Y As Single)
    Source.Visible = True

End Sub

Private Sub imgSource_DragOver(Source As Control, X As Single, Y As Single, State As Integer)
    If State = vbEnter Then
        Source.Visible = False
    End If

End Sub

If it is not clear what is happening here, comment out the code and run the program and it will quickly become apparent why these checks are necessary.

A feature that is very important, yet has nothing to do with the actual Drag and Drop process is the management of the DragIcon property. It provides the user with a visual that will help them determine the correct location to release the mouse button that will complete the Drag Drop operation. In this example, holding down the mouse button after a DoubleClick will automatically start the Drag process (because the DragMode is Automatic). In the Target DragOver Events, be sure to keep track of entry and exit so that the Drag Icon can be properly updated.

Private Sub picTarget_DblClick()
    imgSource.Visible = True
    imgSource.DragIcon = imgSource.Picture

End Sub

Private Sub picTarget_DragOver(Source As Control, X As Single, Y As Single, State As Integer)
    If State = vbEnter Then
        Source.DragIcon = imgHidden.Picture
    ElseIf State = vbLeave Then
        Source.DragIcon = Source.Picture
    End If

End Sub

Download the Example


Drag and Drop - Manual

This example features a Manual Drag and Drop process, along with an "undelete" feature. The Manual Drag and Drop process is not all that different from the automatic version in example 1. It was previously noted that the majority of the work is performed by the Target. The Source simply initiates the Drag operation, but when the process in manually invoked, you have control over exactly how it is invoked. There also does not appear to me a menu on this form. You will see it in design mode and use it in the "undelete" process.

UIEX02.jpg (9093 bytes)

This program used Drag and Drop to move a value from the TextBox on the left, to the ListBox on the right. The contents of either can be cleared by dropping it in the trash. Right Clicking on the trash will allow you to restore deleted ListBox entries, and if you try to drag an empty TextBox to the trash, you will get a visual letting you know that this is not allowed.

Starting with the TextBox, it is the Double-Click event that initiates the manual Drag operation.

Private Sub txtAdd_DblClick()
    txtAdd.Drag vbBeginDrag

End Sub

The same logic is employed in the ListBox, but the process is initiated with the Right Mouse Click.

Private Sub lstText_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbRightButton Then
        lstText.Drag vbBeginDrag
    End If

End Sub

Pretty simple.The DragIcon set at design time is seen after the double-click.

Both the ListBox and TrashCan are drop targets. The code for each objects DragDrop Event looks at the Source parameter to determine what object it is receiving.

The ListBox will only "accept" a drop from the TextBox. The DragIcon is reset to it's original value, as it may have been modified in the DragOver event. This is always something that should be done when the operation completes.

Private Sub lstText_DragDrop(Source As Control, X As Single, Y As Single)
    If Source.Name = "txtAdd" Then

    Else
        Exit Sub
    End If

    Source.DragIcon = imgArrowTxt.Picture

    If Source.Text = "" Then
        Exit Sub
    End If

    lstText.AddItem Source.Text
    lstText.SetFocus

    Source.Text = ""

End Sub

The TrashCan will accept from both controls, but the action is different depending on the source.

When the Text is dropped on the TrashCan, the TrashCan Icon is changed to look like it is Full, and the Text property of the TextBox is cleared. When the ListBox is the Source control, each selected item is removed from the ListBox and the TrashCan changed. The reference to the TextBox and ListBox is performed indirectly using the Source parameter.  

 

Private Sub imgTrash_DragDrop(Source As Control, X As Single, Y As Single)
    If Source.Name = "txtAdd" Then
        Source.DragIcon = imgArrowTxt.Picture
        If Source.Text = "" Then
            Exit Sub
        End If

        Source.Text = ""
        imgTrash.Picture = imgTrashFull.Picture

        Exit Sub

    End If

    If Source.Name = "lstText" Then
        Source.DragIcon = imgArrowLst.Picture
        If Source.ListIndex = -1 Then
            Exit Sub
        End If

        Dim i As Integer
        For i = Source.ListCount - 1 To 0 Step -1
            If Source.Selected(i) Then
               lstTrash.AddItem Source.List(i)                        ' Saved for Undelete
                Source.RemoveItem i
            End If
        Next i
        imgTrash.Picture = imgTrashFull.Picture

        Exit Sub

    End If


End Sub

When an empty TextBox about to be dropped on the TrashCan, the DragOver changes the DragIcon to indicate that this is not an acceptable drop location. This is managed by checking the State paramenter. When entering, set the Icon to the Sad Face if the TextBox is blank, and restore the DragIcon when leaving.

UIEX2No.jpg (8731 bytes)

Private Sub lstText_DragOver(Source As Control, X As Single, Y As Single, State As Integer)
    If State = vbEnter Then
        If Source.Text = "" Then
            Source.DragIcon = imgNo.Picture
        Else
            Source.DragIcon = imgOK.Picture
        End If

    ElseIf State = vbLeave Then
        Source.DragIcon = imgArrowTxt.Picture
    End If

End Sub

There is additional code to save the deleted ListBox entries, as is indicated above. When a Right Click on the TrashCan is detected, a PopUp Menu is displayed asking if you want to restore the deleted entries. Note that the Visible property is NOT checked. The PopUpMenu command is used to display the "context menu" asking for a Restore or Cancel selection.

UIEX02Menu.jpg (17418 bytes)

 

Private Sub imgTrash_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If Button = vbRightButton Then
        PopupMenu mnuTrash
    End If

End Sub

As you can see, the coding is trivial, and the logic to perform the restore is coded in mnuRestore, just like if the menu were displayed as part of the form's menu bar. The actual restore reversed the delete process and changing the TrashCan icon.

Private Sub mnuRestore_Click()
    Dim i As Integer
    For i = lstTrash.ListCount - 1 To 0 Step -1
        lstText.AddItem lstTrash.List(i)
        lstTrash.RemoveItem i
    Next i

    imgTrash.Picture = imgTrashEmpty.Picture

End Sub

Download the Example


Drag and Drop - To an Outside Target and From an Outside Source

When dragging and dropping with a single application, the only objects that are involved will be the local form controls. An additional Data Structure is required when passing information between programs.

The DataObject object is a container for data being transferred from an component source to an component target. The data is stored in the format defined by the method using the DataObject object.

This definition is taken directly from VB Help. It is a bit confusing, but becomes much cleared after you are aware of the methods associated with this object.

The GetFormat method will return a boolean value and requires a type as a parameter. Here is an example:

If Data.GetFormat(vbCFFiles) Then ...

The variable Data is a DataObject, and the If statement is asking if the data is a List of Files. VbCFText, VbCFBitmap, and VbCFMetafile are other types of objects that may be dragged between applications. Looking back at the definition, the DataObjects holds data that is described by its GetFormat method. Other methods associated with the DataObject are the GetData and SetData methods. These methods are used to interpret and construct a DataObject.

Here is a snippet from the example that will add the file list to a ListBox:

Private Sub lstFileName_OLEDragDrop(Data As DataObject, _
                                                                    Effect As Long, _
                                                                        Button As Integer, _
                                                                            Shift As Integer, _
                                                                                X As Single, Y As Single)
    Dim i As Integer

    If Data.GetFormat(vbCFFiles) Then
        For i = 1 To Data.Files.Count
            lstFileName.AddItem Data.Files.Item(i)
        Next i
        Exit Sub
    End If

End Sub

The programming that is involved to process data other than the list of files detailed here is a bit beyond what can be demonstrated at this time. Much of the data is passed in it's binary form so additional Windows API functions and better memory management methods are required for accepting the external data. The Text processing is not as complex.

The objective is to drag some text data to another application. The Double Click will start the Drag operation, which immediately invokes the OLEStartDrag Event. It is here that the Data object is built.

Private Sub txtTarget_DblClick()
    txtTarget.OLEDrag

End Sub

Private Sub txtTarget_OLEStartDrag(Data As DataObject, AllowedEffects As Long)
    Data.SetData txtTarget.Text, vbCFText
    AllowedEffects = vbDropEffectCopy

End Sub

At this point, the Drag operation has been started, and the Data Object built, but the Drop operation will take place in the target application.

To receive text from a source application, the source must be dropped on this control in this application. When this occurs, the OLEDragDrop Event fires.

Private Sub txtTarget_OLEDragDrop(Data As DataObject, _
                                                                    Effect As Long, _
                                                                        Button As Integer, _
                                                                            Shift As Integer, _
                                                                                X As Single, Y As Single)


    If Data.GetFormat(vbCFText) Then
        txtTarget.Text = Data.GetData(vbCFText)
        Exit Sub
    End If

End Sub

The contents of the Data Object are extracted and in this case, stored in the TextBox.

Download the Example


Drag and Drop Operations

Thanks to Mark Pelczarski for this example using a number of the Graphics Methods. This program uses Mouse Events, Drag and Drop Methods and Windows Common Controls for this simple drawing program. Select the type of graphic you wish to draw using the Toolbar buttons. Right-click on the form to set the "Current X" and "Current Y" location. Use the Ctrl-Alt-Shift combination while drawing to select the color. You can move the Toolbar anywhere on the form, or hide it by dropping it in the trash. Double click on the form to clear the screen and double click on the trash can to restore the hidden Toolbar.

UIEX04.jpg (18164 bytes)

The ImageList and Toolbar from the Microsoft Windows Common Controls Library is used in this example. Go to Project | Components and add the library to the project. Select the two controls and add them to the form naming them ImageList and Toolbar. These two controls work together. The first step is to setup the ImageList with the icons that will be used on the Toolbar. Right-Click on the ImageList and select Properties.

ImageListProps.jpg (18642 bytes)

Add the images, and then move on to the Toolbar configuration.

The first Toolbar property panel makes reference to the ImageList. The second panel associates the buttons on the Toolbar with those ImageList images.

ToolBar1Props.jpg (24473 bytes)

 

Note that the button as specified by the index can be associated with any image. Set the Key value so that it represents the function of the button. This will be referenced from within the application to set a DrawStatus indicator..

Toolbar2Props.jpg (21534 bytes)

 

Private Sub Toolbar_ButtonClick(ByVal Button As ComctlLib.Button)
    Select Case Button.Key
        Case "freehand"
            intDrawStatus = 0

        Case "line"
            intDrawStatus = 1

        Case "circle"
            intDrawStatus = 2

    End Select

End Sub

The Drag and Drop methods are used to move the Toolbar around on the form. There is really no information being transfered here as in the earlier examples. The Drag and Drop methods are used simply to relocate a control on the form. The MouseDown manually initiates a Drag operation, while MouseUp will terminate the process. When MouseUp is fired, and the Drag operation is complete, the Form level DragDrop event occurs. It is not until the Drag is manually triggered by MouseUp that the Toolbar is actually moved in the DragDrop event.

Private Sub Toolbar_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
    intDragX = x
    intDragY = y
    Toolbar.Drag vbBeginDrag

End Sub


Private Sub Toolbar_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
    Toolbar.Drag vbEndDrag

End Sub

Private Sub Form_DragDrop(Source As Control, x As Single, y As Single)
    Source.Top = y - intDragY
    Source.Left = x - intDragX

End Sub

The drawing takes place in the Form MouseDown and the MouseMove events.

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)

    If Button = vbLeftButton Then
        Select Case intDrawStatus
            Case 0:
                CurrentX = x
                CurrentY = y
            Case 1:
                Line -(x, y), GetColor(Shift)
            Case 2:
                Dim intRadius As Integer

                intRadius = Sqr((x - CurrentX) ^ 2 + (y - CurrentY) ^ 2)
                Circle (CurrentX, CurrentY), intRadius, GetColor(Shift)
        End Select

    ElseIf Button = vbRightButton Then
        CurrentX = x
        CurrentY = y

    End If

End Sub

A Right Mouse Click will reset the current X and Y coordinates. The Left Mouse Click will complete a Line Segment or draw a Circle depending on the Tooolbar selection.

The MouseMove Event will draw a series of Line Segments with small 30 pixel radius circles as long as the left button is held down.

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
    If Button = vbLeftButton And intDrawStatus = 0 Then
        Line -(x, y), GetColor(Shift)
        Circle (x, y), 30
    End If

End Sub

Note that the properties CurrentX and CurrentY are not defined. These are Form Properties that are used by the Graphic Methods. The Line method uses CurrentX and CurrentY as a starting point and completes the line segment by drawing to the current mouse position as is contained in the X and Y parameters passed to MouseMove.

I've learned to make this the last example, as often, it's kind of hard to put down once you start!

Download the Example


Drop a File onto an Icon?

The final and very trivial example demonstrates how VB receives passed parameters. Dropping a file on to a .EXE file will invoke the application and pass the Source Filename as a parameter. The parameter is received in the VB Command object.

Here's the entire program:

Private Sub Form_Activate()
    If Len(Command) Then
        Me.Print "Here's the file: "
        Me.Print Command
    End If

End Sub

You can even drop the file on to a Shortcut to the Program. It's Windows that manages this feature, but it is VB that provides you with the source file name in the Command object.

This method of passing a filename to a program can be used in situations where you might start a program and then make the selection of a file that you might use for input processing. Incorporating this method of starting a program would give the user a second, perhaps faster and perhaps better method of starting the application.

Download the Example


Assignment

Reading Assignment

Programming Assignment

As Always: The assignment is due before the start of class next week

Food Tracker

    Page 551, Problem 13.3

You will need 4 icons for this program. The first will be used when the drag operation is initiated from the TextBox, the others will be used when the source object (the TextBox) is dragged over the appropriate target (the Salad, Main Course or Dessert ListBox).

Make sure that the icon changes correctly if I drag to in and out of one target, and then into another before dropping the TextBox contents into the final destination.

Be careful here.

This will probably be the most difficult part of the assignment. A user can drag the source anywhere and everywhere. Make sure that if the source is dropped on something other than an expected target that the icons are reset properly.

Also, make sure that you do not start the drag operation if the TextBox source is blank.

Here is a list of the Program Grading Criteria