【自绘Button之一】带Icon的按钮控件

参考:
CButtonST的源码
Demo下载:
CIconBtn_Demo
Demo程序图片:
【自绘Button之一】带Icon的按钮控件_第1张图片
使用示例:
m_btn1.SetIcon(IDI_ICON_TEST);  //设置Icon
// 设置Icon与Text的对齐方式为:Icon在左Text在右
m_btn1.SetAlign(CIconBtn::IBTN_ICON_LEFT_TEXT_RIGHT);

m_btn2.SetIcon(IDI_ICON_TEST);
// 设置Icon与Text的对齐方式为:Icon在右Text在左
m_btn2.SetAlign(CIconBtn::IBTN_ICON_RIGHT_TEXT_LEFT);

m_btn3.SetIcon(IDI_ICON_TEST);
// 设置Icon与Text的对齐方式为:Icon在顶Text在底
m_btn3.SetAlign(CIconBtn::IBTN_ICON_TOP_TEXT_BOTTOM);

m_btn4.SetIcon(IDI_ICON_TEST);
// 设置Icon与Text的对齐方式为:Icon在底Text在顶
m_btn4.SetAlign(CIconBtn::IBTN_ICON_BOTTOM_TEXT_TOP);
    可以先查看之前的一篇博文:WM_DRAWITEM通告消息
    这篇文章比较详细的讲述了怎样绘制和标准PushButton一样的按钮。
CIconBtn类:
class CIconBtn : public CButton
{
	DECLARE_DYNAMIC(CIconBtn)

public:
	CIconBtn();
	virtual ~CIconBtn();
	virtual BOOL PreTranslateMessage(MSG* pMsg);
	virtual void PreSubclassWindow();
	virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);

	enum	
	{	
		IBTN_ICON_LEFT_TEXT_RIGHT = 0,  // Left:Icon   Right:Text	
		IBTN_ICON_RIGHT_TEXT_LEFT,      // Right:Icon  Left:Text	
		IBTN_ICON_TOP_TEXT_BOTTOM,      // Top:Icon    Bottom:Text	
		IBTN_ICON_BOTTOM_TEXT_TOP       // Bottom:Icon Top:Text	
	};

protected:
	void DrawBackground();
	void DrawBorder();
	void Draw3DBorderForRect(CDC *pDC, CRect *pRect);
	void DrawFocusRect();
	void DrawIcon();
	void DrawText();
	void PrepareDrawIconAndText();

public:
	BOOL SetIcon(int nIcon, int nCxDesired = 0, int nCyDesired = 0);
	BOOL SetAlign(BYTE byAlign);

private:
	BYTE  m_byAlign;            // text与icon的对齐方式
	CDC*  m_pDC;                // dc handle pointer
	CRect m_rcBtn;              // 按钮rect
	bool  m_bIsFocused;         // 按钮是否获得焦点
	bool  m_bIsPressed;         // 按钮是否被按下
	bool  m_bIsDisabled;        // 按钮是否Disable

	HICON m_hIcon;              // Icon handle
	int   m_nIconWidth;         // Icon width
	int   m_nIconHeight;        // Icon height

	int   m_nFocusRectOffset;	// 焦点矩形的偏移量
	int   m_nCxIconStart;       // Draw icon的起始点x坐标
	int   m_nCyIconStart;       // Draw icon的起始点y坐标
	RECT  m_rcText;             // Draw text的矩形区域

