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.
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
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.
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.
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.
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
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.
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.
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.
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.
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..
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!
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.
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.