Click here to Skip to main content
15,885,216 members
Articles / Desktop Programming / MFC

Making Cool Button using Images

Rate me:
Please Sign up or sign in to vote.
2.27/5 (16 votes)
8 Jun 2010CPOL4 min read 133.3K   5.3K   58   14
This article is about creating cool buttons on a dialog

Updated: June 8, 2010  

I know you did not love me the first time when I wrote this article because of my non-nativity and non-familiarity with English language and ON_MESSAGE macro implementation which was causing a crash in release mode. I have updated this article and hope you will like it this time. I have added the Source Files and Sample Projects for download separately and the solution in Sample Project is converted to Visual Studio 2008. 

Introduction 

There is a bunch of articles regarding creating cool buttons on CP and Internet but if you are looking for a 10-minute solution to a problem without having to go through nice, huge and fancy articles, this one is for you. 

The way it works is, it assumes that each button has three states, which  are 1) Normal, 2) Hover and 3) Down. 

Normal: When a button is visible to the user on the screen and mouse has not entered the button region. 

Hover: When a button has lit up for the user who has moved the mouse pointer over it.

Down: This is the state when the button is pushed (or clicked), or when the left mouse button is pressed and not release yet. 

 

For each state of a button, it requires an image from the resource and all three images have to be the same size. 

Here is the snapshot of how the three states will look like. 

Snapshot 

Sample screenshot


How to use? 

Create a button on your dialog and set it to be Owner-Drawn. As most of you may know it already that this could be set either from the dialog resource editor or it could be set in run-time. 

There is a Class CCoolButton, derived from CButton, You need to create a member of CCoolButton type for each button in your Dialog class, and use DDX_Control in DoDataExchange to subclass.

Following is the only constructor you may use:

CCoolButton(int nIDNormal, int nIDHover, int nIDDown);

The three arguments are resource IDs, you should specify the bitmap resource ids. .

The Default constructor is private, you must specify the three bitmaps from resources when creating object.

 

10-minute implementation 

Step 1: Download the Source Files from the link on top.
Step 2: Add Fcool.h and Fcool.cpp to your project. 
Step 3: For each button
               a) Add three (Normal, Hover and Down) images unless some buttons share the look.
               b) Add a member of CCoolButton in your CDialog-derived class
               c) Change your buttons to Owner-Drawn.
               d) In DoDataExchange(), DDX_Control your button resource id with the member object of CCoolButton in your CDialog-derived class.
Step 4: Tell your boss that your work for the week is done :) 

 

How does it works?

All it does it is, it traps the three 1) When the mouse pointer has not entered the region, 2) Mouse pointer has entered the region and 3) Mouse pointer is in the button region and user has pressed the left button. 

In constructor, bitmap has been loaded from resource to three CBitmap object aggregated by CCoolButtons.

_TrackMouseEvent() is being used to trap the event when the mouse pointer leaves the button region, I called it "OnLeave" , and defined in msg map, using OnMessage.

When users moves the mouse pointer in the button region, the status of the button changes to Hover and the Custom (overridden) DrawItem invokes, so we draw Hover Image from m_bmpHover member. and it calls _TrackMouseEvent() to try to see if the pointer has left the region or not. 

Following is code for OnMouseMove,

void CCoolButton::OnMouseMove(UINT nFlags, CPoint point)
{
 CRect ButtonRect;
 TRACKMOUSEEVENT tme;
 
 GetWindowRect(&ButtonRect);
 if (m_Status == DOWN) 
 {
  if (IsInRect(ButtonRect,point))
  {
 
  }
  else
  {
   SetStatus(HOVER);
   Invalidate(FALSE);
  }
 }
 else if (m_PrevStatus == DOWN && m_Status == HOVER)
 {
  SetStatus(DOWN);
 }
 else
 {
  if (IsInRect(ButtonRect,point))
  {
   SetStatus(HOVER);
   Invalidate(FALSE);
  }
  else
  {
   SetStatus(NORMAL);
  }
 }
 CButton::OnMouseMove(nFlags, point);
 tme.cbSize = sizeof(TRACKMOUSEEVENT);
 tme.dwFlags = TME_LEAVE;
 tme.hwndTrack = m_hWnd; _TrackMouseEvent(&tme);
 }

