简单的图标按钮类(SDK)

 

 

 

 

 

 

//头文件

/*******************************************************************************************************
*
*               图标按钮类(SDK)
*
*                BY commander
*
*                基于网上代码 geniusdot 的 "VC++ WIN32 sdk实现按钮自绘详解" 的修改
*          
*                编写工具:VS2005
*
*                日期:2011/10/02
*
*                说明:用到WINDOWS SDK写程序,苦于网上很少关于图标按钮的文章,
*                            为了方便,写了个很不给力的类,给和我一样的菜鸟中的菜鸟
*                             一些参考,少走一点弯路吧。
*
*                  调用方法:1.在工程中添加一个按钮设置ID为IDB_BUTTON1
*                                          2.必须设置IDB_BUTTON1按钮的STYLE为owenerdraw属性
*											3.添加3个图标,分别用于正常状态显示,在按钮上空时显示,按下时显示
*											3.在IDB_BUTTON1按钮的直接父窗口的窗口处理函数中(假设是WinMainProc)添加如下
*												LONG_PTR __stdcall WinMainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
*												{//消息处理
*														static IconBtn objIconBtn(hWnd);
*														switch(uMsg)
*														{
*															case WM_INITDIALOG:
*																	objIconBtn.AddBtn(IDI_ICON1,IDI_ICON2, IDI_ICON3, IDC_BUTTON1);
*																	objIconBtn.AddBtn(IDI_ICON1,IDI_ICON2, IDI_ICON3, IDC_BUTTON2);
*																	objIconBtn.AddBtn(IDI_ICON1,IDI_ICON2, IDI_ICON3, IDC_BUTTON3);
*																	break;
*															case WM_DRAWITEM:
 *																	 objIconBtn.DrawMsg(hWnd, lParam);
*																	return true;
*														}
*														return false;
*												}
*******************************************************************************************************/
#ifndef  __ICONBTNSDK_H_
#define __ICONBTNSDK_H_
#include <vector>
#include <windows.h>
/*
出现编译错误注意:
在VC2005中调试一个可执行文件时代码生成通过,但是连接时编译器报错:

Generating Code...
正在链接...
LINK : warning LNK4098: 默认库“LIBCMT”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
libcpmtd.lib(cerr.obj) : error LNK2001: 无法解析的外部符号 __CrtDbgReportW
libcpmtd.lib(stdthrow.obj) : error LNK2001: 无法解析的外部符号 __CrtDbgReportW
libcpmtd.lib(xmbtowc.obj) : error LNK2001: 无法解析的外部符号 __CrtDbgReportW
libcpmtd.lib(cout.obj) : error LNK2001: 无法解析的外部符号 __CrtDbgReportW
以下是解决方法:
 运行时库现在包含可防止混合不同类型的指令。如果试图在同一个程序中使用不同类型的
 运行时库或使用调试和非调试版本的运行时库,则将收到此警告。例如,如果编译一个文件
 以使用一种运行时库,而编译另一个文件以使用另一种运行时库(例如单线程运行时库对
 多线程运行时库),并试图链接它们,则将得到此警告。应将所有源文件编译为使用同一
 个运行时库。有关更多信息,请参见使用运行时库(/MD、/MT   和   /LD)编译器选项。
于是打开项目属性,在“配置属性-->C/C++-->代码生成-->运行时库”中将“多线程(/MT)”
修改为“多线程调试(/MTd)”,再重新调试一下,问题解决。
*/
class IconBtn
{
	//所有的按钮自身都调用系统同一个处理函数
public:
	IconBtn(HWND hParentWnd);
	//参数说明:正常图标ID, 按钮上空图标ID, 按钮选中图标ID,按钮ID
	void AddBtn(UINT normalIconID, UINT hoverIconID, UINT downIconId, UINT btnID);
	//处理按钮WM_DRAWITEM消息,在父窗口处理函数中的WM_DRAWITEM中调用
	BOOL DrawMsg(HWND hDlg, LPARAM lParam);
	
private:
	//void  RedtBtnProc(HWND hParWnd);
	void PrepareImageRect(HWND hBrnWnd, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, 
												BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight,  RECT* rpImage);
	//画ICON
	void DrawTheIcon(HWND hBtnWnd, HDC* dc, BOOL bIsDisabled, HICON hIcon);
	//判断当前触发重画命令的控件是否是一个按钮, true:是按钮,并返回各HICO
	bool CurCtrlIsBtn(UINT CtlID, HICON &normalIcon, HICON &hoverIcon, HICON &downIcon);

private:
   	HWND m_hParWnd;
	struct BtnStruct 
	{
		struct BtnStruct(HICON normalIcon, HICON  hoverIcon, HICON  downIcon, UINT btnID) : 
	                       m_normalIcon(normalIcon), m_hoverIcon(hoverIcon), 
						   m_downIcon(downIcon), m_btnID(btnID) {}
	   struct BtnStruct &operator= (const struct BtnStruct &b)
	   {
		   this->m_btnID = b.m_btnID;
		   this->m_downIcon = b.m_downIcon;
		   this->m_hoverIcon = b.m_hoverIcon;
		   this->m_normalIcon = b.m_normalIcon;
		   return *this;
	   }
		HICON  m_normalIcon, m_hoverIcon, m_downIcon;
		UINT     m_btnID;
	};
	std::vector<BtnStruct > m_btnDataVec;
};

