继承CWnd自绘按钮

头文件:

复制代码
//头文件

#pragma once

// CLhsButton

#define MYWM_BTN_CLICK WM_USER+3001        //关闭按钮单击响应

//tab按钮的状态
enum ButtonState
{
    BTN_STATE_NOR            = 0,
    BTN_STATE_DOWN            = 1,
};

class CLhsButton : public CWnd
{
    DECLARE_DYNAMIC(CLhsButton)

public:
    CLhsButton();
    virtual ~CLhsButton();

     bool Create(CWnd* pParent,CRect rc,CString text,DWORD id = 0,DWORD style = WS_VISIBLE|WS_CHILD);  

    DECLARE_MESSAGE_MAP()

public:
    
protected:
    CString szClassName;  
    bool m_isMouseHover;        //鼠标是否悬浮
    bool m_isMouseClicked;        //鼠标是否单击
    CString m_strShowText;        //要显示的文字

    Image*                        m_pImgNor;            //正常时的图片
    Image*                        m_pImgHot;            //鼠标悬浮时的图片
    Image*                        m_pImgDown;            //单击按下时的图片
    
    void PostClickEvent();
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);  
    afx_msg void OnMouseHover(UINT nFlags, CPoint point);  
    afx_msg void OnMouseLeave();  
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);  
    afx_msg void OnPaint();  
    afx_msg void OnSize(UINT nType, int cx, int cy);    
    virtual BOOL PreTranslateMessage(MSG* pMsg);
public:
    void SetTabState(ButtonState state){m_btnState = state; Invalidate();}    //设置tab状态
    ButtonState GetTabState(){return m_btnState;}
    void SetToolTipText(CString spText, BOOL bActivate = TRUE);
    void LoadBtnImg(LPCTSTR tType, UINT nNorID, UINT nHotID, UINT nDownID);        //加载按钮图片

private:
    ButtonState m_btnState;                            //tab的状态    
    CToolTipCtrl*    m_pToolTip;
    CString m_tooltext;

public:
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
};

//源文件
// CLhsButton.cpp : 实现文件
//

#include "stdafx.h"
#include "../Lander_mini.h"
#include "memdc.h"
#include "../Utility.h"
#include "LhsButton.h"
// CLhsButton

IMPLEMENT_DYNAMIC(CLhsButton, CWnd)

CLhsButton::CLhsButton()
{
    m_isMouseHover = false;  
    m_isMouseClicked = false;  
    // 注册控件类  
    szClassName = AfxRegisterWndClass(0); 
    m_pImgNor = NULL;
    m_pImgHot = NULL;
    m_pImgDown = NULL;
    m_btnState = BTN_STATE_NOR;
    m_pToolTip = NULL;    
}

CLhsButton::~CLhsButton()
{
    SAFE_RELEASE(m_pToolTip);
    SAFE_RELEASE(m_pImgNor);
    SAFE_RELEASE(m_pImgHot);
    SAFE_RELEASE(m_pImgDown);
}


BEGIN_MESSAGE_MAP(CLhsButton, CWnd)
    ON_WM_MOUSEMOVE()  
    ON_WM_MOUSEHOVER()  // 此消息系统并不会给我们发送  
    ON_WM_MOUSELEAVE()  
    ON_WM_LBUTTONDOWN()  
    ON_WM_LBUTTONUP()  
    ON_WM_PAINT()  
    ON_WM_SIZE()
    ON_WM_ERASEBKGND()  
    ON_WM_CREATE()    
    ON_WM_CTLCOLOR()
END_MESSAGE_MAP()

// CLhsButton 消息处理程序
bool CLhsButton::Create(CWnd* pParent,CRect rc,CString text,DWORD id /* = 0 */,DWORD style /* = WS_VISIBLE|WS_CHILD */)  
{  
    // 动态创建控件      
    BOOL ret = CWnd::CreateEx(0, szClassName, text, style, rc, pParent, id);
    return ret ? true : false;  
}  

int CLhsButton::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    
    //::SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) ^ WS_EX_LAYERED);
    
    //ModifyStyle(WS_CLIPCHILDREN, 0);
    //ModifyStyle(0, WS_CLIPCHILDREN , 0);

    return 0;
}

void CLhsButton::PostClickEvent()  
{  
    // 该函数用来向父窗口发送 单击 消息  
    CWnd* parent = GetParent();  
    if(parent)  
        parent->SendMessage(MYWM_BTN_CLICK, 0,0);      
}  

void CLhsButton::OnMouseHover(UINT nFlags, CPoint point)  
{  
    // 鼠标进入  
    Invalidate();  
}  

