Creating Custom Cursors in C#. Part 1: An Icon-based Cursor.
In this post, I shall present and explain C# code for creating an Icon-based custom mouse cursor. Part 2 will present an InterOp-based solution that is a bit more capable than this one.
Building a special-purpose document editor based on a Panel (System.Windows.Forms.Panel), I needed to write code to create an “I-Beam” mouse cursor capable of sizing itself to fit the document’s default font size, like this:
![]()
In the screen shots above, I have misaligned the cursors relative to their text lines deliberately, to emphasize that these are mouse cursors, and not insertion carets.
Magnification reveals the cursors’ notched serif structure:
![]()
A function, IconCursorCreate(int iFontHeightInPixels), takes the document’s Font.Height property as a parameter, creates a sized cursor, and returns its handle for the caller for use in a Cursor constructor in your Form-derived class, as follows:
1 2 |
IntPtr iCursHandle = IconCursorCreate(fon.Height); panel1.Cursor = new Cursor(iCursHandle); |
Here is the IconCursorCreate() function, including the minimum required using references. The comments explain how the code works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using System; using System.Drawing; using System.Windows.Forms; // Cursor creation function -- put in your Form-Derived Class: public static IntPtr IconCursorCreate(int iFontHeightInPixels) { // C# code written by Dominic Kyrie, // of Harmony Systems, http://www.hsys.com int i; // Cursor height and width scale from the font height: int iHeight = Convert.ToInt32(0.9F * iFontHeightInPixels); // Width of a symmetrical cursor will be an odd number >= 1 int iWidth = 1+2*Convert.ToInt32(0.15F*iFontHeightInPixels); int iHalfWidth = iWidth / 2; // Create bitmap of desired size: Bitmap bmp = new Bitmap(iWidth, iHeight); // Set pixels along cursor's vertical column: for(i = iHeight - 2; i > 0; i--) bmp.SetPixel(iHalfWidth, i, Color.Black); // Fill in the serifs, leaving notch in middle: for(i = 0; i < iWidth; i++) { if(i == iHalfWidth) continue; bmp.SetPixel(i, 0, Color.Black); bmp.SetPixel(i, iHeight - 1, Color.Black); } // The caller needs the bitmap's Icon handle: return bmp.GetHicon(); } |
Are we done? Maybe. Our cursor is really an icon, and does not invert the screen background like a ”real” cursor. So, as long as your SetPixel() calls draw a color that contrasts with the background, and as long as you don’t mind that the foreground text does not invert where it is superimposed by the cursor, you have a reasonable solution implemented entirely in Managed Code. The images below illustrate what happens when the cursor finds itself on a dark background, however. Magnification makes it slightly more visible:
![]()
![]()
Sadly, the cursor would disappear entirely on a Color.Black background.
In Part 2, I will create a real, screen-inverting Cursor that uses Captain InterOp.
Isn’t goo-ey programming fun?
Article link: http://www.hsys.com/CustomCursorArticlePart1.htm
Next: Creating Custom Cursors in C#. Part 2: An InterOp-based Cursor.