#endif



//源文件.CPP
#ifndef  __ICONBTNSDK_CPP_
#define __ICONBTNSDK_CPP_
#include "IconBtnSDK.h"
#include <commctrl.h>
#pragma comment(lib, "Comctl32.lib")
#define ICON_SIZE 54

static LONG_PTR btnDefProc = -1;
//所有的按钮自身都调用系统同一个处理函数
LONG_PTR BtnProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{//
	/*
	TME_NONCLIENT是非客户区消息,你在WM_MOUSEMOVE里TrackMouseEvent是没有用的,
	因为这样只有鼠标在客户区才会关注WM_NCMOUSEMOVE,而鼠标移到标题栏因为没有触发
	WM_MOUSEMOVE,就没有TrackMouseEvent,也就不会有WM_NCMOUSEMOVE消息
	如下才能接收WM_MOUSEHOVER
	*/
	static TRACKMOUSEEVENT tacMouseEv;

	//_TrackMouseEvent((LPTRACKMOUSEEVENT)&tacMouseEv);

	switch (uMsg)
	{
	case WM_MOUSELEAVE:	
		{
			UINT CtlID = GetWindowLong(hWnd, GWL_ID);
			static DRAWITEMSTRUCT param;
			param.CtlID = CtlID;
			param.CtlType = ODT_BUTTON;
			param.hDC = GetWindowDC(hWnd);
			param.hwndItem= hWnd;
			param.itemAction = ODA_DRAWENTIRE | ODA_FOCUS | ODA_SELECT;
			param.itemData = 0;
			param.itemID = 0;
			if (GetFocus() == hWnd)
				param.itemState = ODS_FOCUS;
			else  param.itemState = 0;
			GetClientRect(hWnd, ¶m.rcItem);
			SendMessage(GetParent(hWnd), WM_DRAWITEM, (WPARAM)CtlID, (LPARAM)(LPDRAWITEMSTRUCT)¶m);
		}
		break;
	case WM_MOUSEHOVER:
		{
			UINT CtlID = GetWindowLong(hWnd, GWL_ID);
			static DRAWITEMSTRUCT param;
			param.CtlID = CtlID;
			param.CtlType = ODT_BUTTON;
			param.hDC = GetWindowDC(hWnd);
			param.hwndItem= hWnd;
			param.itemAction = ODA_DRAWENTIRE | ODA_FOCUS | ODA_SELECT;
			param.itemData = 0;
			param.itemID = 0;
			param.itemState = ODS_HOTLIGHT;
			if (GetFocus() == hWnd)
				param.itemState |= ODS_FOCUS;
			GetClientRect(hWnd, ¶m.rcItem);
			SendMessage(GetParent(hWnd), WM_DRAWITEM, (WPARAM)CtlID, (LPARAM)(LPDRAWITEMSTRUCT)¶m);
		}
		break;
	case WM_MOUSEMOVE:
		{
			tacMouseEv.cbSize = sizeof(TRACKMOUSEEVENT);
			tacMouseEv.dwFlags = TME_HOVER | TME_LEAVE;
			tacMouseEv.dwHoverTime = 10;
			tacMouseEv.hwndTrack = hWnd;
			_TrackMouseEvent((LPTRACKMOUSEEVENT)&tacMouseEv);
		}
		break;
	case WM_LBUTTONDBLCLK:
		PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lParam);
		break;
	}
	//将不做处理的消息路由给原默认函数
	return CallWindowProc((WNDPROC)btnDefProc, hWnd, uMsg, wParam, lParam);
}