protected:
	DECLARE_MESSAGE_MAP()
};
一. override PreTranslateMessage
将鼠标双击消息解释为两次鼠标单击消息。
BOOL CIconBtn::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class
	if (pMsg->message == WM_LBUTTONDBLCLK)
		pMsg->message = WM_LBUTTONDOWN;

	return CButton::PreTranslateMessage(pMsg);
}
二. override PreSubclassWindow
将控件更改为Owner-Draw风格。
void CIconBtn::PreSubclassWindow()
{
	// TODO: Add your specialized code here and/or call the base class
	ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);

	CButton::PreSubclassWindow();
}
三. override DrawItem
void CIconBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// 获取DC及按钮大小
	m_pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	m_pDC->SetBkMode(TRANSPARENT);
	m_rcBtn = lpDrawItemStruct->rcItem;

	// 监测按钮状态
	m_bIsFocused  = lpDrawItemStruct->itemState & ODS_FOCUS;
	m_bIsPressed  = lpDrawItemStruct->itemState & ODS_SELECTED;
	m_bIsDisabled = lpDrawItemStruct->itemState & ODS_DISABLED;

	// Draw background
	this->DrawBackground();

	// Draw border
	this->DrawBorder();

	// Draw focus rect
	this->DrawFocusRect();

	// 计算Draw icon的位置及Draw text的矩形
	this->PrepareDrawIconAndText();

	// Draw icon
	if (m_hIcon)
		this->DrawIcon();

	// Draw text
	CString strText;
	GetWindowText(strText);
	if (!strText.IsEmpty())
		this->DrawText();
}

//
// Draw background
//
void CIconBtn::DrawBackground()
{
	CBrush brushBk(::GetSysColor(COLOR_BTNFACE));
	if (m_bIsFocused)
	{
		m_rcBtn.DeflateRect(1, 1);
		m_pDC->FillRect(&m_rcBtn, &brushBk);
		m_rcBtn.DeflateRect(-1, -1);

		CBrush brushFrame(RGB(0, 0, 0));
		m_pDC->FrameRect(&m_rcBtn, &brushFrame);
	}
	else
	{
		m_pDC->FillRect(&m_rcBtn, &brushBk);
	}
}

//
// Draw border
//
void CIconBtn::DrawBorder()
{
	if (m_bIsPressed)
	{
		m_rcBtn.DeflateRect(1, 1);
		CBrush brBtnShadow(::GetSysColor(COLOR_BTNSHADOW));
		m_pDC->FrameRect(&m_rcBtn, &brBtnShadow);
		m_rcBtn.DeflateRect(-1, -1);
	}
	else if (m_bIsFocused)
	{
		m_rcBtn.DeflateRect(1, 1);
		this->Draw3DBorderForRect(m_pDC, &m_rcBtn);
		m_rcBtn.DeflateRect(-1, -1);
	}
	else
	{
		this->Draw3DBorderForRect(m_pDC, &m_rcBtn);
	}
}

//
// 为pRect绘制3D边框
//
void CIconBtn::Draw3DBorderForRect(CDC *pDC, CRect *pRect)
{
	CPen penBtnHiLight(PS_SOLID, 0, GetSysColor(COLOR_BTNHILIGHT)); // White
	CPen pen3DLight(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT));       // Light gray
	CPen penBtnShadow(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));   // Dark gray
	CPen pen3DDKShadow(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); // Black
	// Draw top-left borders
	// White line
	CPen* pOldPen = pDC->SelectObject(&penBtnHiLight);
	pDC->MoveTo(pRect->left, pRect->bottom-1);
	pDC->LineTo(pRect->left, pRect->top);
	pDC->LineTo(pRect->right, pRect->top);
	// Light gray line
	pDC->SelectObject(pen3DLight);
	pDC->MoveTo(pRect->left+1, pRect->bottom-1);
	pDC->LineTo(pRect->left+1, pRect->top+1);
	pDC->LineTo(pRect->right, pRect->top+1);
	// Draw bottom-right borders
	// Black line
	pDC->SelectObject(pen3DDKShadow);
	pDC->MoveTo(pRect->left, pRect->bottom-1);
	pDC->LineTo(pRect->right-1, pRect->bottom-1);
	pDC->LineTo(pRect->right-1, pRect->top-1);
	// Dark gray line
	pDC->SelectObject(penBtnShadow);
	pDC->MoveTo(pRect->left+1, pRect->bottom-2);
	pDC->LineTo(pRect->right-2, pRect->bottom-2);
	pDC->LineTo(pRect->right-2, pRect->top);
	//
	pDC->SelectObject(pOldPen);
}

