参考:
CButtonST的源码
Demo下载:
CIconBtn_Demo
Demo程序图片:
使用示例:
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;
}