void CLhsButton::OnMouseMove(UINT nFlags, CPoint point)
{
    // 只处理鼠标第一次进入时的情况  
    if(!m_isMouseHover)  
    {  
        m_isMouseHover = true;  

        TRACKMOUSEEVENT evt = { sizeof(evt), TME_LEAVE|TME_HOVER, m_hWnd, 0 };  
        TrackMouseEvent(&evt);  

        OnMouseHover(0,CPoint());  
    }  
}

void CLhsButton::OnMouseLeave()  
{  
    // 鼠标离开  
    m_isMouseHover = false;  
    m_isMouseClicked = false;  
    Invalidate();  
}  

void CLhsButton::OnLButtonDown(UINT nFlags, CPoint point)  
{  
    // 鼠标按下  
    m_isMouseClicked = true;  
    Invalidate();  
}  

void CLhsButton::OnLButtonUp(UINT nFlags, CPoint point)  
{  
    // 鼠标松开  
    if(m_isMouseClicked)  
    {  
        m_isMouseClicked = false;  
        Invalidate(); 
        PostClickEvent();  
    }  
}  

BOOL CLhsButton::OnEraseBkgnd(CDC* pDC)  
{  
//    return CWnd::OnEraseBkgnd(pDC);
    return TRUE;    // 阻止擦除背景,防止闪烁  
}  

void CLhsButton::OnPaint()  
{  
    CPaintDC dc(this);   
    CRect rc;  
    GetClientRect(&rc); 
    
    // 采用双缓存,防止闪烁  
    CMemDC memdc(&dc,&rc,TRUE);
    Graphics graphic(memdc);
    if (!m_pImgNor || !m_pImgHot || !m_pImgDown)
    {//没有提供按钮图片就刷下背景
        // 刷背景  
        COLORREF bkgnd = RGB(100,0,0);  
        if(m_isMouseHover)  
        {  
            if(m_isMouseClicked)  
                bkgnd = RGB(250,0,0);  
            else  
                bkgnd = RGB(180,0,0);  
        }  
        memdc.FillSolidRect(&rc,bkgnd);  
    }
    
    if (m_isMouseClicked || m_btnState == BTN_STATE_DOWN)
    {//单击一定画单击状态
        graphic.DrawImage(m_pImgDown, 0, 0, m_pImgDown->GetWidth(), m_pImgDown->GetHeight());
    }
    else if (m_isMouseHover && !m_isMouseClicked)
    {
        //悬浮,但是没单击
        graphic.DrawImage(m_pImgHot, 0, 0, m_pImgHot->GetWidth(), m_pImgHot->GetHeight());        
    }
    else
    {
        graphic.DrawImage(m_pImgNor, 0, 0, m_pImgNor->GetWidth(), m_pImgNor->GetHeight());    
    }
    
    // 使绘制生效  
    graphic.ReleaseHDC(memdc);                
}  


BOOL CLhsButton::PreTranslateMessage(MSG* pMsg) 
{
    if (m_pToolTip)
    {
        if (::IsWindow(m_pToolTip->m_hWnd))
        {
            m_pToolTip->RelayEvent(pMsg);        
        }
    }

    return CWnd::PreTranslateMessage(pMsg);
}


void CLhsButton::OnSize(UINT nType, int cx, int cy) 
{

}

void CLhsButton::SetToolTipText(CString spText, BOOL bActivate)
{
    if (m_pToolTip == NULL)
    {
        m_pToolTip = new CToolTipCtrl;
        // Create ToolTip control
        m_pToolTip->Create(this);
        m_pToolTip->Activate(TRUE);
    }

    m_tooltext = spText;

    // If there is no tooltip defined then add it
    if (m_pToolTip->GetToolCount() == 0)
    {
        CRect rectBtn; 
        GetClientRect(rectBtn);
        m_pToolTip->AddTool(this, m_tooltext, rectBtn, 1);
    }

    // Set text for tooltip
    m_pToolTip->UpdateTipText(m_tooltext, this, 1);
    m_pToolTip->SetDelayTime(2000);
    m_pToolTip->Activate(bActivate);
}


HBRUSH CLhsButton::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CWnd::OnCtlColor(pDC, pWnd, nCtlColor);

    // TODO:  在此更改 DC 的任何属性

    // TODO:  如果默认的不是所需画笔,则返回另一个画笔
    return hbr;
}

//加载按钮图片
void CLhsButton::LoadBtnImg(LPCTSTR tType, UINT nNorID, UINT nHotID, UINT nDownID)
{
    m_pImgNor = CQYUtility::LoadImgFromRes(_T("PNG"), nNorID);
    m_pImgHot = CQYUtility::LoadImgFromRes(_T("PNG"), nHotID);
    m_pImgDown = CQYUtility::LoadImgFromRes(_T("PNG"), nDownID);    
}