//
// 绘制焦点矩形
//
void CIconBtn::DrawFocusRect()
{
	if (m_bIsFocused)
	{
		m_rcBtn.DeflateRect(m_nFocusRectOffset, m_nFocusRectOffset);
		m_pDC->DrawFocusRect(&m_rcBtn);
		m_rcBtn.DeflateRect(-m_nFocusRectOffset, -m_nFocusRectOffset);
	}
}

//
// 计算绘制icon与text的位置
//
void CIconBtn::PrepareDrawIconAndText()
{
	// 判断有无text与icon
	bool bIsHasText = false;
	bool bIsHasIcon  = false;
	CString cstrCaption;
	this->GetWindowText(cstrCaption);
	bIsHasText = !cstrCaption.IsEmpty();
	if (m_hIcon)
		bIsHasIcon = true;

	// 计算绘制icon与text的位置
	if (bIsHasText && bIsHasIcon)	//既有text又有icon
	{
		switch (m_byAlign)
		{
		case IBTN_ICON_LEFT_TEXT_RIGHT:
			{
				m_nCxIconStart = m_rcBtn.left + m_nFocusRectOffset;
				m_nCyIconStart = m_rcBtn.top + (m_rcBtn.Height() - m_nIconHeight) / 2;

				m_rcText.left = m_rcBtn.left + m_nFocusRectOffset + m_nIconWidth;
				m_rcText.top = m_rcBtn.top + m_nFocusRectOffset;
				m_rcText.right = m_rcBtn.right - m_nFocusRectOffset;
				m_rcText.bottom = m_rcBtn.bottom - m_nFocusRectOffset;
			}
			break;

		case IBTN_ICON_RIGHT_TEXT_LEFT:
			{
				m_nCxIconStart = m_rcBtn.right - m_nFocusRectOffset - m_nIconWidth;
				m_nCyIconStart = m_rcBtn.top + (m_rcBtn.Height() - m_nIconHeight) / 2;
				
				m_rcText.left = m_rcBtn.left + m_nFocusRectOffset;
				m_rcText.top = m_rcBtn.top + m_nFocusRectOffset;
				m_rcText.right = m_rcBtn.right - m_nFocusRectOffset - m_nIconWidth;
				m_rcText.bottom = m_rcBtn.bottom - m_nFocusRectOffset;
			}
			break;

		case IBTN_ICON_TOP_TEXT_BOTTOM:
			{
				m_nCxIconStart = m_rcBtn.left + (m_rcBtn.Width() - m_nIconWidth) / 2;
				m_nCyIconStart = m_rcBtn.top + m_nFocusRectOffset;
				
				m_rcText.left = m_rcBtn.left + m_nFocusRectOffset;
				m_rcText.top = m_rcBtn.top + m_nFocusRectOffset + m_nIconHeight;
				m_rcText.right = m_rcBtn.right - m_nFocusRectOffset;
				m_rcText.bottom = m_rcBtn.bottom - m_nFocusRectOffset;
			}
			break;

		case IBTN_ICON_BOTTOM_TEXT_TOP:
			{
				m_nCxIconStart = m_rcBtn.left + (m_rcBtn.Width() - m_nIconWidth) / 2;
				m_nCyIconStart = m_rcBtn.bottom - m_nFocusRectOffset - m_nIconHeight;

				m_rcText.left = m_rcBtn.left + m_nFocusRectOffset;
				m_rcText.top = m_rcBtn.top + m_nFocusRectOffset;
				m_rcText.right = m_rcBtn.right - m_nFocusRectOffset;
				m_rcText.bottom = m_rcBtn.bottom - m_nFocusRectOffset - m_nIconHeight;
			}
			break;

		default:
			break;
		}

	}
	else if (!bIsHasText && bIsHasIcon)	//没有text只有icon
	{
		m_nCxIconStart = m_rcBtn.left + (m_rcBtn.Width() - m_nIconWidth) / 2;
		m_nCyIconStart = m_rcBtn.top + (m_rcBtn.Height() - m_nIconHeight) / 2;

		m_rcText.left = 0;
		m_rcText.top = 0;
		m_rcText.right = 0;
		m_rcText.bottom = 0;
	}
	else if (bIsHasText && !bIsHasIcon)  //只有text没有icon
	{
		m_nCxIconStart = 0;
		m_nCyIconStart = 0;

		m_rcText.left = m_rcBtn.left;
		m_rcText.top = m_rcBtn.top;
		m_rcText.right = m_rcBtn.right;
		m_rcText.bottom = m_rcBtn.bottom;
	}
	else
	{
		m_nCxIconStart = 0;
		m_nCyIconStart = 0;

		m_rcText.left = 0;
		m_rcText.top = 0;
		m_rcText.right = 0;
		m_rcText.bottom = 0;
	}
}

