• Advertisement
Sign in to follow this  

HoverButton Class

This topic is 4706 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have searched and searched for a way to change the default image of buttons in the Win32 API. I finally decided to make my own button class. I figured someone out there might get some use from it, so here it is. If you have any questions, comments, or suggestions, feel free to e-mail me at mrtie_dye at yahoo dot com. EDIT: I tried to edit the code so that it would fit in the screen better. Please forgive me if all the comments don't line up just right. :) CHoverButton.h
#ifndef CHOVERBUTTON_H
#define CHOVERBUTTON_H

#include <windows.h>
#include <stdio.h>
#include "bitmapobject.h"

class CHoverButton
{
public:
	CHoverButton();
	~CHoverButton();
	
	void initButton(HWND hwndMain,WORD img, int num,BOOL draw=TRUE);
	void initButton(BitMapObject &bmo,int x, int y,int butt, BOOL hovered=TRUE, BOOL trans=FALSE, BOOL clicked=FALSE);
	
	void isHovered(int x, int y, int butt);
	BOOL isClicked(int x, int y, int butt, BOOL dropped=FALSE);
	
	int getXcord(int butt);
	int getYcord(int butt);
	int getXsize();
	int getYsize();
	
private:
	int *xcord;
	int *ycord;
	
	int *mxcord;
	int *mycord;
	
	int xsize;
	int ysize;
	
	int numOfButtons;
	
	BOOL *hover;
	BOOL *transparent;
	BOOL *dropClick;
	BOOL initDraw;
		
	WORD bmpName;
	
	BitMapObject bmoButtonImg;
	BitMapObject *bmoMain;
	
	HWND hwnd;
};

#endif












CHoverButton.cpp
#include "CHoverButton.h"

CHoverButton::CHoverButton()
{
}

CHoverButton::~CHoverButton()
{
	//clean up all the pointers.
	if(bmoMain)
		delete bmoMain;
	
	if(xcord)
		delete xcord;
	
	if(ycord)
		delete ycord;
	
	if(mxcord)
		delete mxcord;
	
	if(mycord)
		delete mycord;
}

/***************************************************************
initButton is an overloaded function. The first initButton takes
arguments of types HWND,WORD, int, and BOOL. It sets up some of the more
"global" aspects of CHoverButton. The other initButton takes arguments
of types BitMapObject,3 integers, then 3 BOOLs. It sets up a specific button
and displays it's initial state(by defalut).

You want to call the first initButton listed below first. A typical call
would look something like

initButton(hwnd,IDC_BUTTONIMG,3);

Note that you can add FALSE after the 3 if you do not want the buttons 
drawn when they are inilized in the second call to initButton. The second
call is what sets up each individual button. You might have several of these,
which might look something like

initButton(bmoDisplay,50, 50,1); //the first button is a hover button at coordinates 50,50
initButton(bmoDisplay,50,100,2,FALSE,TRUE);//the second button is a transparent button at 50,100
initButton(bmoDisplay,50,150,3,FALSE,FALSE,TRUE);//the third button is a dropClick button at 50,150

******************************************************************/
void CHoverButton::initButton(HWND hwndMain,WORD img, int num,BOOL draw)
{
	hwnd = hwndMain;	//the handle to the window
	bmpName = img;	//the name of the image to load
	numOfButtons = num;//how many buttons are in the image
			   //this is how many rows of buttons are in the
			   //image. 
	
	hover = new BOOL[num+1];//tells if this is a hover button
				//defaults to TRUE
	
	transparent = new BOOL[num+1];//tells if this is a transparent button
			             //defaults to FALSE
	
	dropClick = new BOOL[num+1];//tells if this button's image changes 
				    //when it is clicked. Defaluts to FALSE
	
/****************************************************************
It should be noted that if a button is dropClick, then it should not
be transparent or hover. I could probably code it so that it 
could, but I don't see me ever needing to make a transparent button 
that changes images when hovered over or clicked on.
******************************************************************/
	
	initDraw = draw;		//tells if the buttons should be drawn when 
					//initButton is called. Defaluts to TRUE; 
						
	
	xcord = new int[num+1];	//each button will have an x and
	ycord = new int[num+1];	//y coordinate.
	
	mxcord = new int[num+1];//each button will also have an mx and my
	mycord = new int[num+1];//cordinate. This tells where to find the button
				//in the image.
	
	bmoButtonImg.Load(hwnd, bmpName);	//load the image from which to get the buttons
}

