自繪式按鈕COwnerDrawBtn:可設定文字字型、文字顏色、按鈕背景圖片
阿新 • • 發佈:2019-02-13
使用MFC做介面的程式設計師,一定很痛苦,因為其預設效果比較古老呆板,實現好的UI效果往往需要費大力氣
但是花了精力去做,收穫比起只是拖拖介面設定引數的程式設計師,自然是更多的,最重要的收穫,就是靈活和自由,
到最後發現想要什麼效果,都可以去自定義實現
最近需要自繪按鈕,需求是:能設定背景圖、能設定字型、能改文字顏色,
上網找到的都不能完全滿足,最後參照著自己實現了一個,經驗證可用,貼程式碼:
//使用示例 COwnerDrawBtn m_btn; m_btn.MoveWindow(xGap,yGap,BTN_W,BTN_H); m_btn.SetBkSkin(_T("res\\Btn.bmp")); m_btn.SetTextFont(120, "宋體"); m_btn.SetTextColor(RGB(255,0,0));
OwnerDrawBtn.h
OwnerDrawBtn.cpp#ifndef _OWNERDRAW_BTN_H_ #define _OWNERDRAW_BTN_H_ #if _MSC_VER > 1000 #pragma once #endif class COwnerDrawBtn : public CButton { public: COwnerDrawBtn(); virtual ~COwnerDrawBtn(); private: enum{ BS_NORMAL=0, BS_HOVER, BS_PUSHDOWN, BS_DISABLE }; int m_nStatus; //按鈕狀態 BOOL m_bInRect; //滑鼠進入標誌 CString m_strText; //按鈕文字 COLORREF m_BackColor; //背景色 COLORREF m_TextColor; //文字顏色 CRect m_BtnRect; //按鈕尺寸 CFont m_font; //字型 HBITMAP m_hBkBmp; //背景圖片 public: void DrawButton(CDC *pDC); //畫按鈕 void DrawBkBmp(CDC *pDC); void DrawTxt(CDC *pDC); void SetText(CString str); void SetTextColor(COLORREF color); //設定文字顏色 void SetBkColor(COLORREF color); //設定背景顏色 void SetTextFont(int FontHight,LPCTSTR FontName); //設定字型 void SetTextFont(CFont* pFont); void SetBkSkin(HBITMAP hBkBmp); //設定按鈕底圖,傳(五態)圖片控制代碼 void SetBkSkin(LPCTSTR pBmpFile); //傳相對exe路徑 //{{AFX_VIRTUAL(COwnerDrawBtn) virtual void PreSubclassWindow(); virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); //}}AFX_VIRTUAL protected: //{{AFX_MSG(COwnerDrawBtn) afx_msg void OnMouseMove( UINT nFlags, CPoint point); afx_msg void OnLButtonDown( UINT nFlags, CPoint point ); afx_msg void OnLButtonUp( UINT nFlags, CPoint point ); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #endif
#include "stdafx.h" #include "OwnerDrawBtn.h" #pragma comment(lib,"msimg32.lib") #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif COwnerDrawBtn::COwnerDrawBtn() { m_nStatus = BS_NORMAL; m_bInRect = FALSE; m_strText = _T(""); m_TextColor = RGB(0,0,0); m_BackColor = RGB(243,243,243); m_hBkBmp = NULL; } COwnerDrawBtn::~COwnerDrawBtn() { } BEGIN_MESSAGE_MAP(COwnerDrawBtn, CButton) //{{AFX_MSG_MAP(COwnerDrawBtn) ON_WM_MOUSEMOVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() // PreSubclassWindow()在按鈕建立前自動執行,所以我們可以在其中做一些初始工作,此處為按鈕設定屬性“自繪” void COwnerDrawBtn::PreSubclassWindow() { ModifyStyle( 0, BS_OWNERDRAW ); //設定按鈕屬性為自繪 CButton::PreSubclassWindow(); } // DrawItem()函式是一個關鍵函式,按鈕的繪製工作就在這裡進行,它的作用相當於對話方塊中的OnPaint()函式和檢視中的OnDraw()函式 // 這裡做了三項工作:獲取按鈕尺寸、獲取按鈕文字、繪製按鈕。其中繪製工作在自定義函式DrawButton()中完成 void COwnerDrawBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { m_BtnRect = lpDrawItemStruct->rcItem; //獲取按鈕尺寸 if( m_strText.IsEmpty() ) GetWindowText( m_strText ); //獲取按鈕文字 CDC *pDC = CDC::FromHandle( lpDrawItemStruct->hDC ); int nSaveDC = pDC->SaveDC(); if (pDC) { DrawButton( pDC ); //繪製按鈕 pDC->RestoreDC( nSaveDC ); } } void COwnerDrawBtn::DrawButton(CDC *pDC) { if(BS_DISABLE == m_nStatus) m_nStatus = BS_NORMAL; //狀態 if( GetStyle() & WS_DISABLED ) m_nStatus = BS_DISABLE; DrawBkBmp(pDC); //繪製按鈕背景 DrawTxt(pDC); //繪製按鈕文字 } void COwnerDrawBtn::DrawBkBmp(CDC *pDC) { if (m_hBkBmp) { int nWidth=m_BtnRect.Width(); int nHeight=m_BtnRect.Height(); HDC hBkDC = CreateCompatibleDC(pDC->m_hDC); HBITMAP hOld = (HBITMAP)::SelectObject(hBkDC, m_hBkBmp); int bmpLeft = 0; if (BS_HOVER == m_nStatus) bmpLeft = nWidth*3; else if (BS_PUSHDOWN == m_nStatus) bmpLeft = nWidth; else if (BS_DISABLE == m_nStatus) bmpLeft = nWidth*2; TransparentBlt(pDC->m_hDC,0,0,nWidth,nHeight, hBkDC, bmpLeft,0,nWidth,nHeight, RGB(255,0,255)); ::SelectObject(hBkDC,hOld); ::DeleteDC(hBkDC); } else { COLORREF clrBorder; switch( m_nStatus ) { case BS_NORMAL: clrBorder = RGB(192,192,192); break; case BS_HOVER: clrBorder = RGB(255,255,255); break; case BS_PUSHDOWN: clrBorder = RGB(192,192,192); break; case BS_DISABLE: clrBorder = RGB(243,243,243); break; } CBrush Brush; Brush.CreateSolidBrush( m_BackColor ); //背景刷 pDC->SelectObject( &Brush ); CPen Pen; Pen.CreatePen(PS_SOLID, 1, clrBorder ); pDC->SelectObject( &Pen ); pDC->RoundRect(&m_BtnRect,CPoint(5,5)); //畫圓角矩形 if( m_nStatus!=BS_PUSHDOWN)//繪製按鈕按下時的邊框 { CRect Rect; Rect.SetRect( m_BtnRect.left+2, m_BtnRect.top+1, m_BtnRect.right, m_BtnRect.bottom ); pDC->DrawEdge( &Rect, BDR_RAISEDINNER, BF_RECT ); //畫邊框 } if( GetFocus()==this )//繪製擁有焦點按鈕的虛線框 { CRect Rect; Rect.SetRect( m_BtnRect.left+3, m_BtnRect.top+2, m_BtnRect.right-3, m_BtnRect.bottom-2 ); pDC->DrawFocusRect( &Rect ); } } } void COwnerDrawBtn::DrawTxt(CDC *pDC) { COLORREF txtColor; switch( m_nStatus ) { case BS_NORMAL: txtColor = m_TextColor; break; case BS_HOVER: txtColor = m_TextColor; break; case BS_PUSHDOWN: txtColor = m_TextColor; break; case BS_DISABLE: txtColor = GetSysColor(COLOR_GRAYTEXT); break; } pDC->SetTextColor( txtColor ); pDC->SetBkMode( TRANSPARENT ); pDC->DrawText( m_strText, &m_BtnRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS); } void COwnerDrawBtn::OnMouseMove(UINT nFlags, CPoint point) { if( !m_bInRect || GetCapture()!=this ) //滑鼠進入按鈕 { m_bInRect = TRUE; //設定進入標誌 SetCapture(); //捕獲滑鼠 m_nStatus = BS_HOVER; //設定按鈕狀態 Invalidate(); //重繪按鈕 } else { if (m_bInRect && !m_BtnRect.PtInRect(point)) //滑鼠離開按鈕 { m_bInRect = FALSE; //清除進入標誌 ReleaseCapture(); //釋放滑鼠 m_nStatus = BS_NORMAL; //設定按鈕狀態 Invalidate(); //重繪按鈕 } } CButton::OnMouseMove(nFlags, point); } void COwnerDrawBtn::OnLButtonDown(UINT nFlags, CPoint point) { m_nStatus = BS_PUSHDOWN; Invalidate(); //重繪按鈕 CButton::OnLButtonDown(nFlags, point); } void COwnerDrawBtn::OnLButtonUp(UINT nFlags, CPoint point) { m_nStatus = BS_HOVER; Invalidate(); //重繪按鈕 CButton::OnLButtonUp(nFlags, point); } void COwnerDrawBtn::SetText(CString str) { m_strText = _T(""); SetWindowText(str); } void COwnerDrawBtn::SetTextColor(COLORREF color) { m_TextColor = color; Invalidate(); } void COwnerDrawBtn::SetBkColor(COLORREF color) { m_BackColor = color; Invalidate(); } void COwnerDrawBtn::SetTextFont(int FontHight,LPCTSTR FontName) { m_font.DeleteObject(); m_font.CreatePointFont(FontHight, FontName); SetFont(&m_font); } void COwnerDrawBtn::SetTextFont(CFont* pFont) { SetFont(pFont); } void COwnerDrawBtn::SetBkSkin(HBITMAP hBkBmp) { if (!m_hBkBmp) { m_hBkBmp = hBkBmp; } } void COwnerDrawBtn::SetBkSkin(LPCTSTR pBmpFile) { if (!m_hBkBmp) { m_hBkBmp = (HBITMAP)LoadImage(AfxGetInstanceHandle(), pBmpFile, IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION); } }