I had thought about creating a button to replace
CBitmapButton for years.
Yesterday, I overcame my lazy habits and started to create the button.
This button, in my opinion, is much better than
CBitmapButton because of the following reasons:
- Only needs one normal image.
Other images or button requests are auto generated.
CBitmapButton requires 4 images: normal, pressed, focus, and disabled images.
- Image background is transparent.
Transparent feature is the same as
- Supports for both resource bitmap and image files (such as bitmap, GIF, JPG).
So the button can display rich-colored images as we see on websites, which is much nicer.
- Supports for tool tip.
- A few more options.
Following is the interface of resource program.
The 5 buttons in the middle are mine. The top 2 of them use resource bitmap - background color is gray. The bottom 3 use bitmap, GIF and JPG files respectively - background color is black.
Background color of JPG file cannot be transferred to
COLOR_BTNFACE properly - I will talk about why later.
Tool tips are associated with each button. If you run the source program and move mouse into buttons, you can see their tool tips at run time.
If you click right button "Enable or disable", buttons will be enabled/disabled.
Disabled buttons look like:
If you look at the top 2 buttons carefully, you may find that their disabled images are slightly different (see below).
This is a little bit of a fun option, which allows to change button border from stronger to weaker.
Stronger border draws border twice, weaker draws only once. You can click right button "Raised Weaker or Stronger" to change the option. Weaker border looks like:
Could you find border difference between the above and first picture?
XP uses different colors to draw button border, such as RGB(241,239,226), RGB(113,111,100), I only use black and white colors - easy or lazy.
XP operating system loses much 3D effects than 95/98/NT because of its default dialog color.
If a button gets focus, dot lines are simply drawn along its border inside.
An option allows to hide the dot lines, so these dot lines will not be drawn even if the button gets focus.
You can try click right button "Show or hide Focus" to see the feature.
I don't like focus lines, so I add the option for myself - is there another programmer who doesn't like focus border in the world?
An option allows to generate disabled image in different ways:
The left one is normal - as Windows disabled images, which moves white shadow 1 pixel to down and right side. The right one moves white shadow 1 pixel to top and left side.
The left one looks like "sunken", right one looks like "raised".
Files, Class, Usage and Functions
- Files and class
There are 2 files in directory "lib" of source program: ButtonMine (H and CPP).
The file contains only one class:
ButtonMine, which is inherited from
- Static way
Add a button to dialog from dialog editor of VC, then change the button style as owner-draw.
Add a member-variable for the button from MFC-class-wizard.
Go to the dialog's header file, change the button type from
The above steps are exactly the same as that for
CBitmapButton, so you know them already.
- Dynamic way
You can call
Create() function to create the button dynamically.
Yesterday, after I developed the button, I changed all image buttons in my current commercial application from
ButtonMine, they work perfect without any problem - but all of them are in static way.
Unfortunately, I haven't tried a dynamic way to create a button so far, because I don't have time to do extra things except my application needs. I guess the dynamic way should be OK.
There are 2 reasons for me to spend hours to write the article: first of all, I have used several source programs downloaded from CodeProject, they are really helpful, I submit the article for a fair exchange. Second, I hope to have more professional traffic to our website, so, please do not forget to visit our site after you read the doc or download my source program.
BOOL SetImage(int iBmpID,COLORREF clrBkgnd=RGB(192,192,192),
BOOL bAutoSize=TRUE,BOOL bNormalDisable=TRUE);
BOOL SetImage(LPCSTR pszFile,COLORREF clrBkgnd,
BOOL bAutoSize=TRUE,BOOL bNormalDisable=TRUE);
The first function loads image from resource - identified by
The second function loads image from file - identified by
bAutoSize: If button size is resized according to image size.
bNormalDisable: Disabled image is in "sunken" (normal) or "raised" style - refer to pictures above.
The 2 functions can be called anywhere - such as in dialog's constructor or
void SetToolTip(LPCSTR pszToolTip);
Optional function which must be called after dialog has been initialized - normally in
OnInitDialog() - because tool tip needs valid window handle of dialog.
There are other 2 versions of
SetImage(...) functions, which involve tool tips, so they must be called after dialog has been initialized.
void SetWeaker(BOOL bWeaker)
TRUE (default is
FALSE), button's border is drawn only for once - refer to picture above.
void SetShowFocus(BOOL bShowFocus)
FALSE (default is
TRUE), focus lines will not be drawn - refer to the picture above.
The most important code is in function
When a resource bitmap ID or image file is passed into the function, a template buffer is created to read image's bits, the template buffer is deleted after using inside the function.
There are 2 permanent image buffers (class members), one is for normal image, another one is for disabled image. Those 2 buffers are larger than template buffer - in other words, the 2 images are 2x2 pixels larger than source image in size, because disabled image needs one more pixel border to make white shadow for disabled effect.
The 2 buffers are held by instance
bmp_Dis of inner class
When source image is copied to
bmp_Nml, background color is transferred to
COLOR_BTNFACE, that is why button images look transparent.
There are 2 reasons why JPG image is not transparent:
First of all, I don't know how to use PhotoShop, so I don't know if background color of its image file (img\img.jpg) is real black.
Second, the JPG file is loaded by function
::OleLoadPicturePath(...), who knows what the function does inside? If it really transfers black to black from JPG to bitmap format, the image should be transparent.
- 26th August, 2006: Initial post