void CHoverButton::initButton(BitMapObject &bmo,int x, int y,int butt, BOOL hovered, BOOL trans, BOOL clicked)
{
	bmoMain = &bmo;	//bmoMain is the BitMapObject to draw the finished button to
	
	xcord[butt] = x;	//set the xcord for this particular button
	ycord[butt] = y;	//set the ycord for this particular button
	
	hover[butt] = hovered;	//is this a hover button?
	transparent[butt]=trans;	//is this a transparent button?
	dropClick[butt]=clicked;	//is this a dropClick button?
	
/******************************************************************
A note on the button image. There should only be two button images per
row in the bitmap. You can have as many rows as you like. In the case of
a hover button or dropClick buttons, the image on the left is displayed 
by default. The image on the right is displayed when the mouse is hovered
over the button(hover button) or clicked on(dropClicked). 

With transparent buttons, the image on the left should be the same as the 
one on the right. Any place you want the background to show through should be
white on the left side and black on the right side. This is how the transparancy
is created!
	
Here is a sample layout of the bitmap image. All squares should be the same size.
Note that for the purpose of the variable called numOfButtons, there are 3 buttons
in this example.

---------------------------------
*	      *			*
*default img  * hover or clicked*
*	      *	  image		*
*	      *			*
---------------------------------
*	      *			*
*white side   *  black side	*
*	      *			*
*	      *			*
---------------------------------
*	      *			*
*extra button *   extra button	*
*	      *		        *
*	      *			*
---------------------------------
      
***********************************************************************/	
	
	xsize = bmoButtonImg.GetWidth()/2; //we are trying to find the size of one
						//image. Since there are only two colums
						//we devide the total width by 2.
	
	ysize = bmoButtonImg.GetHeight()/numOfButtons;//we can have any number of rows,
						//which is also the number of buttons. 
	
	//if there is only 1 button, then it must be in the upper left corner
	//of the image.
	if(numOfButtons == 1)
	{
		mxcord[1] = 0;
		mycord[1] = 0;
	}
	else
	{
		//otherwise, we need to find out how many buttons down it is
		mxcord[butt] = 0;
		mycord[butt] = (butt-1)*ysize;
	}
	
	//By default, the buttons are drawn when they are initilized. You can specify
	//FALSE for initDraw when you call initButton, if you want.
	if(initDraw)
	{
		//if the button is transparent....
		if(transparent[butt])
		{
			//then you will want to lay the left image on top of the
			//right image. This will make the black/white area dissappear
	BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
	BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt],SRCPAINT);
		}
		//otherwise, it is solid....
		else
		{
			//so just draw the default image.
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCPAINT);
		}
	}
}

/******************************************************************************
isHovered should be called whenever windows is given the WM_MOUSEMOVE message.
You should capture the x,y cordinates of the mouse, and send them, as well as the
button number, to isHovered. NOTE: You should not call isHovered on a dropClick
button!

Note below all the statements that look like this

BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCPAINT);

You should notice that the only thing that is changing is the mxcord and mycord. We are
just moving around in the image. Everything else is the same in every case below.
*********************************************************************************/

void CHoverButton::isHovered(int x, int y, int butt)
{
/******************************************************************************
isClicked actually just testes to see if the x,y cordinates of the mouse match
those of the button in question. It doesn't actually test if the mouse button 
was clicked.
******************************************************************************/
	//if the mouse is on this button
	if(isClicked(x,y,butt))
	{
		//and this button is a hover button...
		if(hover[butt])
		{
			//and it is transparent.....
			if(transparent[butt])
			{
/**********************************************************************************
A transparent hover button actually requires 4 images, taking up 2 button slots. Out of
the four, the top left should be the default white image. To its right should be the
default black image. The bottom left should be the white hover image, and the bottom
right should be the black hover image.
***********************************************************************************/
				
				//in this case, we want to draw the bottom left image on top of 
				//the bottom right image.
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt]+ysize,SRCAND);
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt]+ysize,SRCPAINT);
			}
			//has the mouse on it,is hover, but not transparent
			else
			{
				//draw the image on the right side.
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt],SRCAND);
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt],SRCPAINT);
			}
		}
		//ok, where are we? Oh, mouse is on the button, but it is not a hover button
		else
		{
			//Draw the default transparent image
			if(transparent[butt])
			{
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt],SRCPAINT);
			}
			//Not transparent, you say?
			else
			{
				//Then just draw the default image for cryin' out loud
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCPAINT);
			}
		}
	}
	//if the mouse is not hovering on the button, then we don't care if it is a hover
	//button or not
	else
	{
		//same old thing for transparent buttons. This is the default transparent
		//image
		if(transparent[butt])
		{
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt],SRCPAINT);
		}
		//if it is not transparent, then just draw the default image.
		else
		{
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
		BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCPAINT);
		}
	}
}

/************************************************************************
isClicked is called by isHovered, but it can also be called from the message
loop. You would do this in the event of a WM_LBUTTONDOWN or WM_LBUTTONUP message
when the button is a dropClick. In the case of WM_LBUTTONDOWN, you should send 
the x,y cordinates of the mouse, as well as the BOOL TRUE, to let it know the
mouse button has been clicked on it. In the case of WM_LBUTTONUP, you should send
the x/y cordiantes of the mouse as well as the BOOL FALSE, to let it know the mouse
is no longer clicked on it.
******************************************************************************/