Normally, in windows if you look at the normal button, when you press the mouse left button down over it and without releasing move the pointer out of the region, it doesnt spare the button's soul, although it draws the normal picture again but when you move the pointer back in the region (with the left button pressed) it draws the "down" image again and if you release the button while the pointer is in the region, it sends the command. To mimic this behavior I have used the help of SetCapture() and ReleaseCapture() in OnLButtonDown() and OnLButtonUp() respectively. 

Following is DrawItem.

void CCoolButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
 CDC *pthisDC;
 CDC bmpDC;
 CBitmap *pOldBitmap;
 pthisDC = CDC::FromHandle(lpDrawItemStruct->hDC);
 bmpDC.CreateCompatibleDC(pthisDC);
 switch (m_Status)
 {
 case NORMAL:
  pOldBitmap = bmpDC.SelectObject(&m_bmpNormal);
  break;
 case HOVER:
  pOldBitmap = bmpDC.SelectObject(&m_bmpHover);
   break;
 case DOWN:
  pOldBitmap = bmpDC.SelectObject(&m_bmpDown);

  break;
 }
 pthisDC->BitBlt(0,0,lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left,
 lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top,&bmpDC,0,0,SRCCOPY);
 bmpDC.SelectObject(pOldBitmap);
 bmpDC.DeleteDC();
 
}

Here we go, your button is ready. I would like to know your feedback on this article 

Alright! :) 

I know its not performance efficient and it could be improved in a lots of ways and I have not done the "disable" button state yet. But again this is for those who are looking for a 10 minutes solution to turn all buttons on their forms to cool buttons. 

License

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


Written By
Systems Engineer
United States United States
My name is Fahad Ashfaque, I work for a financial company in USA as Senior Software Engineer. I have done MS in computer science. My hobbies are Enjoying the Nature, Finding new ways to living green, Swimming, Reading news, Researching on stuff etc. My hotmail account is not active. Please use CP to send me a message.

Comments and Discussions

 
Generalbug fix Pin
Jae-in, Kim7-Dec-04 14:25
sussJae-in, Kim7-Dec-04 14:25 
Generalresizing the button. Pin
Anonymous21-Jul-04 9:59
Anonymous21-Jul-04 9:59 
GeneralFile not found Pin
Filomela11-May-04 20:59
Filomela11-May-04 20:59 
Generalfix bugs Pin
stephen(china)17-Mar-04 10:11
stephen(china)17-Mar-04 10:11 
GeneralRe: fix bugs Pin
vite10-Jun-04 16:20
vite10-Jun-04 16:20 
GeneralRe: fix bugs Pin
Anonymous13-Jul-04 2:31
Anonymous13-Jul-04 2:31 
GeneralUnvisible buttons images ! (at release mode) Pin
muhon2-Nov-03 21:20
muhon2-Nov-03 21:20 
Generalbag fix Pin
liveboys29-Sep-03 2:47
liveboys29-Sep-03 2:47 
Generalthere is a error in release Pin
ltqin28-Sep-03 22:10
ltqin28-Sep-03 22:10 
in release it cant show in nomal, and have a error when exit
GeneralSetCapture/ReleaseCapture Pin
Davide Pizzolato22-Sep-03 1:12
Davide Pizzolato22-Sep-03 1:12 
GeneralCButtonST Pin
Davide Calabro22-Sep-03 0:37
Davide Calabro22-Sep-03 0:37 
QuestionIllustration ? Pin
Stlan21-Sep-03 23:20
Stlan21-Sep-03 23:20 
GeneralSource code page Pin
bruno leclerc21-Sep-03 20:43
bruno leclerc21-Sep-03 20:43 
GeneralRe: Source code page Pin
FahadAsh21-Sep-03 22:06
FahadAsh21-Sep-03 22:06 

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.