/** * \file OwnerDrawButton.h * * \brief 自绘按钮的实现类 * * \author */ #pragma onceclass COwnerDrawButton{public: COwnerDrawButton(void); ~COwnerDrawButton(void);private: COwnerDrawButton(const COwnerDrawButton &OtherOwnerDrawButton); COwnerDrawButton &operator=(const COwnerDrawButton &OtherOwnerDrawButton);public: /** * \brief 刷新控件 */ bool InvalidataCtrl();public: /** * \brief 创建按钮 * \param lpszCaption 参数,为按钮的显示文本 * \param lpszImage 参数,为按钮的位图路径 * \param rect 参数,为按钮的坐标 * \param hParentWnd 参数,为按钮的父窗口句柄 * \param nID 参数,为按钮的控件ID * \param lpszImage 参数,为按钮控件一般状态位图路径 */ BOOL Create(LPCSTR lpszCaption, const RECT& rect, HWND hParentWnd,\ UINT nID, LPCSTR lpszImage); /** * \brief 绘制按钮 * \param hDC 参数,为按钮的绘制用DC句柄 */ void Draw(HDC hDC); void DrawFocusRect(HDC hDC,RECT &rcWnd); /** * \brief 设置按钮 * \param fEnable 参数,为设置按钮是否可用 */ void EnableButton(bool fEnable); void OnLbuttonDown(WPARAM wParam, LPARAM lParam); void OnLbuttonUp(WPARAM wParam, LPARAM lParam); void OnLbuttonDBClick(WPARAM wParam, LPARAM lParam); void OnMouseMove(WPARAM wParam, LPARAM lParam); void OnMouseLeave(WPARAM wParam, LPARAM lParam);private: /** * \brief 按钮消息回调函数 */ static LRESULT CALLBACK ButtonProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);public: enum STATE { STATE_UP, STATE_DOWN, STATE_FOCUS, STATE_DISABLE }; WNDPROC m_OldProc;//!按钮的默认消息回调函数 HWND m_hWnd; //!此按钮的句柄private: HBITMAP m_hFourStateBitmap; //!按钮的普通四状态位图 BOOL m_fRoundButton; //!当前控件类型,TRUE为按钮类型,FALSE为一般的显示位图控件 BOOL m_fTrackMouse; int m_nButtonState;//!按钮的当前状态 HFONT m_hFont;//!控件字体};
#include <Windows.h>#include "OwnerDrawButton.h"const int g_nCaptionLen = 50;COwnerDrawButton::COwnerDrawButton(void): m_hWnd(NULL), m_hFourStateBitmap(NULL), \m_fTrackMouse(FALSE){}COwnerDrawButton::~COwnerDrawButton(void){ if (m_hFourStateBitmap) { DeleteObject(m_hFourStateBitmap); } if (m_hFont) { DeleteObject(m_hFont); }}BOOL COwnerDrawButton::Create(LPCSTR lpszCaption, const RECT& rect, HWND hParentWnd,\ UINT nID, LPCSTR lpszImage){ if(m_hWnd) return FALSE; m_hFourStateBitmap = (HBITMAP)LoadImage(NULL, lpszImage, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); if( NULL == m_hFourStateBitmap) { goto CREATE_FAIL; } m_hWnd = CreateWindow("BUTTON", lpszCaption, \ WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_OWNERDRAW, \ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, \ hParentWnd,(HMENU)nID,NULL,NULL); if( NULL == m_hWnd) { goto CREATE_FAIL; } m_OldProc = (WNDPROC)SetWindowLong(m_hWnd, GWL_WNDPROC, (LONG)ButtonProc); SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this); m_hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET, \ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial" ); return TRUE;CREATE_FAIL: if (m_hFourStateBitmap) { DeleteObject(m_hFourStateBitmap); } return FALSE;}LRESULT CALLBACK COwnerDrawButton::ButtonProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ PAINTSTRUCT ps; HDC hdc; COwnerDrawButton *_this = (COwnerDrawButton *)GetWindowLong(hWnd, GWL_USERDATA); _this->m_hWnd = hWnd; switch (message) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... _this->Draw(hdc); EndPaint(hWnd, &ps); break; case WM_ERASEBKGND: return TRUE; case WM_DRAWITEM: { DRAWITEMSTRUCT *pDrawItemSturct = (DRAWITEMSTRUCT *)lParam; if(pDrawItemSturct->itemState & ODS_FOCUS) { RECT rtFocus = pDrawItemSturct->rcItem; rtFocus.left += 3; rtFocus.top += 3; rtFocus.right -= 3; rtFocus.bottom -= 3; _this->DrawFocusRect(pDrawItemSturct->hDC, rtFocus); } //_this->Draw(pDrawItemSturct->hDC); } break; case WM_LBUTTONDOWN: { _this->OnLbuttonDown(wParam, lParam); } break; case WM_LBUTTONUP: { _this->OnLbuttonUp(wParam, lParam); } break; case WM_LBUTTONDBLCLK: { _this->OnLbuttonDBClick(wParam, lParam); } break; case WM_MOUSEMOVE: { _this->OnMouseMove(wParam, lParam); } break; case WM_MOUSELEAVE: { _this->OnMouseLeave(wParam, lParam); } break; default: return CallWindowProc(_this->m_OldProc, hWnd, message, wParam, lParam); } return 0;}void COwnerDrawButton::OnLbuttonDown(WPARAM wParam, LPARAM lParam){ SetCapture(m_hWnd); m_nButtonState = STATE_DOWN; InvalidataCtrl();}void COwnerDrawButton::OnLbuttonUp(WPARAM wParam, LPARAM lParam){ if(m_nButtonState == STATE_DOWN) { ReleaseCapture(); POINT pt = {}; GetCursorPos(&pt); RECT rcWnd = {}; GetWindowRect(m_hWnd, &rcWnd); if(PtInRect(&rcWnd, pt)) { m_fTrackMouse = TRUE; m_nButtonState = STATE_FOCUS; SendMessage(GetParent(m_hWnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(m_hWnd), \ BN_CLICKED), (LPARAM)m_hWnd); } else { m_fTrackMouse = FALSE; m_nButtonState = STATE_UP; } InvalidataCtrl(); }}void COwnerDrawButton::OnLbuttonDBClick(WPARAM wParam, LPARAM lParam){ SendMessage(m_hWnd, WM_LBUTTONDOWN, NULL, NULL);}void COwnerDrawButton::OnMouseMove(WPARAM wParam, LPARAM lParam){ if(!m_fTrackMouse) { TRACKMOUSEEVENT MouseEvent = {sizeof(TRACKMOUSEEVENT)}; MouseEvent.dwFlags = TME_LEAVE; MouseEvent.hwndTrack = m_hWnd; MouseEvent.dwHoverTime = 1000; TrackMouseEvent(&MouseEvent); m_fTrackMouse = TRUE; m_nButtonState = STATE_FOCUS; InvalidataCtrl(); }}void COwnerDrawButton::OnMouseLeave(WPARAM wParam, LPARAM lParam){ m_fTrackMouse = FALSE; m_nButtonState = STATE_UP; InvalidataCtrl();}void COwnerDrawButton::Draw(HDC hDC){ HDC hMemDC = CreateCompatibleDC(hDC); HBITMAP hOldBmp = NULL; BITMAP bmpInfo = {}; hOldBmp= (HBITMAP)SelectObject(hMemDC, m_hFourStateBitmap); GetObject(m_hFourStateBitmap, sizeof(bmpInfo), &bmpInfo); RECT rcWnd = {}; GetClientRect(m_hWnd, &rcWnd); int nWidth = rcWnd.right - rcWnd.left; int nHeight = rcWnd.bottom - rcWnd.top; int nBmpWidth = bmpInfo.bmWidth / 4; int nBmpHeight = bmpInfo.bmHeight; //绘制背景图 SetStretchBltMode(hDC, HALFTONE); StretchBlt(hDC, 0, 0, nWidth, nHeight, hMemDC, nBmpWidth * m_nButtonState,\ 0, nBmpWidth, nBmpHeight, SRCCOPY); if(m_nButtonState == STATE_DOWN) { rcWnd.top += 2; } //绘制文本 char szCaption[g_nCaptionLen] = {}; GetWindowText(m_hWnd, szCaption, g_nCaptionLen - 1); if(strlen(szCaption) > 0) { SetBkMode(hDC, TRANSPARENT); char *pReturnPos = NULL; HFONT hOldFont = (HFONT)SelectObject(hDC, m_hFont); if(pReturnPos = strstr(szCaption, "\\r\\n")) { //pReturnPos[0] = '\r'; //pReturnPos[1] = '\n'; //strcpy(&pReturnPos[2], &pReturnPos[4]); char *pszSecondLine = pReturnPos + 4; rcWnd.bottom = (rcWnd.bottom + rcWnd.top) / 2; rcWnd.top += 1; DrawText(hDC, szCaption, pReturnPos - szCaption, &rcWnd, DT_CENTER); rcWnd.top -= 1; rcWnd.bottom = rcWnd.bottom * 2 - rcWnd.top; rcWnd.top = (rcWnd.bottom + rcWnd.top) / 2; rcWnd.top -= 1; DrawText(hDC, pszSecondLine, strlen(pszSecondLine), &rcWnd, DT_CENTER); } else { DrawText(hDC, szCaption, strlen(szCaption), &rcWnd, DT_CENTER|DT_VCENTER|DT_SINGLELINE); } SelectObject(hDC, hOldFont); } SelectObject(hMemDC, hOldBmp); DeleteDC(hMemDC);}void COwnerDrawButton::DrawFocusRect(HDC hDC,RECT &rcWnd){ HPEN hOldPen = NULL; HPEN hDrawPen = CreatePen(PS_DOT, 2, RGB(0,0,0)); HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); hOldPen = (HPEN)SelectObject(hDC, hDrawPen); Rectangle(hDC, rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom); SelectObject(hDC,hOldBrush); SelectObject(hDC,hOldPen); DeleteObject(hDrawPen);}bool COwnerDrawButton::InvalidataCtrl(){ //RECT rcWnd = {}; //GetClientRect(m_hWnd, &rcWnd); //InvalidateRect(m_hWnd, &rcWnd, bErase); HDC hDC = GetDC(m_hWnd); Draw(hDC); ReleaseDC(m_hWnd, hDC); return true;}void COwnerDrawButton::EnableButton(bool fEnable){ if(fEnable) { m_nButtonState = STATE_UP; } else { m_nButtonState = STATE_DISABLE; } EnableWindow(m_hWnd, fEnable); InvalidataCtrl();}