Harmony Systems -- Custom Firmware & Software Development Services

Letter #1
Letter #2
Letter #3
Creating Custom Cursors in C#. Part 1
Creating Custom Cursors in C#. Part 2

 

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?

– Dominic Kyrie

 

Article link: http://www.hsys.com/CustomCursorArticlePart1.htm

Next: Creating Custom Cursors in C#. Part 2: An InterOp-based Cursor.

 

©2004 - 2010 Harmony Systems
All rights reserved. Unauthorized duplication of any text, image, or logo on this web page is a violation of applicable laws.
Windows and .net are Registered Trademarks of Microsoft Corporation.