
Introduction
It appears after some minor searching that nobody has written a BitmapButton for The Code Project (or anywhere else). WiB's excellent XP style button control solves the problem of XP style buttons with icons. But what if you want to control the entire appearance of the button using a bitmap, regardless of OS, manifest, theme, etc.? This control does provides that ability. Mind you that this class is pretty bare bones--I haven't made any effort to make is usable with a form designer. If anyone wants to update the code with this capability, I'll be more than happy to add them as a co-author.
Using The BitmapButton
Specifying Button State Images
The BitmapButton class uses a single bitmap comprised of one or more images, where each image represents the button in one of five states. The images must be placed contiguously from left to right. For example:

represents the bitmap of a button with five states:
- up
- down
- focused
- mouse-over
- disabled
Initializing The BitmapButton
The button is initialized in the usual manner with the additional line of code to specify the bitmap file:
bitmapButton=new BitmapButton();
bitmapButton.Location=new Point(232, 32);
bitmapButton.Size=new Size(32, 32);
bitmapButton.TabIndex=0;
bitmapButton.Text="&Down";
bitmapButton.Image=new Bitmap("downArrow.bmp");
Three important notes:
- The
Text field is used exclusively to specify the keyboard shortcut for the button;
- The button width should be the same as the width of a single state image in the bitmap (all images should be the same width and height);
- The button height should be the same as the bitmap height.
That's it. (If you forget the image, the program will generate an exception).
Behind The Scenes
Button State
Button state is a complicated thing when considering the dual user interface of keyboard and mouse. For example, the user may have the mouse over the button but be using the tab key to navigate between the controls. A complete state diagram appears as follows:

This diagram represents the state transitions that must be considered when using the mouse and the keyboard together. It's fairly complicated!
Button State Using The Keyboard
If the keyboard is being used, the state diagram is much simpler (the Disabled state has been removed for clarity only):

Button State Using The Mouse
If the mouse is being used, the state diagram has some missing state transitions (again, the Disabled state has been removed for clarity only):

