参考: 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 DrawItemvoid 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; }