void IconBtn::PrepareImageRect(HWND hBtnWnd, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, RECT* rpImage)
{
	RECT rBtn;

	CopyRect(rpImage, rpItem);


	GetClientRect(hBtnWnd, &rBtn);
	if (bHasTitle == FALSE)//如果按钮上有文本内容
	{
		// 使图片水平居中
		LONG rpImageWidth = rpImage->right - rpImage->left;
		rpImage->left += ((rpImageWidth - (long)dwWidth)/2);
	}
	else
	{   //控制图片与焦点方框内部
		LONG rpTitleWidth = rpTitle->right - rpTitle->left;
		rpTitle->right = rpTitleWidth - dwWidth - 30;
		rpTitle->left = 30;
		//rpImage->left = rBtn.right - dwWidth - 22;
		//假设图标为32*32像素
		unsigned short iconWidth =  ICON_SIZE;
		unsigned short iconHei =  ICON_SIZE;
		if (rBtn.right > iconWidth) rpImage->left = ((rBtn.right - iconWidth) >> 1);
		else rpImage->left = 0;
		if (rBtn.bottom > iconHei) rpImage->top = ((rBtn.bottom - iconHei) >> 1);
		else rpImage->top = 0;

		LONG rpImageHeight = rpImage->bottom - rpImage->top;
		//rpImage->top += ((rpImageHeight - (long)dwHeight)/2);
	}
	if (bIsPressed)//按钮被按下的处理
		OffsetRect(rpImage, 1, 1);

}

void IconBtn::DrawTheIcon(HWND hBtnWnd, HDC* dc, BOOL bIsDisabled, HICON hIcon)
{
	RECT    rImage;
	//PrepareImageRect(hBtnWnd, bHasTitle, rpItem, rpTitle, bIsPressed, 38, 38, &rImage);

	// 调用API函数按准备好的形式将图片画到按钮上
	GetClientRect(hBtnWnd, &rImage);
	DrawState(    *dc,
		NULL,
		NULL,
		(LPARAM)hIcon,
		0,
		rImage.left,
		rImage.top,
		(rImage.right - rImage.left),
		(rImage.bottom - rImage.top), 
		(bIsDisabled ? DSS_DISABLED : DSS_NORMAL) | DST_ICON);
}

bool IconBtn::CurCtrlIsBtn(UINT CtlID, HICON &normalIcon, HICON &hoverIcon, HICON &downIcon)
{//判断当前触发重画命令的控件是否是一个按钮, true:是按钮
	for (std::vector<BtnStruct >::iterator iter = m_btnDataVec.begin(); iter != m_btnDataVec.end(); ++iter)
		if ((*iter).m_btnID == CtlID)
		{
			normalIcon = (*iter).m_normalIcon;
			hoverIcon    = (*iter).m_hoverIcon;
			downIcon    = (*iter).m_downIcon;
			return true;
		}
		return false;
}