复制代码

内存DC

复制代码
<pre name="code" class="cpp">#ifndef _MEMDC_H_
#define _MEMDC_H_

//////////////////////////////////////////////////
// CMemDC - memory DC
//
class CMemDC : public CDC {
private:    
    CBitmap        m_bitmap;        // Offscreen bitmap
    CBitmap*    m_oldBitmap;    // bitmap originally found in CMemDC
    CDC*        m_pDC;            // Saves CDC passed in constructor
    CRect        m_rect;            // Rectangle of drawing area.
    BOOL        m_bMemDC;        // TRUE if CDC really is a Memory DC.
public:
       void Build( CDC* pDC )
   {
        ASSERT(pDC != NULL); 

        m_pDC        = pDC;
        m_oldBitmap = NULL;
        m_bMemDC    = !pDC->IsPrinting();

        if( m_bMemDC )
        {
            CreateCompatibleDC(pDC);
            pDC->LPtoDP(&m_rect);

            m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
            m_oldBitmap = SelectObject(&m_bitmap);
            
            SetMapMode(pDC->GetMapMode());
            pDC->DPtoLP(&m_rect);
            SetWindowOrg(m_rect.left, m_rect.top);
        }
        else
        {
            m_bPrinting = pDC->m_bPrinting;
            m_hDC       = pDC->m_hDC;
            m_hAttribDC = pDC->m_hAttribDC;
        }

        FillSolidRect( m_rect, pDC->GetBkColor() );
    }
    
    CMemDC(CDC* pDC, const CRect* pRect = NULL, BOOL bBg = FALSE) : CDC()
    {
        ASSERT(pDC != NULL); 

        // Some initialization
        m_pDC = pDC;
        m_oldBitmap = NULL;
        m_bMemDC = !pDC->IsPrinting();

        // Get the rectangle to draw
        if (pRect == NULL) {
            pDC->GetClipBox(&m_rect);
        } else {
            m_rect = *pRect;
        }

        if (m_bMemDC) {
            // Create a Memory DC
            CreateCompatibleDC(pDC);
            pDC->LPtoDP(&m_rect);

            m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
            m_oldBitmap = SelectObject(&m_bitmap);

            SetMapMode(pDC->GetMapMode());

            SetWindowExt(pDC->GetWindowExt());
            SetViewportExt(pDC->GetViewportExt());

            pDC->DPtoLP(&m_rect);
            SetWindowOrg(m_rect.left, m_rect.top);
        } else {
            // Make a copy of the relevent parts of the current DC for printing
            m_bPrinting = pDC->m_bPrinting;
            m_hDC       = pDC->m_hDC;
            m_hAttribDC = pDC->m_hAttribDC;
        }

        // Fill background 
        if( bBg )
            BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
                m_pDC, m_rect.left, m_rect.top, SRCCOPY);
        else
            FillSolidRect(m_rect, pDC->GetBkColor());
    }
    
    ~CMemDC()    
    {        
        if (m_bMemDC) {
            // Copy the offscreen bitmap onto the screen.
            m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
                this, m_rect.left, m_rect.top, SRCCOPY);            
            
            //Swap back the original bitmap.
            SelectObject(m_oldBitmap);        
        } else {
            // All we need to do is replace the DC with an illegal value,
            // this keeps us from accidently deleting the handles associated with
            // the CDC that was passed to the constructor.            
            m_hDC = m_hAttribDC = NULL;
        }    
    }
    
    // Allow usage as a pointer    
    CMemDC* operator->() 
    {
        return this;
    }    

    // Allow usage as a pointer    
    operator CMemDC*() 
    {
        return this;
    }
       CMemDC( HDC hDC )
       : CDC()
   {
       CDC::FromHandle( hDC )->GetClipBox( &m_rect );
       Build( CDC::FromHandle( hDC ) );
   }

};

#endif
复制代码

调用方法:

//使用例子
RECT rc = {0, 0, 20, 20};
    m_btnClose.LoadBtnImg(_T("PNG"),IDB_PNG_TAB_CLOSE_NOR, IDB_PNG_TAB_CLOSE_HOT,IDB_PNG_TAB_CLOSE_HOT);
    m_btnClose.Create(this, rc, L"",ID_BTN_MYTAB_CLOSE);        
    m_btnClose.SetToolTipText(_T("关闭"));         

源文地址:http://blog.csdn.net/huasonl88/article/details/43226011

原文地址:https://www.cnblogs.com/findumars/p/5624863.html