//
// 绘制ICON
//
void CIconBtn::DrawIcon()
{
	// 判断有无icon
	if (!m_hIcon)
		return;

	// 如果Disabled则灰掉
	// 如果Pressed则icon向右及向下各移1格
	UINT flag = DST_ICON | (m_bIsDisabled ? DSS_DISABLED : DSS_NORMAL);
	int nCxIconStart = m_bIsPressed ? m_nCxIconStart + 1 : m_nCxIconStart;
	int nCyIconStart = m_bIsPressed ? m_nCyIconStart + 1 : m_nCyIconStart;

	// Draw icon
	::DrawState(m_pDC->m_hDC, NULL, NULL, (LPARAM)m_hIcon, NULL,
		nCxIconStart, nCyIconStart, m_nIconWidth, m_nIconHeight, flag);
}

//
// 绘制Text
//
void CIconBtn::DrawText()
{
	// 判断有无text
	CString strText;
	GetWindowText(strText);
	if (strText.IsEmpty())
		return;

	// 如果按下则text向右及向下各移动一格
	if (m_bIsPressed)
	{
		m_rcText.left += 2;
	}
	else
	{
		m_rcText.bottom -= 2; // 使text真正垂直居中
	}

	// Draw text
	if (m_bIsDisabled)	//draw text并灰掉text
	{
		CRect rcText(&m_rcText);
		rcText.OffsetRect(1, 1);
		m_pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
		m_pDC->DrawText(strText, &rcText, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
		rcText.OffsetRect(-1, -1);
		m_pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW));
		m_pDC->DrawText(strText, &rcText, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
	}
	else  // draw text
	{
		m_pDC->DrawText(strText, &m_rcText, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
	}
}
四. 开放接口
//
// 设定Icon
//
BOOL CIconBtn::SetIcon(int nIcon, int nCxDesired, int nCyDesired)
{
	HICON hIcon = (HICON)::LoadImage(::GetModuleHandle(NULL), MAKEINTRESOURCE(nIcon), 
		IMAGE_ICON, nCxDesired, nCyDesired, 0);
	if (hIcon)
	{
		// 先释放先前的ICON
		::DestroyIcon(m_hIcon);
		//
		m_hIcon = hIcon;

		// Get icon size
		ICONINFO ici;  
		::GetIconInfo(m_hIcon, &ici);  
		BITMAP bm;  
		::GetObject(ici.hbmColor, sizeof(BITMAP), &bm);  
		m_nIconWidth = bm.bmWidth;  
		m_nIconHeight = bm.bmHeight; 

		::DeleteObject(ici.hbmColor);  
		::DeleteObject(ici.hbmMask);  

		return TRUE;
	}
	else
		return FALSE;
}

//
// 设定Icon与Text的对齐方式
//
BOOL CIconBtn::SetAlign(BYTE byAlign)
{
	switch (byAlign)
	{
	case IBTN_ICON_LEFT_TEXT_RIGHT:
	case IBTN_ICON_RIGHT_TEXT_LEFT:
	case IBTN_ICON_TOP_TEXT_BOTTOM:
	case IBTN_ICON_BOTTOM_TEXT_TOP:
		m_byAlign = byAlign;
	default:
		return FALSE;
	}

	return TRUE;
}

你可能感兴趣的:(【自绘Button之一】带Icon的按钮控件)