BOOL CHoverButton::isClicked(int x, int y, int butt, BOOL dropped)
{	
	//if the mouse x,y cordinates match those of the button in question...
	if((x > xcord[butt] && x < xcord[butt] + xsize) && (y > ycord[butt] && y < ycord[butt] + ysize))
	{
		//and it is a dropClick button...
		if(dropClick[butt])
		{
			//and the mouse button is clicked....
			if(dropped)
			{
				//draw the "pressed" image
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt],SRCAND);
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt]+xsize,mycord[butt],SRCPAINT);
			}
			//and the mouse button is not clicked....
			else
			{
				//draw the "up" image
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCAND);
			BitBlt(*bmoMain,xcord[butt],ycord[butt],xsize,ysize,bmoButtonImg,mxcord[butt],mycord[butt],SRCPAINT);
			}
		}
		//return TRUE so that isHovered will know the mouse is hovering on it
		return TRUE;
	}
	else
	{
		//we return false if the mouse is not on the button
		return FALSE;
	}
}

/****************************************************************
The rest of these funtions are simple funtions that allow you to 
access private member variables from the outside.
*****************************************************************/

int CHoverButton::getXcord(int butt)
{
	return xcord[butt];
}

int CHoverButton::getYcord(int butt)
{
	return ycord[butt];
}

int CHoverButton::getXsize()
{
	return xsize;
}

int CHoverButton::getYsize()
{
	return ysize;
}












[Edited by - mrtie_dye on May 31, 2005 7:18:28 AM]

Share this post


Link to post
Share on other sites
Advertisement
Yeah, I guess that would be useful. :)

BitMapObject.h

/*******************************************************************************
The BitMapObject class was borrowed from Evil_Greven's "Tetris clone in an
hour with C++" tutorial on gamedev.net. You can find it here...
http://www.gamedev.net/community/forums/topic.asp?topic_id=192483
I have modified it slightly to suit my needs.
********************************************************************************/


//BitMapObject.h
#ifndef BITMAPOBJECT_H
#define BITMAPOBJECT_H

#include <windows.h>

class BitMapObject
{
private:
//memory dc
HDC hdcMemory;
//new bitmap!
HBITMAP hbmNewBitMap;
//old bitmap.
HBITMAP hbmOldBitMap;
//width & height as integers.
int iWidth;
int iHeight;

public:
//constructor
BitMapObject();

//destructor
~BitMapObject();

//loads bitmap from a file
void Load(HWND hwnd, WORD lpszFilename);

//creates a blank bitmap
void Create(HDC hdcCompatible, int width, int height);

//destroys bitmap and dc
void Destroy();

//return width
int GetWidth();

//return height
int GetHeight();

//converts to HDC
operator HDC();
};

#endif



BitMapObject.cpp

/*******************************************************************************
The BitMapObject class was borrowed from Evil_Greven's "Tetris clone in an
hour with C++" tutorial on gamedev.net. You can find it here...
http://www.gamedev.net/community/forums/topic.asp?topic_id=192483
I have modified it slightly to suit my needs.
********************************************************************************/


//BitMapObject.cpp
#include "bitmapobject.h"

BitMapObject::BitMapObject()
{
hdcMemory=NULL;
hbmNewBitMap=NULL;
hbmOldBitMap=NULL;
iWidth=0;
iHeight=0;
}

BitMapObject::~BitMapObject()
{
//if the hdcMemory hasn't been destroyed, do so
if(hdcMemory)
Destroy();
}

void BitMapObject::Create(HDC hdcCompatible, int width, int height)
{
//if hdcMemory isn't null, blow it up!
if(hdcMemory)
Destroy();

//create the memory dc.
hdcMemory=CreateCompatibleDC(hdcCompatible);
//create the bitmap
hbmNewBitMap=CreateCompatibleBitmap(hdcCompatible, width, height);
//shove the image into the dc
hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory, hbmNewBitMap);
//change the width and height.
iWidth=width;
iHeight=height;
}

void BitMapObject::Load(HWND hwnd, WORD lpszFilename)
{
if(hdcMemory)
Destroy();

BITMAP bmp;
PAINTSTRUCT ps;

HDC hdc = BeginPaint(hwnd, &ps);

hdcMemory = CreateCompatibleDC(hdc);

hbmNewBitMap=LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(lpszFilename));
//shove the image into the dc
hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory,hbmNewBitMap);
//grab the bitmap's properties
GetObject(hbmNewBitMap,sizeof(BITMAP),(LPVOID)&bmp);
//grab the width & height
iWidth=bmp.bmWidth;
iHeight=bmp.bmHeight;

SelectObject(hdc, hbmOldBitMap);
DeleteDC(hdc);
EndPaint(hwnd, &ps);
}

void BitMapObject::Destroy()
{
//restore old bitmap.
SelectObject(hdcMemory, hbmOldBitMap);
//delete new bitmap.
DeleteObject(hbmNewBitMap);
//delete device context.
DeleteDC(hdcMemory);
//set members to 0/NULL
hdcMemory=NULL;
hbmNewBitMap=NULL;
hbmOldBitMap=NULL;
iWidth=0;
iHeight=0;
}

BitMapObject::operator HDC()
{
//return hdcMemory.
return(hdcMemory);
}

int BitMapObject::GetWidth()
{
//return width
return(iWidth);
}

int BitMapObject::GetHeight()
{
//return height
return(iHeight);
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement