by Stephan Grieger - Independent Developer
Here is a cool little app that acts like a mini explorer, providing a basis for any "select these files, then do that" action.
It displays a list of file icons that can be selected by either clicking on, using a "rubber band" selection with the mouse, or a Select All function. Best of all, it also allows other files to be dragged into the display window. This could be the skeleton for a batch program, a compression utility or anything else that requires the selection of a number of files. This article concentrates on the more 'interesting' parts of the code, all of which can be downloaded.
Most of the cool stuff with the file icon display and selection occurs within a picture box. This enables you to easily grab the handle of the control as well as the x and y coordinates when you are selecting many icons with a mouse drag. This has been designed with a "rubber band" effect.
This is done with the API call DrawFocusRect, which draws a focus rectangle onto the owner of the handle using the values stored in the following User Defined Type.
Type RECT Left As Long Top As Long right As Long bottom As Long End Type
During the MouseDown Event for the Picture control, the original X,Y values are stored in the UDT as the top and left values and are also stored in two variables. (OrigX and OrigY).
typRect.Top = Y typRect.Left = X typRect.bottom = 0 typRect.right = 0 OrigX = X OrigY = Y
During the MouseMove Event, the API is called for every pixel (almost) covered by the mouse pointer.
The UDT values then alter depending on whether they are greater than or less than the new X,Y coordinates passed to it by the event parameters. (Don't forget to clear the rectangle by calling the API again with the old coordinates.). This will give the impression that the rectangle is shrinking and expanding in line with the mouse movements.
' Clear the original rectangle. Call DrawFocusRect(picScroll.hDC, typRect) ' Set the bounds of the rectangle. If X > typRect.Left Then typRect.right = X typRect.Left = OrigX Else typRect.right = OrigX typRect.Left = X End If If Y > typRect.Top Then typRect.bottom = Y typRect.Top = OrigY Else typRect.bottom = OrigY typRect.Top = Y End If ' Draw the rectangle. Call DrawFocusRect(picScroll.hDC, typRect)
The MouseUp Event calls a procedure which clears any highlighted icons and then highlights any icons which are within the boundaries of the UDT rectangle values. Highlighting is achieved by changing the back colour of the icon. This is all fairly straight forward once you understand the API call and have the right logic for your x and y coordinates.
Another interesting part of this app is the ability to drag a number of files onto the picture box. This is done using the OleDragOver and OleDragDrop events.
The OleDragOver event is triggered when one component is dragged over another. In the code below, the GetFormat method is used to check if the item in the DataObject object matches a specified format. In this case the format uses a constant which represents the files from windows explorer. If the component being dragged over the picture box meets this condition, a mask is used which represents that a copy will take place. If it does not, then no operation will be performed.
Private Sub picscroll_OLEDragOver(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single, State As Integer) ' Check to see if we are dragging files across the picture control. If Data.GetFormat(vbCFFiles) Then Effect = vbDropEffectCopy And Effect Else Effect = vbDropEffectNone End If End Sub
The Fields property of the DataObject contains a collection of all files being dragged into the component. For each file in this collection, the FileList array is redimensioned and has the new file added to it. The ArrangeIcons procedure is then called which unloads and then reloads the icons and filenames. These icons are then arranged within the picture box into rows and columns.
Private Sub picscroll_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) ' Dim a few variables. Dim vFN ' Check to see if we have dropped files. If Not Data.GetFormat(vbCFFiles) Then Exit Sub ' Place all the files into the file array. For Each vFN In Data.Files ReDim Preserve FileList(UBound(FileList) + 1) FileList(UBound(FileList)).FileName = vFN Next ' Arrange the icons. Call ArrangeIcons(Me, True) If ilCurFile = 0 Then ilCurFile = 1 Call frmMain.imgIcon_MouseDown(ilCurFile, 0, 0, 0, 0) Call EnableMenus End Sub
This app also has the facility to keep the highlighted icon within the current viewing area by using the dimensions of the viewing area, the position of the vertical scroll bar, and the coordinates of the icon itself.
' Determine whether the icon is off screen or not. ' Get the bounds of the viewing area. ViewTop = frmName.vsScrollBar.Value ViewBottom = frmName.picFileContainer.Height + ViewTop ' Get the bounds of the icon. IconBottom = (frmName.lblIcon(IconIndex).Top + frmName.lblIcon(IconIndex).Height) * Screen.TwipsPerPixelY IconTop = frmName.imgIcon(IconIndex).Top * Screen.TwipsPerPixelY ' Check for lower than window. If IconBottom > ViewBottom Then NewVal = (IconBottom - ViewBottom) + frmName.vsScrollBar.Value + (4.8 * Screen.TwipsPerPixelY) frmName.vsScrollBar.Value = NewVal End If ' Check for higher than window. If IconTop < ViewTop Then NewVal = IconTop frmName.vsScrollBar.Value = NewVal End If
With this code, you should be able to scroll through the file icons without leaving your highlighted icon behind.
OK, so it's not bug free. You may find some possible problems when trying to drag a file onto the picture box when there is no currently selected icon. This shouldn't take too much to fix. Also, the number of highlighted icons shown at the bottom of the form can become inaccurate.
I guess that's what comes from moving the the UK (and working for a living!) and still having our erstwhile Editor expect articles!