HELP: Problems setting mouse cursor for AddIn tool

3145
1
Jump to solution
06-04-2013 02:05 AM
AndrewClark1
New Contributor II
Hi everyone. Looking for a little help. I'm re-developing some VBA Macros into an ArcDesktop AddIn. I have a [Tool] coded that's used to select the point on the map used as the focal point for a report. The function of this works fine, with the user clicking the map to place a graphic on the map, and holding down CTRL+click to actually place and define the point (with graphic).

What I'm trying to do now is finesse the application a little, by changing the mouse pointer (to a custom pointer) when the tool is selected, and this is where I have the problem. First of all, I've tried the mouse pointer source as a PNG, an ICO, and a CUR. The latest attempt involved dropping the color-depth down to 24-bit and I was about to try 1-bit.

Code-wise, I've tried

        Dim curIcon As System.Object = ESRI.ArcGIS.ADF.COMSupport.OLE.GetIPictureDispFromIcon(myIcon)         appCursor.SetCursor(curIcon)


which has had mixed results, the latest taking the 24-bit pointer and displaying it as 1-bit, but is also non-contextual, so outside the map window the cursor remains.

I've also tried some code with Overriding the cursor property of the tool returning the current handle of the bitmap/icon/cursor:

            Dim m_Cursor As New System.Windows.Forms.Cursor(Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName.Name & ".Marker24b.cur"))             If Not m_Cursor Is Nothing Then                 intptrCursor = m_Cursor.Handle                 System.Windows.Forms.Application.DoEvents()             End If



         ........

    Public Overloads ReadOnly Property cursor() As Integer         Get             Return intptrCursor.ToInt32()         End Get     End Property


But none of it seems to work correctly. It probably doesn't help that I'm also using OnKeyDown and OnKeyUp to detect the user pressing the CTRL key, changing the mouse pointer to indicate the difference in actions.

Please, any advice greatly welcome.



p.s. If anyone out there is producing PDF's I would advise taking a look at MigraDoc, which I've used in this project to create a document starting with a map, followed by tabular data representing what's on the map.
0 Kudos
1 Solution

Accepted Solutions
AndrewClark1
New Contributor II
No worries everyone. Dug deep enough and found a simple solution.... . . .  but with a memory leak... . . . .  but with a solution to that too.

First of all, I'm using 32bit PNG's complete with alpha effects. The pointers drawn in the PNG's assume the cursor derived from it will use the centre point as an anchor point, so I'm only really using the top half of a 32x32 PNG. Two PNG's are used as I change the cursor on holding down CTRL.

Next, added the PNG's into the project in Visual Studio (2010 express edition) and Properties-Build Action set to Embedded Resource.

Then, in the code of the tool, within it's class I define 2 variables to hold pointers to the Icon version of the PNG's

Public Class LocationButton     Inherits ESRI.ArcGIS.Desktop.AddIns.Tool   ???..      Private objMarker As System.IntPtr = Nothing     Private objMarkerAdd As System.IntPtr = Nothing


Then in New() I assign the Embedded resources to the pointers

        objMarker = (New System.Drawing.Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName.Name & ".Marker32.png"))).GetHicon()         objMarkerAdd = (New System.Drawing.Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName.Name & ".MarkerAdd32.png"))).GetHicon()


Or

        Dim objThisCode as System.Reflection.Assembly = Assembly.GetExecutingAssembly()         Dim strResourceNamespace as String = objThisCode.GetName.Name         Dim streamMarkerPNG as System.IO.Stream = objThisCode.GetManifestResourceStream(strResourceNamespace & ".Marker32.png")         Dim streamMarkerAddPNG as System.IO.Stream = objThisCode.GetManifestResourceStream(strResourceNamespace & ".MarkerAdd32.png")         Dim bmpMarker as System.Drawing.Bitmap = New System.Drawing.Bitmap(streamMarkerPNG)         Dim bmpMarkerAdd as System.Drawing.Bitmap = New System.Drawing.Bitmap(streamMarkerAddPNG)          objMarker = bmpMarker.GetHicon()         objMarkerAdd = bmpMarkerAdd.GetHicon()


And here's the stuff that actually uses it:

    Protected Overrides Sub OnActivate()          preUseSelectedTool = My.ArcMap.Application.CurrentTool()          My.ArcMap.Application.StatusBar.Message(0) = "Position the focal point for the report"          MyBase.OnActivate()          MyBase.CursorHandle = objMarker      End Sub      Protected Overrides Sub OnKeyDown(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs)          If arg.Control Then             MyBase.CursorHandle = objMarkerAdd             My.ArcMap.Application.StatusBar.Message(0) = "Fix the focal point for the report"         Else             MyBase.CursorHandle = objMarker             My.ArcMap.Application.StatusBar.Message(0) = "Position the focal point for the report"         End If          MyBase.OnKeyDown(arg)      End Sub      Protected Overrides Sub OnKeyUp(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs)          If arg.Control Then             MyBase.CursorHandle = objMarkerAdd             My.ArcMap.Application.StatusBar.Message(0) = "Fix the focal point for the report"         Else             MyBase.CursorHandle = objMarker             My.ArcMap.Application.StatusBar.Message(0) = "Position the focal point for the report"         End If          MyBase.OnKeyUp(arg)      End Sub      Protected Overrides Sub Dispose(ByVal disposing As Boolean)          DestroyIcon(objMarker)         DestroyIcon(objMarkerAdd)          MyBase.Dispose(disposing)     End Sub


