Click here to Skip to main content
15,867,330 members
Articles / Programming Languages / C#
Article

Creating Bitmap Regions for Forms and Buttons

Rate me:
Please Sign up or sign in to vote.
4.97/5 (66 votes)
8 Feb 20042 min read 322.7K   12K   183   62
This article describes on how to create bitmap regions for WinForms and buttons.

Sample Image - bmprgnform.jpg

Introduction

This article shows you how to create bitmap regions for forms and buttons. I think there are several articles on this for MFC and this one uses a similiar technique, Regions. Beside using this technique on forms, it also allows you to do that to Buttons, with hovering effect(i.e. Change another image and/or region when mouse hovering on the button) without the need to create a custom control.

Main Functions Overview

Below are the codes for the 2 main functions used to create your bitmap regions. They are located in BitmapRegion.cs.

C#
// Create and apply the given bitmap region on the supplied control
public static void CreateControlRegion(Control control, Bitmap bitmap)
{
    // Return if control and bitmap are null
    if(control == null || bitmap == null)
        return;
            
    // Set our control's size to be the same as the bitmap
    control.Width = bitmap.Width;
    control.Height = bitmap.Height;

    // Check if we are dealing with Form here
    if(control is System.Windows.Forms.Form)
    {
        // Cast to a Form object
        Form form = (Form)control;

        // Set our form's size to be a little larger that the bitmap just 
        // in case the form's border style is not set to none in the first 
        // place
        form.Width += 15;
        form.Height += 35;
        
        // No border
        form.FormBorderStyle = FormBorderStyle.None;

        // Set bitmap as the background image
        form.BackgroundImage = bitmap;

        // Calculate the graphics path based on the bitmap supplied
        GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);

        // Apply new region
        form.Region = new Region(graphicsPath);
    }

    // Check if we are dealing with Button here
    else if(control is System.Windows.Forms.Button)
    {
        // Cast to a button object
        Button button = (Button)control;

        // Do not show button text
        button.Text = "";
                
        // Change cursor to hand when over button
        button.Cursor = Cursors.Hand;

        // Set background image of button
        button.BackgroundImage = bitmap;
                
        // Calculate the graphics path based on the bitmap supplied
        GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);

        // Apply new region
        button.Region = new Region(graphicsPath);
    }
}

// Calculate the graphics path that representing the figure in the bitmap 
// excluding the transparent color which is the top left pixel.
private static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap)
{
    // Create GraphicsPath for our bitmap calculation
    GraphicsPath graphicsPath = new GraphicsPath();

    // Use the top left pixel as our transparent color
    Color colorTransparent = bitmap.GetPixel(0, 0);

    // This is to store the column value where an opaque pixel is first found.
    // This value will determine where we start scanning for trailing 
    // opaque pixels.
    int colOpaquePixel = 0;

    // Go through all rows (Y axis)
    for(int row = 0; row < bitmap.Height; row ++)
    {
        // Reset value
        colOpaquePixel = 0;

        // Go through all columns (X axis)
        for(int col = 0; col < bitmap.Width; col ++)
        {
            // If this is an opaque pixel, mark it and search 
            // for anymore trailing behind
            if(bitmap.GetPixel(col, row) != colorTransparent)
            {
                // Opaque pixel found, mark current position
                colOpaquePixel = col;

                // Create another variable to set the current pixel position
                int colNext = col;

                // Starting from current found opaque pixel, search for 
                // anymore opaque pixels trailing behind, until a transparent
                // pixel is found or minimum width is reached
                for(colNext=colOpaquePixel; colNext<bitmap.Width; colNext++)
                    if(bitmap.GetPixel(colNext, row) == colorTransparent)
                        break;

                // Form a rectangle for line of opaque pixels found and 
                // add it to our graphics path
                graphicsPath.AddRectangle(new Rectangle(colOpaquePixel, 
                                           row, colNext - colOpaquePixel, 1));

                // No need to scan the line of opaque pixels just found
                col = colNext;
            }
        }
    }

    // Return calculated graphics path
    return graphicsPath;
}

