/** * \file OwnerDrawButton.h * * \brief 自绘按钮的实现类 * * \author */ #pragma once class 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(); }