BOOL IconBtn::DrawMsg(HWND hDlg, LPARAM lParam)
{
	LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) lParam;
	//声明一个指向DRAWITEMSTRUCT结构体的指针并将其指向存储着按钮构造信息的lParam
	HICON normalIcon, hoverIcon, downIcon;
	if(!CurCtrlIsBtn(lpDIS->CtlID, normalIcon, hoverIcon, downIcon))
		return FALSE;

	HDC dc = lpDIS->hDC; //用于按钮绘制的DC
	BOOL bIsPressed  = (lpDIS->itemState & ODS_SELECTED);
	BOOL bIsFocused  = (lpDIS->itemState & ODS_FOCUS);
	BOOL bIsDisabled = (lpDIS->itemState & ODS_DISABLED);
	BOOL bIsHover      = (lpDIS->itemState & ODS_HOTLIGHT);
	const int ODS_NOFOCUSRECT = 0x020;
	BOOL bDrawFocusRect = !(lpDIS->itemState & ODS_NOFOCUSRECT);
	//判断按钮各种状态的BOOL值
	RECT itemRect = lpDIS->rcItem; //按钮的矩形区域

	//SetBkMode(dc, TRANSPARENT); //设置绘制按钮时的背景状态
	//if (bIsFocused)  //判断按钮是否获得了焦点并对其边框进行处理
	//{
	//	HBRUSH br = CreateSolidBrush(RGB(0,0,0));  
	//	//draw a border
	//	FrameRect(dc, &itemRect, br);
	//	//设置边框的厚度,一定要是负数
	//	InflateRect(&itemRect, -1, -1);
	//	DeleteObject(br);
	//} // if

	COLORREF crColor = GetSysColor(COLOR_WINDOW);//得到系统窗口颜色

	HBRUSH    brBackground = CreateSolidBrush(crColor);//创建画刷

	FillRect(dc, &itemRect, brBackground);//绘制按钮

	DeleteObject(brBackground);

	
	//TCHAR sTitle[100];
	//GetWindowText(GetDlgItem(hDlg, lpDIS->CtlID), sTitle, 100);//得到按钮的文本

	//RECT captionRect = lpDIS->rcItem;//把文本的区域设置为按钮区域


	//BOOL bHasTitle = (sTitle[0] !='/0');//按钮上是否有文本存在
	///


	if (bIsHover)
	{// 鼠标在按钮上空
		//UINT uState = DFCS_BUTTONPUSH |
		//	((bIsPressed) ? DFCS_PUSHED : 0);
		//draws a frame control of the specified type and style.
		//DrawFrameControl(dc, &itemRect, DFC_BUTTON, uState);
		DrawTheIcon(GetDlgItem(hDlg, lpDIS->CtlID), &dc, bIsDisabled, hoverIcon);
	}
	else if (bIsPressed)
	{// 这里画被按下去的按钮
		//HBRUSH brBtnShadow = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
		//FrameRect(dc, &itemRect, brBtnShadow);
		//DeleteObject(brBtnShadow);
		DrawTheIcon(GetDlgItem(hDlg, lpDIS->CtlID), &dc, bIsDisabled, downIcon);
	}

	else//如果没有被按下就这样画
	{
		//UINT uState = DFCS_BUTTONPUSH |
		//	((bIsPressed) ? DFCS_PUSHED : 0);
		//draws a frame control of the specified type and style.
		//DrawFrameControl(dc, &itemRect, DFC_BUTTON, uState);
		DrawTheIcon(GetDlgItem(hDlg, lpDIS->CtlID), &dc, bIsDisabled, normalIcon);
	}

	//if (bHasTitle)//如果按钮有文本标题
	//{
	//	// 按钮被按下的处理
	//	if (bIsPressed)
	//		OffsetRect(&captionRect, 1, 1);

	//	// 将文本居中
	//	HFONT hFont = (HFONT)SendMessage(GetDlgItem(hDlg, lpDIS->CtlID), WM_GETFONT, 0, 0);
	//	if (hFont == NULL)
	//	{//当前使用系统默认字体
	//		hFont = (HFONT)GetStockObject(SYSTEM_FONT);
	//	}
	//	LOGFONT lf;
	//	GetObject(hFont, sizeof(LOGFONT), &lf);
	//	size_t textLen = wcslen(sTitle);
	//	textLen *= lf.lfWidth;
	//	RECT centerRect = captionRect;
	//	DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CALCRECT|DT_CENTER);
	//	LONG captionRectWidth = captionRect.right - captionRect.left;
	//	LONG captionRectHeight = captionRect.bottom - captionRect.top;
	//	LONG centerRectWidth = centerRect.right - centerRect.left;
	//	LONG centerRectHeight = centerRect.bottom - centerRect.top;
	//	OffsetRect(&captionRect, (centerRectWidth - captionRectWidth)/2, (centerRectHeight - captionRectHeight)/2);

	//	SetBkMode(dc, TRANSPARENT);

	//	if (bIsDisabled)//如果按钮被禁用
	//	{
	//		OffsetRect(&captionRect, 1, 1);
	//		SetTextColor(dc, ::GetSysColor(COLOR_3DHILIGHT));
	//		DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
	//		OffsetRect(&captionRect, -1, -1);
	//		SetTextColor(dc, ::GetSysColor(COLOR_3DSHADOW));
	//		DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
	//	} 
	//	else //如果没被禁用正常画
	//	{
	//		SetTextColor(dc, ::GetSysColor(COLOR_BTNTEXT));
	//		SetBkColor(dc, ::GetSysColor(COLOR_BTNFACE));
	//		DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
	//	} 

	//}

	 画按钮得到焦点时的虚线方框
	//if (bIsFocused && bDrawFocusRect)
	//{
	//	RECT focusRect = itemRect;
	//	InflateRect(&focusRect, -3, -3);
	//	DrawFocusRect(dc, &focusRect);
	//} // if
	return (TRUE);
}

IconBtn::IconBtn(HWND hParentWnd)
{
	m_hParWnd = hParentWnd;
	m_btnDataVec.clear();
}

void IconBtn::AddBtn(UINT normalIconID, UINT hoverIconID, UINT downIconId, UINT btnID)
{
	RECT btnClient;
	GetClientRect(GetDlgItem(m_hParWnd, btnID), &btnClient);
	HICON normalIcon = (HICON)LoadImage(GetModuleHandle(NULL), 
		MAKEINTRESOURCE(normalIconID), 
		IMAGE_ICON, 
		 btnClient.right,
		 btnClient.bottom,
		0);

	HICON hoverIcon = (HICON)LoadImage(GetModuleHandle(NULL), 
		MAKEINTRESOURCE(hoverIconID), 
		IMAGE_ICON, 
		btnClient.right,
		btnClient.bottom,
		0);

	HICON downIcon = (HICON)LoadImage(GetModuleHandle(NULL), 
		MAKEINTRESOURCE(downIconId), 
		IMAGE_ICON, 
		btnClient.right,
		btnClient.bottom,
		0);
	m_btnDataVec.push_back(BtnStruct(normalIcon, hoverIcon, downIcon, btnID));
	btnDefProc = (LONG_PTR)SetWindowLongPtr(GetDlgItem(m_hParWnd, btnID), GWLP_WNDPROC, (LONG)(LONG_PTR)BtnProc);
}

#endif


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值