Creating our bitmap region for Forms

To create the bitmap region for our form, you only need these 2 lines of code. Note that you need not explicitly change the form's border to none, as it will be done for you.

C#
public class Form1 : System.Windows.Forms.Form
{
    // Load your bitmap for the form
    private Bitmap bmpFrmBack = new Bitmap(typeof(Form1), "back.bmp");

    public Form1()
    {
        //
        // Required for Windows Form Designer support
        //
        InitializeComponent();

        // Make our bitmap region for the form
        BitmapRegion.CreateControlRegion(this, bmpFrmBack);
    }
}

Creating our bitmap region for Buttons

Creating bitmap region for buttons is the same for forms. Also, you need not do anything to the style of the button.

C#
public class Form1 : System.Windows.Forms.Form
{
    // Load your bitmap for the form
    private Bitmap bmpFrmBack = new Bitmap(typeof(Form1), "back.bmp");
    
    // Load your bitmap for the button
    private Bitmap bmpBob = new Bitmap(typeof(Form1), "bob.bmp");

    public Form1()
    {
        //
        // Required for Windows Form Designer support
        //
        InitializeComponent();

        // Make our bitmap region for the form
        BitmapRegion.CreateControlRegion(this, bmpFrmBack);
        
        // Make our bitmap regions for the buttons
        BitmapRegion.CreateControlRegion(button1, bmpBob);
    }
}

Now if you want to change the bitmap of the button when mouse is over it, I am glad to say that you need not create a custom button control for that. You can just simply handle the MouseLeave and MouseEnter events as shown below.

C#
private void button1_MouseEnter(object sender, System.EventArgs e)
{
    // Make bitmap region for button
    BitmapRegion.CreateControlRegion(button1, bmpBobSay);
}

private void button1_MouseLeave(object sender, System.EventArgs e)
{
    // Make bitmap region for button
    BitmapRegion.CreateControlRegion(button1, bmpBob);
}

Dragging the Form

Since the form now doesn't have a title bar, we need to make it such that the user is able to left click anywhere in the form and drag it. The solution used for the MFC version is to handle WM_LBUTTONDOWN and doing a PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x,point.y)) to fool windows into thinking that we clicked on the caption. However, I couldn't get this to work with Window Forms, so the code below is an alternative solution.

C#
private void Form1_MouseMove(object sender, 
                                        System.Windows.Forms.MouseEventArgs e)
{
    // Check if dragging of the form has occurred
    if(e.Button == MouseButtons.Left)
    {
        // If this is the first mouse move event for left click dragging 
        // of the form, store the current point clicked so that we can use 
        // it to calculate the form's new location in subsequent mouse move 
        // events due to left click dragging of the form
        if(isFirst == true)
        {
            // Store previous left click position
            prevLeftClick = new Point(e.X, e.Y);

            // Subsequent mouse move events will not be treated as first time,
            // until the left mouse click is released or other mouse click 
            // occur
            isFirst = false;
        }

        // On subsequent mouse move events with left mouse click down. 
        // (i.e. During dragging of form)
        else
        {
            // This flag here is to do alternate processing for the form 
            // dragging because it causes serious flicking when u allow 
            // every such events to change the form's location.
            // You can try commenting this out to see what i mean
            if(toBlock == false)
                this.Location = new Point(this.Location.X + e.X - 
                    prevLeftClick.X, this.Location.Y + e.Y - prevLeftClick.Y);

            // Store new previous left click position
            prevLeftClick = new Point(e.X, e.Y);

            // Allow or deny next mouse move dragging event
            toBlock = !toBlock;
        }
    }

    // This is a new mouse move event so reset flag
    else
        isFirst = true;
}

Issues to take note

