October 11, 2012

Custom Cursor Hotspot - HowTo...

When I recently implemented some drag and drop functionality I wanted to create a nice "drag cursor". A little different from the default. A quick "Google" showed me how to use a bitmap as a cursor.

My Problem



When creating a cursor from a bitmap the new cursor hotspot is the center point of that cursor image.

Though I had a nice cursor now, using it posed a challenge for my users. People -rightfully- assume the "fingertip" to be the point where they are pointing at not the center of their cursor.



Problem solved?!

Another Google search brought me the solution. To create my custom cursor (assuming the image is one of my resources) I had this code:

 Cursor.Current = New Cursor(My.Resources.addCursor.GetHicon())  

To create a custom cursor with a custom hotspot I changed it to:

 Cursor.Current = FormHelper.CreateCursor(My.Resources.addCursor, New Point(5, 5))  

The voodoo happens in the CreateCursor -static- method. Though you're probably not interested, I copied the source anyway:

#Region "Create Custom Cursor" 
  
   Private Structure IconInfo  
     Public fIcon As Boolean  
     Public xHotspot As Int32  
     Public yHotspot As Int32  
     Public hbmMask As IntPtr  
     Public hbmColor As IntPtr  
   End Structure  

   <DllImport("user32.dll", EntryPoint:="CreateIconIndirect")> _  
   Private Shared Function CreateIconIndirect(ByVal iconInfo As IntPtr) As IntPtr  
   End Function  

   <DllImport("user32.dll", CharSet:=CharSet.Auto)> _  
   Public Shared Function DestroyIcon(ByVal handle As IntPtr) As Boolean  
   End Function  

   <DllImport("gdi32.dll")> _  
   Public Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean  
   End Function  

   ''' <summary>  
   ''' Create a custom winforms cursor with a designated hotspot  
   ''' </summary>  
   ''' <param name="bmp">Image to be used as cursor</param>  
   ''' <param name="hotspot">Hotspot location of the cursor</param>  
   ''' <returns></returns>  
   ''' <remarks>  
   ''' Requires imports:  
   ''' Imports System.Drawing  
   ''' Imports System.Runtime.InteropServices  
   ''' Imports System.Windows.Forms  
   '''</remarks>  
   Public Shared Function CreateCursor(ByVal bmp As Bitmap, ByVal hotspot As Point) As Cursor  
     'Setup the Cursors IconInfo  
     Dim tmp As New IconInfo  
     tmp.xHotspot = hotspot.X  
     tmp.yHotspot = hotspot.Y  
     tmp.fIcon = False  
     tmp.hbmMask = bmp.GetHbitmap()  
     tmp.hbmColor = bmp.GetHbitmap()  
     'Create the Pointer for the Cursor Icon  
     Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(tmp))  
     Marshal.StructureToPtr(tmp, pnt, True)  
     Dim curPtr As IntPtr = CreateIconIndirect(pnt)  
     'Clean Up  
     DestroyIcon(pnt)  
     DeleteObject(tmp.hbmMask)  
     DeleteObject(tmp.hbmColor)  
     Return New Cursor(curPtr)  
   End Function  

#End Region  

Don't forget the required imports! (In case you it did interest you)

No comments:

Post a Comment