![]() |
Desktop Development »
Button Controls »
General
Intermediate
Custom Bitmap Button Using C#By JSimmsAn article on creating a bitmap button |
C#, Windows, .NET 1.1VS.NET2003, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

The motivation behind the custom bitmap control was to allow different bitmap images to be displayed for each of the button states. This includes disabled, normal, mouse over, and button pressed. In addition to the button graphics, it was important to include button text and control the alignment of the text with regards to the button image. It follows an XP style look and feel with some embellishments that are unique to it.
The code can be segmented into 3 main sections: data, rendering, and events.
OnPaint method is the driver which calls the other paint methods for button rendering.
OnMouseDown, OnMouseUp, OnMouseLeave, OnMouseMove, OnEnabledChanged, OnLostFocus. When viewing the source code, the sections can be easily found, since the #region keyword is used for code separation.
First, let's explore the properties.
|
BITMAP BUTTON PROPERTIES | ||||||||||||||||||||||||||||||||||||||||||||
|
All of the properties have been added to the appearance category in the property page. The below picture is a snapshot of them.

Rendering of the button is performed by the OnPaint method. This in turn calls several routines to handle the rendering particulars of the button.
CreateRegion: creates a see-through rounded button edge for the control.
paint_Background: renders the background of the button.
paint_Text: renders the text and text drop shadow.
paint_Border: renders the 1 pixel with border around the button.
paint_InnerBorder: renders the 2 pixel width inner border.
paint_FocusBorder: renders the 1 pixel width dashed focus border within the button. See the below code snippet for details.
/// <summary>
/// This method paints the button in its entirety.
/// </summary>
/// <param name="e">paint arguments use to paint the button</param>
protected override void OnPaint(PaintEventArgs e)
{
CreateRegion(0);
paint_Background(e);
paint_Text(e);
paint_Image(e);
paint_Border(e);
paint_InnerBorder(e);
paint_FocusBorder(e);
}
Painting the background can be of some interest. The approach that was taken allows for a gradient background interpolation between multiple colors (meaning more then 2 colors). First, a blend object needs to be initialized with an array of colors, and the position of interpolation. Next, the gradient brush can be created as usual. The Final step involves linking the blend object to the brush. This is accomplished by setting the InterpolationColors property of a brush.
The following is an example interpolating multiple colors:
Color[] ColorArray = new Color[]{
System.Drawing.Color.White,
System.Drawing.Color.Yellow,
System.Drawing.Color.Blue,
System.Drawing.Color.Green,
System.Drawing.Color.Red,
System.Drawing.Color.Black};
float[] PositionArray = new float[]{0.0f,.15f,.40f,.65f,.80f,1.0f};
//
// create blend variable for the interpolate the colors
//
System.Drawing.Drawing2D.ColorBlend blend
= new System.Drawing.Drawing2D.ColorBlend();
blend.Colors = ColorArray;
blend.Positions = PositionArray;
//
// create vertical gradient brush
//
System.Drawing.Drawing2D.LinearGradientBrush brush
= new System.Drawing.Drawing2D.LinearGradientBrush(rect,
this.BackColor,Blend(this.BackColor,this.BackColor,10),
System.Drawing.Drawing2D.LinearGradientMode.Vertical);
brush.InterpolationColors = blend;
//
// fill the rectangle
//
g.FillRectangle(brush, rect);
//
// release resources
//
brush.Dispose();
For rendering the text, I used System.Drawing.DrawString method. The tricky part was determining where to draw the text. Because of the amount of code, that functionality was placed in helper functions to keep it from cluttering the paint_Text method. One point of interest with this method, is it implements the drop shadow functionality. This simply involves creating a brushes with alpha components, and drawing the text as usual.
//
// paint text shadow
//
if(TextDropShadow)
{
System.Drawing.Brush TransparentBrush0
= new System.Drawing.SolidBrush( System.Drawing.Color.FromArgb(50,
System.Drawing.Color.Black ) ) ;
System.Drawing.Brush TransparentBrush1
= new System.Drawing.SolidBrush( System.Drawing.Color.FromArgb(20,
System.Drawing.Color.Black ) ) ;
e.Graphics.DrawString(this.Text,this.Font,
TransparentBrush0,pt.X,pt.Y+1);
e.Graphics.DrawString(this.Text,this.Font,
TransparentBrush0,pt.X+1,pt.Y);
e.Graphics.DrawString(this.Text,this.Font,
TransparentBrush1,pt.X+1,pt.Y+1);
e.Graphics.DrawString(this.Text,this.Font,
TransparentBrush1,pt.X,pt.Y+2);
e.Graphics.DrawString(this.Text,this.Font,
TransparentBrush1,pt.X+2,pt.Y);
TransparentBrush0.Dispose();
TransparentBrush1.Dispose();
}Painting the image was a rather straight forward process. However, I did experience some difficulties when using the below method. It worked properly using a bitmap created by the resource editor, but unfortunately, failed with a 24 bit image created by a 3rd party paint program. The work around involved calling a different DrawImage method. It is probably slower, but until I understand what the issue is, it will have to work for now.// FAILED
g.DrawImage(image,rect.Left,rect.Top)
// WORKAROUND
g.DrawImage(image,rect, 0, 0 ,image.Width,image.Height, GraphicsUnit.Pixel);
Painting borders with interpolating colors was not difficult either. You go through the same process of creating a gradient brush as before. The gradient brush is passed as a parameter when creating the pen object. The below code snippet is an example of this process.
....
//
// create brush and pens
//
System.Drawing.Drawing2D.LinearGradientBrush brush
= new System.Drawing.Drawing2D.LinearGradientBrush(rect,
this.BackColor,Blend(this.BackColor,this.BackColor,10),
System.Drawing.Drawing2D.LinearGradientMode.Vertical);
brush.InterpolationColors = blend;
System.Drawing.Pen pen0 = new System.Drawing.Pen(brush,1);
//
// draw line 0
//
g.DrawLine(pen0 , point_0,point_1);
....
| Event Methods | Button state |
OnMouseDown |
Set BtnState to Pushed and Capturing mouse to true |
OnMouseUp |
Set BtnState to Normal and set CapturingMouse to false |
OnMouseLeave |
Set BtnState to normal if we CapturingMouse = true |
OnMouseMove |
If CapturingMouse = true and mouse coordinates are within button region, set BtnState to Pushed, otherwise set BtnState to Normal.
If CapturingMouse = false, then set BtnState to MouseOver |
OnEnabledChanged |
The button either became enabled or disabled. If button became enabled, set BtnState to Normal else set BtnState to Inactive |
OnLostFocus |
Set btnState to Normal |
The below code block shows an example of the event code. Events generally are composed of little code. One tidbit of information I should cover is the Capture property of the control. By setting this to true, the button does not lose input focus when the pointer is outside the button region. This is important because if the mouse button is held down and the user moves the mouse pointer in and out of the button region, the state of the button needs to change accordingly. If the Capture property is not set, the control will stop capturing input events when the pointer leaves the button region.
/// <summary> /// Mouse Down Event: /// set BtnState to Pushed and Capturing mouse to true /// </summary> /// <param name="e"></param> protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown (e); this.Capture = true; this.CapturingMouse = true; btnState = BtnState.Pushed; this.Invalidate(); }
This is the first incarnation of the control, and the entire source code is in one file, BitmapButton.cs. Later, if time permits and the control draws interest, the source code could make use of interfaces to componentize the different facets of functionality and abet expandability and maintainability. It would be nice to include themes and access them from an xml source. And caching (double buffering) of the images should be an option as well. I Look forward to suggestions, and hope the bitmap control meets your needs or provides some ideas for your controls to be.
| Version | Date | Changes |
| 1.0 | 02-27-2005 | Initial release of the control |
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 3 Mar 2005 Editor: Chris Maunder |
Copyright 2005 by JSimms Everything else Copyright © CodeProject, 1999-2009 Web19 | Advertise on the Code Project |