Which raises the question in the Dispose Event, where's this DestroyIcon Sub? Well, that's the bit I found on the Net that deals with the memory leak which is associated with the GetHicon() method:

    <System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint:="DestroyIcon")> _     Public Shared Function DestroyIcon(<System.Runtime.InteropServices.InAttribute()> ByVal hIcon As System.IntPtr) As <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean     End Function



Finally, my apologies. I spent 30 minutes trying to find a way to convert from visual studio highlighting to BBcodes used here, but with no luck.

View solution in original post

0 Kudos
1 Reply
AndrewClark1
New Contributor II
No worries everyone. Dug deep enough and found a simple solution.... . . .  but with a memory leak... . . . .  but with a solution to that too.

First of all, I'm using 32bit PNG's complete with alpha effects. The pointers drawn in the PNG's assume the cursor derived from it will use the centre point as an anchor point, so I'm only really using the top half of a 32x32 PNG. Two PNG's are used as I change the cursor on holding down CTRL.

Next, added the PNG's into the project in Visual Studio (2010 express edition) and Properties-Build Action set to Embedded Resource.

Then, in the code of the tool, within it's class I define 2 variables to hold pointers to the Icon version of the PNG's

Public Class LocationButton     Inherits ESRI.ArcGIS.Desktop.AddIns.Tool   ???..      Private objMarker As System.IntPtr = Nothing     Private objMarkerAdd As System.IntPtr = Nothing


Then in New() I assign the Embedded resources to the pointers

        objMarker = (New System.Drawing.Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName.Name & ".Marker32.png"))).GetHicon()         objMarkerAdd = (New System.Drawing.Bitmap(Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName.Name & ".MarkerAdd32.png"))).GetHicon()


Or

        Dim objThisCode as System.Reflection.Assembly = Assembly.GetExecutingAssembly()         Dim strResourceNamespace as String = objThisCode.GetName.Name         Dim streamMarkerPNG as System.IO.Stream = objThisCode.GetManifestResourceStream(strResourceNamespace & ".Marker32.png")         Dim streamMarkerAddPNG as System.IO.Stream = objThisCode.GetManifestResourceStream(strResourceNamespace & ".MarkerAdd32.png")         Dim bmpMarker as System.Drawing.Bitmap = New System.Drawing.Bitmap(streamMarkerPNG)         Dim bmpMarkerAdd as System.Drawing.Bitmap = New System.Drawing.Bitmap(streamMarkerAddPNG)          objMarker = bmpMarker.GetHicon()         objMarkerAdd = bmpMarkerAdd.GetHicon()


And here's the stuff that actually uses it:

    Protected Overrides Sub OnActivate()          preUseSelectedTool = My.ArcMap.Application.CurrentTool()          My.ArcMap.Application.StatusBar.Message(0) = "Position the focal point for the report"          MyBase.OnActivate()          MyBase.CursorHandle = objMarker      End Sub      Protected Overrides Sub OnKeyDown(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs)          If arg.Control Then             MyBase.CursorHandle = objMarkerAdd             My.ArcMap.Application.StatusBar.Message(0) = "Fix the focal point for the report"         Else             MyBase.CursorHandle = objMarker             My.ArcMap.Application.StatusBar.Message(0) = "Position the focal point for the report"         End If          MyBase.OnKeyDown(arg)      End Sub      Protected Overrides Sub OnKeyUp(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs)          If arg.Control Then             MyBase.CursorHandle = objMarkerAdd             My.ArcMap.Application.StatusBar.Message(0) = "Fix the focal point for the report"         Else             MyBase.CursorHandle = objMarker             My.ArcMap.Application.StatusBar.Message(0) = "Position the focal point for the report"         End If          MyBase.OnKeyUp(arg)      End Sub      Protected Overrides Sub Dispose(ByVal disposing As Boolean)          DestroyIcon(objMarker)         DestroyIcon(objMarkerAdd)          MyBase.Dispose(disposing)     End Sub


Which raises the question in the Dispose Event, where's this DestroyIcon Sub? Well, that's the bit I found on the Net that deals with the memory leak which is associated with the GetHicon() method:

    <System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint:="DestroyIcon")> _     Public Shared Function DestroyIcon(<System.Runtime.InteropServices.InAttribute()> ByVal hIcon As System.IntPtr) As <System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)> Boolean     End Function



Finally, my apologies. I spent 30 minutes trying to find a way to convert from visual studio highlighting to BBcodes used here, but with no luck.
0 Kudos