Event Handlers
To manage all the events that can occur and properly transition between different states, several event handlers must be defined:
Paint+=new PaintEventHandler(BitmapButton_Paint);
MouseDown+=new MouseEventHandler(BitmapButton_MouseDown);
MouseUp+=new MouseEventHandler(BitmapButton_MouseUp);
GotFocus+=new EventHandler(BitmapButton_GotFocus);
LostFocus+=new EventHandler(BitmapButton_LostFocus);
MouseEnter+=new EventHandler(BitmapButton_MouseEnter);
MouseLeave+=new EventHandler(BitmapButton_MouseLeave);
KeyDown+=new KeyEventHandler(BitmapButton_KeyDown);
KeyUp+=new KeyEventHandler(BitmapButton_KeyUp);
EnabledChanged+=new EventHandler(BitmapButton_EnabledChanged);
| Paint |
Responsible for painting the button in all its different states. |
| MouseDown |
Transitions into the "Clicked" state. |
| MouseUp |
Transitions into the "Has Focus" state. |
| GotFocus |
Transitions into the "Has Focus" state (got focus through keyboard, for example) |
| LostFocus |
Transitions into the "Button Up" or "Mouse Over" state. |
| MouseEnter |
If in the "Button Up" state, transitions to the "Mouse Over" state. |
| MouseLeave |
If in the "Mouse Over" state, transitions to the "Button Up" state. |
| KeyDown |
Transitions to the "Clicked" state when the user presses the spacebar while the button has focus. |
| KeyUp |
Transitions to the "Has Focus" state when the user releases the spacebar while the button has focus. |
| EnabledChanged |
Transitions to the "Disabled" state or back to the "Button Up" state when the Enabled state of the button is changed. |
Drawing The Image
While double buffering is not required, since the entire state image is drawn on the surface of the button, it is implemented in case the control is enhanced to include additional drawing effects. Double buffering is specified with the SetStyle method, which is a protected member, because someone decided that, since the control will have its own Paint handler, it should not be settable without sub-classing the control. Never mind that the Paint event handler could be implemented in a completely separate class!
SetStyle(ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer, true);
The button image is displayed in the Paint event handler. Given the state, it determines the index of the requested image. The bitmap does not need to include all the image states, as long as the image states provided are contiguous (meaning, you can't have button up, button down, and disabled image states, leaving focused and mouse-over empty--if you want an image for the disabled state, then you have to provide images for all the other states as well). private void BitmapButton_Paint(object sender, PaintEventArgs e)
{
Graphics gr=e.Graphics;
int indexWidth=Size.Width*(int)imgState;
if (Image.Width > indexWidth)
{
gr.DrawImage(Image, 0, 0,
new Rectangle(new Point(indexWidth, 0), Size),
GraphicsUnit.Pixel);
}
else
{
gr.DrawImage(Image, 0, 0,
new Rectangle(new Point(0, 0),
new Size(Size.Width, Size.Height)),
GraphicsUnit.Pixel);
}
}
Conclusion
Wow, that's probably one of the shortest articles I've written in recent times! Bitmap buttons can have a lot more complexity to them than I have implemented here. For example, what if your images don't have borders, and you'd like the control to generate a 3D style border by itself? There's also considerations for different button state sizes and transparency, for example. Hopefully, this article will give the reader the basis for customizing the bitmap control to his/her needs.
| You must Sign In to use this message board. |
|
|
 |
|
 |
I used this code to make a round button and was very happy with the results. (Thanks again, Marc).
However, when shipped to the users, on some computers the image was not cropped to the image size, but larger (by ~25%) so some of the next image appeared on the button. (I have an image, but can't figure if I can upload it). I believe this was caused by Display setting for Large Size Fonts (120 DPI instead of 96 DPI). Has anyone seen this, and have any ideas for a workaround?
Thanks
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|
 |
|
 |
I seen posts about the same sort of thing with other controls. I beleave that they fixed it by setting the dpi of the image to 96 before assigning it to the control. Something like this:
Bitmap i = MyProject.Properties.Resources.myBMP; i.SetResolution(96, 96); return i;
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It would be nice with areas (e.g. the triangle in this case) that was the actual button. You could easily impliment that by adding an extra image to your imagestrip. This image would be an x-ray (black&white). Whenever the mouse is over a black pixel, we are in the hot area which is the actual button. That way, the button do not have to be square, triangle or whatever.
Gooky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
hi all I am need help .... how can i implement start button (like windows )in my apllication(program)? thanks alote
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
hey marc, nice one - quick 'n dirty =); but whats about removing the rectangle if the button has focus? what am i supposed to do?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
chris18 wrote: but whats about removing the rectangle if the button has focus? what am i supposed to do?
You mean the black border around the button? Edit the .bmp file and remove it for the focused state. The .bmp file in the example has a black border around all the button states.
If that's not what you meant, let me know.
Marc
Latest AAL Article My blog Join my forum!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
no, sorry thats not what i wanted. i tried the button with a new self-created bitmap(png) file. it works fine, but if the button gets focused, a black border is drawn. it disappears after the buttons loses the focus.
several days before i discovered your bitmapbutton solution i tried to do somethink like that myself, but i always came up with that border. its especially annoying if you choose non rectangle images.
btw. can you tell me, why the jpg/png etc. files (in contrast to the bmp ones) always get drawn a bit bigger in VS2003 than everything else draws them? i suppose its related to the image's resolution? it seems that VS2003 accepts or draws them in a horizontal resolution of 96 instead of whatever it was created with - is that true?
thanks!!
chris
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
One way to solve the problem is to inherit from Control instead of button.. but then you have to add some code:
in the constructur:
this.Click += this.BitmapButton_Click;
and in the class:
private Image image = null; public Image Image { get { return this.image; } set { this.image = value; this.Invalidate(); } }
void BitmapButton_Click(object sender, EventArgs e) { this.Focus(); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
Marc Clifton wrote: I'm using Visio.
So far 3 questions and all related to Visio.
I can smell an article, Marc!
Simple Intro to Visio by Marc Clifton
"...if you don't want to hear things that piss you off don't piss off other people. SIMPLE." - Steven Hicks This signature was created by "Code Project Quoter".
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Kant wrote: Simple Intro to Visio by Marc Clifton
He he. What I'd like to write is an article on interfacing to Visio in .NET. The thing can be completely controlled programmatically. I used it several years ago for a client that designs and manufactures satellites. One of the required drawings, a frequency plan showing uplink/downlink channels, channel separation, command/data, etc., took 2 weeks for an engineer to generate manually. Given about 2 minutes of inputting about 20 parameters, I programmatically generated the frequency plan in about 5 minutes. (One of the funny stories is that an engineer was on the plane to meet with a customer and realized he'd forgotten the drawings. He pulled out his laptop and redid the whole batch in about an hour on the plane!) The same thing was done with the payload block diagram, showing the full signal path from input antenna through the demultiplexers, amplifiers, multiplexers, and back to the output antenna.
It's too bad I can't demonstrate that project, but it's all proprietary. 
Marc
Help! I'm an AI running around in someone's f*cked up universe simulator. Sensitivity and ethnic diversity means celebrating difference, not hiding from it. - Christian Graus Every line of code is a liability - Taka Muraoka Microsoft deliberately adds arbitrary layers of complexity to make it difficult to deliver Windows features on non-Windows platforms--Microsoft's "Halloween files"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
leppie wrote: What did you use for those pictures?
Visio.
leppie wrote: I didnt realise you needed such a "simple" bitmap button
Yup. Turns out though that after writing it, I didn't like how it looked on my client's software, so I ended up using WiB's XP-style button control. Oh well, I know I can use this on some other projects though.
Marc
Help! I'm an AI running around in someone's f*cked up universe simulator. Sensitivity and ethnic diversity means celebrating difference, not hiding from it. - Christian Graus Every line of code is a liability - Taka Muraoka Microsoft deliberately adds arbitrary layers of complexity to make it difficult to deliver Windows features on non-Windows platforms--Microsoft's "Halloween files"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Thanks!
Kant wrote: I think this article should be under this category. http://www.codeproject.com/cs/miscctrl/[^]
What about "Button Controls"? I saw a category there. Didn't see it in the pulldown list--I'll check and move it.
Visio. It's great.
I should put that vsconverter utility at the top of all my articles. Thanks for the reminder.
Marc
Help! I'm an AI running around in someone's f*cked up universe simulator. Sensitivity and ethnic diversity means celebrating difference, not hiding from it. - Christian Graus Every line of code is a liability - Taka Muraoka Microsoft deliberately adds arbitrary layers of complexity to make it difficult to deliver Windows features on non-Windows platforms--Microsoft's "Halloween files"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Marc Clifton wrote:
What about "Button Controls"? I saw a category there. Didn't see it in the pulldown list--I'll check and move it. Come on, people, this is just a common case for 'multiple inheritance'
Due to technical difficulties my previous signature, "I see dumb people" will be off until further notice. Too many people were thinking I was talking about them... 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|