There is a problem with the focus rect drawn on the button when it receives focus. I am unable to disable this focus rect. As a result, I have made my bitmaps slightly larger so that the focus rect ends up being drawn outside the region of the button. Take a look at the figure below.

Image 2

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Singapore Singapore
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionColor ? Pin
wwardaww12-Aug-14 23:06
wwardaww12-Aug-14 23:06 
GeneralThanks!!!!! Pin
Member 157966222-Oct-10 6:45
Member 157966222-Oct-10 6:45 
Great Work!
GeneralForm Resize Issue Pin
cooldude28-Apr-08 20:40
cooldude28-Apr-08 20:40 
QuestionGreat but Slow Pin
ayman.metwally@gizasystems.com4-Apr-08 22:08
ayman.metwally@gizasystems.com4-Apr-08 22:08 
GeneralRe: Great but Slow Pin
Nick Alexeev6-Feb-11 8:47
professionalNick Alexeev6-Feb-11 8:47 
QuestionI have Prolem ...??? Pin
taixiu16-Jan-08 23:03
taixiu16-Jan-08 23:03 
AnswerRe: I have Prolem ...??? Pin
hitechntv29-Dec-08 22:24
hitechntv29-Dec-08 22:24 
AnswerRe: I have Prolem ...??? Pin
draobrehtom4-Oct-15 2:05
draobrehtom4-Oct-15 2:05 
QuestionIsn't this what XAML was designed for? Pin
John Wolfe12-Jan-07 10:00
John Wolfe12-Jan-07 10:00 
AnswerRe: Isn't this what XAML was designed for? Pin
Heywood31-Aug-07 5:36
Heywood31-Aug-07 5:36 
GeneralMuch faster routine using LocksBit with Marshal Pin
bcodebcode10-Jan-07 17:09
bcodebcode10-Jan-07 17:09 
GeneralRe: Much faster routine using LocksBit with Marshal Pin
GaryJForeman9-Apr-07 8:29
GaryJForeman9-Apr-07 8:29 
GeneralRe: Much faster routine using LocksBit with Marshal Pin
GaryJForeman9-Apr-07 8:34
GaryJForeman9-Apr-07 8:34 
GeneralRe: Much faster routine using LocksBit with Marshal Pin
bcodebcode12-Apr-07 10:32
bcodebcode12-Apr-07 10:32 
QuestionMouse Move Problem Pin
aslim_sahal2-Nov-06 4:25
aslim_sahal2-Nov-06 4:25 
GeneralForm dragging Pin
Sergei Prognimak11-Sep-06 7:22
Sergei Prognimak11-Sep-06 7:22 
AnswerRe: Form dragging Pin
qwerty@sh25-Jan-07 5:06
qwerty@sh25-Jan-07 5:06 
Generalbut .... Pin
tareqGamal10-Aug-06 3:00
tareqGamal10-Aug-06 3:00 
GeneralGood code Pin
QuaKx11-Jan-06 2:55
QuaKx11-Jan-06 2:55 
GeneralCorrection to W2000 shifting issue Pin
bouzard30-Nov-05 22:22
bouzard30-Nov-05 22:22 
GeneralRe: Correction to W2000 shifting issue Pin
Mubi | www.mrmubi.com24-Dec-05 1:30
professionalMubi | www.mrmubi.com24-Dec-05 1:30 
QuestionRe: Correction to W2000 shifting issue Pin
Frank Meng7-Nov-07 7:41
Frank Meng7-Nov-07 7:41 
GeneralGreat work! - I have made it faster for you Pin
spirit1238-Nov-05 5:54
spirit1238-Nov-05 5:54 
GeneralRe: Great work! - I have made it faster for you Pin
Miguel Lopes13-Feb-06 3:46
Miguel Lopes13-Feb-06 3:46 
GeneralRe: Great work! - I have made it faster for you Pin
motasus7-Oct-06 0:13
motasus7-Oct-06 0:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.