Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C++

A Super-button to Replace CBitmapButton for MFC Programs

Rate me:
Please Sign up or sign in to vote.
3.30/5 (7 votes)
26 Aug 2006CPOL5 min read 57.6K   1.7K   27   3
A super-button to replace CBitmapButton for MFC programs

Introduction

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:

  1. Only needs one normal image.
    Other images or button requests are auto generated.
    CBitmapButton requires 4 images: normal, pressed, focus, and disabled images.
  2. Image background is transparent.
    Transparent feature is the same as CToolBar.
  3. 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.
  4. Supports for tool tip.
  5. A few more options.

Following is the interface of resource program.

Image 1

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.

Disabled Button

If you click right button "Enable or disable", buttons will be enabled/disabled.
Disabled buttons look like:

Image 2

If you look at the top 2 buttons carefully, you may find that their disabled images are slightly different (see below).

Raised Weaker

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:

Image 3

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.

Focus

If a button gets focus, dot lines are simply drawn along its border inside.

Image 4

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?

Disable Strategies

An option allows to generate disabled image in different ways:

Image 5

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

  1. 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 CButton.

  2. Usage
    • 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 CButton to ButtonMine.
      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 CBitmapButton to 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.

  3. Functions
    • C++
      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 iBmpID.
      The second function loads image from file - identified by pszFile.
      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 OnInitDialog().

    • C++
      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.

    • C++
      void SetWeaker(BOOL bWeaker)
      Optional function.
      If bWeaker is TRUE (default is FALSE), button's border is drawn only for once - refer to picture above.
    • C++
      void SetShowFocus(BOOL bShowFocus)
      Optional function.
      If bShowFocus is FALSE (default is TRUE), focus lines will not be drawn - refer to the picture above.

Code Inside

The most important code is in function SetImage(...).

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_Nml and bmp_Dis of inner class TheBitmap.

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.

History

  • 26th August, 2006: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Australia Australia

Please visit our Download Home to obtain many interesting software for free ...


Comments and Discussions

 
GeneralWorks great Pin
Member 87818142-Sep-12 15:41
Member 87818142-Sep-12 15:41 
GeneralExcellent -- one tweak needed however in my experience Pin
zunkination10-Sep-07 7:10
zunkination10-Sep-07 7:10 
GeneralDon't forget to test on themed systems Pin
Anna-Jayne Metcalfe26-Aug-06 11:35
Anna-Jayne Metcalfe26-Aug-06 11:35 

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.