win32方式实现自绘按钮

/**
 * \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();
}


你可能感兴趣的:(win32方式实现自绘按钮)