MFC 之 重绘按键Cbutton

上次我们学习了如何美化对话框的界面,这次我们为上次的对话框添加两个按钮,一个是关闭按钮,另一个是最小化按钮,好,现在我们先看一下效果:

是不是很难看,因为我们的对话框美化了,所以我们的按钮也要美化,因为采用贴图的方式来美化,所以,我先给出这两个按钮的PNG格式的图片,该图片支持透明色,具体如下:

关闭按钮效果图:

最小化按钮效果图:

这两张效果图是我自己从网上找的,可能不是很合适,但是用来教学,完全没有问题,它们的尺寸都是108*21,每张图片都有四个小图片,第一张和第四张小图片都是透明的,所以看不见效果,我们使用这两张图片来完成按钮的美化,每张图片从左向右有四张小图片,我们只用前三张,分别对应默认状态,焦点状态,按下状态。

下面,我们来说一下如何美化按钮?

第1步,我们先在对话框上放置两个按钮,一个是关闭按钮,另一个是最小化按钮,它们对应的ID分别是IDC_BUTTON_CLOSE和IDC_BUTTON_MIN,然后将我们的按钮设置为自绘制模式,方法如下:

选择按钮,右键属性,在属性列表中找到Owner Draw选项,将其设置为True,效果图如下:

再为它们添加两个成员变量,具体如下:

CButton m_btnClose;
CButton m_btnMin;
第2步,我们新建一个类,继承自CButton,我们取名为CMyButton,为其添加3个成员变量,分别如下:
//按钮背景图像
CImage m_imgButton;
//按钮png路径,包括焦点,正常,按下3个状态
CString m_strImgPath;
//父窗口背景图片背景路径,透明png需要使用
CString m_strImgParentPath;
第3步,我们为CMyButton添加3个成员函数,分别如下:
//设置按钮背景图片路径,父窗口背景图片路径
void SetImagePath(CString strImgPath, CString strParentImgPath);
//初始化按钮,主要是调整按钮的位置,处理透明色
bool InitMyButton(int nX/*左上角X坐标*/, int nY/*左上角Y坐标*/,int nW/*图像宽*/, int nH/*图像高*/, bool bIsPng/*是否是PNG图片*/);
//自绘制函数
void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
CMyButton的声明最终如下:
class CMyButton : public CButton
{
    DECLARE_DYNAMIC(CMyButton)
 
public:
    CMyButton();
 
    virtual ~CMyButton();
    
    //按钮背景图像
    CImage m_imgButton;
 
    //按钮png路径,包括焦点,正常,按下3个状态
    CString m_strImgPath;
 
    //父窗口背景图片背景路径,透明png需要使用
    CString m_strImgParentPath;
 
    //设置按钮背景图片路径,父窗口背景图片路径
    void SetImagePath(CString strImgPath, CString strParentImgPath);
 
    //初始化按钮,主要是调整按钮的位置,处理透明色
    bool InitMyButton(int nX/*左上角X坐标*/, int nY/*左上角Y坐标*/,int nW/*图像宽*/, int nH/*图像高*/, bool bIsPng/*是否是PNG图片*/);
 
    //自绘制函数
    void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
 
protected:
    DECLARE_MESSAGE_MAP()
};
第4步,我们实现SetImagePath函数,它的功能是为按钮背景图片和父窗口背景图片成员函数初始化,具体如下:
void CMyButton::SetImagePath(CString strImgPath, CString strParentImgPath)
{
    m_strImgPath = strImgPath;
    m_strImgParentPath = strParentImgPath;
}
第5步,我们实现InitMyButton函数,它的功能是调整按钮在对话框上的位置,其中的参数代表该按钮在父窗口的左上角X坐标,Y坐标,宽度,高度,最后一个参数是为PNG格式图片准备的,如果是PNG带透明色的图片,需要对它进行特殊处理,具体定义如下:
bool CMyButton::InitMyButton(int nX, int nY, int nW, int nH, bool bIsPng)
{
    HRESULT hr = 0;
    if (m_strImgPath.IsEmpty())
        return false;
    hr = m_imgButton.Load(m_strImgPath);
 
    if (FAILED(hr))
        return false;
 
    if (bIsPng)
    {
        if (m_imgButton.GetBPP() == 32)
        {
            int i = 0;
            int j = 0;
            for (i = 0; i < m_imgButton.GetWidth(); i++)
            {
                for (j = 0; j < m_imgButton.GetHeight(); j++)
                {
                    byte * pbyte = (byte *)m_imgButton.GetPixelAddress(i, j);
                    pbyte[0] = pbyte[0] * pbyte[3] / 255;
                    pbyte[1] = pbyte[1] * pbyte[3] / 255;
                    pbyte[2] = pbyte[2] * pbyte[3] / 255;
                }
            }
        }
    }
 
    MoveWindow(nX,nY,nW,nH);
 
    return true;
}
其中MoveWindow函数是用来调整按钮位置的函数,其中的参数分别代表其在父窗口的左上角X坐标,左上角Y坐标,宽度,高度。
第6步,我们实现DrawItem函数,它是美化Button的核心函数,当我们将Button设置为自绘制后,每次按钮需要刷新,重新绘制的时候,MFC框架会调用它的DrawItem函数,在这个函数中,我们可以根据按钮当前的状态为其贴上相应的背景图。当我们按钮按钮的时候,为其贴上被按下的背景图;当我们的按钮获取焦点的时候,为其贴上获取焦点的背景图;当我们的按钮没有焦点,我们为其贴上默认的背景图片,它们对应的位置前面已经说过。为了避免闪烁,我们采用双缓冲的方式,具体代码如下:

void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    if (!lpDrawItemStruct)
        return;
    HDC hMemDC;
    HBITMAP bmpMem;
    HGDIOBJ hOldObj;
    bmpMem = CreateCompatibleBitmap(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top);
    if (!bmpMem)
        return;
    hMemDC = CreateCompatibleDC(lpDrawItemStruct->hDC);
    if (!hMemDC)
    {
        if (bmpMem)
        {
            ::DeleteObject(bmpMem);
            bmpMem = NULL;
        }
        return;
    }
 
    hOldObj = ::SelectObject(hMemDC, bmpMem);
 
    RECT rectTmp = { 0 };
 
    rectTmp = lpDrawItemStruct->rcItem;
 
    MapWindowPoints(GetParent(), &rectTmp);
 
    int nW = lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left;
 
    int nH = lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top;
 
    if (lpDrawItemStruct->itemState & ODS_SELECTED)
    {
        //按钮被选择
        m_imgButton.BitBlt(hMemDC, 0, 0, nW, nH, nW*2, 0, SRCCOPY);
    }
    else if (lpDrawItemStruct->itemState & ODS_FOCUS)
    {
               //焦点状态
              m_imgButton.BitBlt(hMemDC, 0, 0, nW, nH, nW, 0, SRCCOPY);        
    }
    else
    {
        //默认状态
        CImage imgParent;
 
        imgParent.Load(m_strImgParentPath);
 
        imgParent.Draw(hMemDC, 0, 0, nW, nH, rectTmp.left, rectTmp.top, nW, nH);
 
        m_imgButton.AlphaBlend(hMemDC, 0, 0, nW, nH, 0, 0, nW, nH);
 
        imgParent.Destroy();
        
    }
 
    ::BitBlt(lpDrawItemStruct->hDC, 0, 0, nW, nH, hMemDC, 0, 0, SRCCOPY);
 
    SelectObject(hMemDC, hOldObj);
 
    if (bmpMem)
    {
        ::DeleteObject(bmpMem);
        bmpMem = NULL;
    }
 
    if (hMemDC)
    {
        ::DeleteDC(hMemDC);
        hMemDC = NULL;
    }
    return;
}
这里我们重点说一下默认状态的背景图,因为它是透明的,并且我们采用的是双缓冲,所以,为了避免最终透明色变成黑色,我们先在内存DC上贴上按钮在父窗口位置的背景图,这样可以解决透明色变成黑色的问题,如果你采用GDI+,就不用这么做,但是我们采用的是GDI。
第7步,用CMyButton替代对话框头文件中的CButton。

第8步,在对话框的InitDialog中,对两个按钮进行初始化,具体如下:

m_btnMin.SetImagePath(_T("./res/btn_min.png"), _T("./res/Background.png"));
m_btnMin.InitMyButton(516, 8, 27, 21, true);
m_btnClose.SetImagePath(_T("./res/btn_close.png"),_T("./res/Background.png"));
m_btnClose.InitMyButton(545,8,27,21,true);

第9步,编译程序,最终效果图如下:


今天,我们已经为它添加了最小化,关闭按钮,下次,我们为其添加编辑框!

原文:https://blog.csdn.net/yu__jia/article/details/83090442 
 

 

最近在为公司用MFC做产品界面。因为是小公司,所以也没有现成的界面库,必须自己一点一点写。自己在网上收集了点资料,就写了几个类型的button类,以供以后使用。

目前为止,做了三种类型的按钮,分别是:

1.一般情况使用的,比较常用的button类CNormalBtn;

2.特殊一点的,类似拥有菜单功能的button类CMenuBtn(和CNormal的区别是按钮selected后的状态不会随着鼠标的离开而消失);

3.静态按钮,用来呈现log等图片之类的button类CStatic,该类不会响应鼠标事件。

对于1,2种按钮,用的图片模式是:(png格式,一幅图里有四副小图,依次表示NoFoucs,Mousemove, buttondown, Disable四种状态);

对于3类按钮,用的图片模式是:(png格式)

下面贴代码:

基类代码(BaseBtn.h)

#ifndef __BASEBTN_H__
#define __BASEBTN_H__
 
#include "stdafx.h"
#include
 
#if _MSC_VER > 1000
#pragma once
#endif
 
class CBaseBtn : public CButton
{
public:
    CBaseBtn();
    ~CBaseBtn();
 
public:
    virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    virtual void SetFont(CFont* pFont, BOOL bRedraw = TRUE);
    virtual void SetWindowText(LPCTSTR lpszString);
    
public:
    void Init(UINT uImageID);
    void SetBtnTextColor(COLORREF clr);
        
protected:
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
 
    DECLARE_MESSAGE_MAP()
 
protected:
    int            m_nCtrlState;
 
    CImage        m_Image;
    int            m_nSrcWidth;
    int            m_nSrcHeight;
 
private:
    CString        m_strBtnText;
    CFont*        m_pFont;
    COLORREF    m_clr;
};
 
#endif


基类代码(BaseBtn.cpp)

#include "stdafx.h"
#include "BaseBtn.h"
#include "Public.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 
CBaseBtn::CBaseBtn()
{
    m_pFont = new CFont;
    VERIFY(m_pFont->CreateFont(15, 0, 0, 0, FW_BOLD, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, 
        CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Tahoma")));
 
    m_strBtnText = L"";
    m_clr = RGB(0, 0, 0);
}
 
CBaseBtn::~CBaseBtn()
{
    if (!m_Image.IsNull())
        m_Image.Destroy();
 
    if (m_pFont != NULL)
    {
        m_pFont->DeleteObject();
 
        delete m_pFont;
        m_pFont = NULL;
    }
}
 
BEGIN_MESSAGE_MAP(CBaseBtn, CButton)
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
 
void CBaseBtn::Init(UINT uImageID)
{
    SetButtonStyle(BS_OWNERDRAW);
 
    LoadPicture(m_Image, uImageID);
    m_nSrcWidth = m_Image.GetWidth();
    m_nSrcHeight = m_Image.GetHeight();
 
    SetWindowPos(NULL, 0, 0, m_nSrcWidth/4, m_nSrcHeight, SWP_NOMOVE|SWP_NOACTIVATE);
 
    if (IsWindowEnabled())
        m_nCtrlState = CTRL_NOFOCUS;
    else
        m_nCtrlState = CTRL_DISABLE;
}
 
void CBaseBtn::SetFont(CFont* pFont, BOOL bRedraw)
{
    m_pFont = pFont;
 
    if(bRedraw)
        Invalidate();
}
 
void CBaseBtn::SetWindowText(LPCTSTR lpszString)
{
    m_strBtnText = lpszString;
    Invalidate();
}
 
void CBaseBtn::SetBtnTextColor(COLORREF clr)
{
    m_clr = clr;
    Invalidate();
}
 
BOOL CBaseBtn::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
    return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}
 
void CBaseBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    if (m_Image.IsNull())
        return ;
 
    CRect buttonRect;
    GetClientRect(buttonRect);
 
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);        //按钮控件DC
 
    CDC dcMem;
    dcMem.CreateCompatibleDC(pDC);
 
    CBitmap memBitmap;
    memBitmap.CreateCompatibleBitmap(pDC, buttonRect.Width(), buttonRect.Height());
    dcMem.SelectObject(memBitmap);
 
    dcMem.FillSolidRect(buttonRect, RGB(255,0,255));    //设置画布颜色
 
    CRect rcSrc = CRect(0,0,0,0);
    switch(m_nCtrlState)
    {
    case CTRL_NOFOCUS:
        {
            rcSrc = CRect(0, 0, m_nSrcWidth/4, m_nSrcHeight);        
        }
        break;
 
    case CTRL_FOCUS:
        {
            rcSrc = CRect(m_nSrcWidth/4, 0, m_nSrcWidth/4 * 2, m_nSrcHeight);
        }
        break;
    case CTRL_SELECTED:
        {
            rcSrc = CRect(m_nSrcWidth/4 * 2, 0, m_nSrcWidth/4 * 3, m_nSrcHeight);
        }
        break;
 
    case CTRL_DISABLE:
        {
            rcSrc = CRect(m_nSrcWidth/4 * 3, 0, m_nSrcWidth, m_nSrcHeight);
        }
        break;
 
    default:
        break;
    }
    m_Image.Draw(dcMem.m_hDC, buttonRect, rcSrc);
 
    dcMem.SetBkMode(TRANSPARENT);
    dcMem.SetTextColor(m_clr);
    CFont* pOldFont = dcMem.SelectObject(m_pFont);
    DrawText(dcMem.m_hDC, m_strBtnText, -1, buttonRect, DT_CENTER|DT_SINGLELINE|DT_VCENTER);
    dcMem.SelectObject(pOldFont);
 
    pDC->BitBlt(0, 0, buttonRect.Width(), buttonRect.Height(), &dcMem, 0, 0, SRCCOPY);
    memBitmap.DeleteObject();
}
 
BOOL CBaseBtn::OnEraseBkgnd(CDC* pDC)
{
    return TRUE;
}

第一类button(NormalBtn.h)
#ifndef __NORMALBTN_H__
#define __NORMALBTN_H__
 
#include "BaseBtn.h"
 
class CNormalBtn : public CBaseBtn
{
public:
    CNormalBtn();
    ~CNormalBtn();
 
protected:
    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 LRESULT OnMouseLeave(WPARAM, LPARAM);       
    afx_msg LRESULT OnMouseHover(WPARAM, LPARAM);
 
    DECLARE_MESSAGE_MAP()
 
private:
    BOOL   m_bTracking;                        // 捕获设置标记
    
};
 
#endif


第一类button(NormalBtn. cpp)
#include "stdafx.h"
#include "NormalBtn.h"
#include "Public.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 
CNormalBtn::CNormalBtn()
    :m_bTracking(FALSE)
{
 
}
 
CNormalBtn::~CNormalBtn()
{
 
}
 
BEGIN_MESSAGE_MAP(CNormalBtn, CBaseBtn)
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)       
    ON_MESSAGE(WM_MOUSEHOVER,OnMouseHover)
END_MESSAGE_MAP()
 
void CNormalBtn::OnMouseMove(UINT nFlags, CPoint point) 
{
    if (!m_bTracking)  
    {   
        TRACKMOUSEEVENT tme;  
        tme.cbSize = sizeof(tme);  
        tme.hwndTrack = m_hWnd;  
        tme.dwFlags = TME_LEAVE|TME_HOVER;  
        tme.dwHoverTime = 1;  
        m_bTracking = _TrackMouseEvent(&tme);  
    }  
 
    CBaseBtn::OnMouseMove(nFlags, point);
}
LRESULT CNormalBtn::OnMouseHover(WPARAM wParam,LPARAM lParam)
{
    if (m_nCtrlState == CTRL_NOFOCUS)
    {
        m_nCtrlState = CTRL_FOCUS;
        Invalidate();
    }
 
    m_bTracking = FALSE;
    return 0;
}
 
LRESULT CNormalBtn::OnMouseLeave(WPARAM wParam,LPARAM   lParam)       
{   
    if(m_nCtrlState != CTRL_NOFOCUS)
    {
        m_nCtrlState = CTRL_NOFOCUS;
        Invalidate();
    }
 
    m_bTracking = FALSE; 
    return 0;       
}       
 
void CNormalBtn::OnLButtonDown(UINT nFlags, CPoint point) 
{
    if(m_nCtrlState == CTRL_FOCUS)
    {
        m_nCtrlState = CTRL_SELECTED;
        Invalidate();
    }
 
    CBaseBtn::OnLButtonDown(nFlags, point);
}
 
void CNormalBtn::OnLButtonUp(UINT nFlags, CPoint point)
{
    if(m_nCtrlState == CTRL_SELECTED)
    {
        m_nCtrlState = CTRL_FOCUS;
        Invalidate();
    }
    CBaseBtn::OnLButtonUp(nFlags, point);
}

第二类按钮(CMenu.h)
#ifndef __MENUBTN_H__
#define __MENUBTN_H__
 
#include "BaseBtn.h"
 
class CMenuBtn : public CBaseBtn
{
public:
    CMenuBtn();
    ~CMenuBtn();
 
public:
    BOOL GetMenuOn()    { return m_bMenuOn;    }
    void SetMenuOn(BOOL bMenuOn);
 
protected:
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg LRESULT OnMouseLeave(WPARAM, LPARAM);       
    afx_msg LRESULT OnMouseHover(WPARAM, LPARAM);
 
    DECLARE_MESSAGE_MAP()
 
private:
    BOOL   m_bTracking;                        // 捕获设置标记
    BOOL   m_bMenuOn;                        // 该菜单按钮是否被选中
 
};
 
#endif

第二类按钮(CButton.cpp)
#include "stdafx.h"
#include "MenuBtn.h"
#include "Public.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 
CMenuBtn::CMenuBtn()
:m_bTracking(FALSE)
,m_bMenuOn(FALSE)
{
 
}
 
CMenuBtn::~CMenuBtn()
{
 
}
 
BEGIN_MESSAGE_MAP(CMenuBtn, CBaseBtn)
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONDOWN()
    ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)       
    ON_MESSAGE(WM_MOUSEHOVER,OnMouseHover)
END_MESSAGE_MAP()
 
void CMenuBtn::OnMouseMove(UINT nFlags, CPoint point) 
{        
    if (!m_bTracking)  
    {   
        TRACKMOUSEEVENT tme;  
        tme.cbSize = sizeof(tme);  
        tme.hwndTrack = m_hWnd;  
        tme.dwFlags = TME_LEAVE|TME_HOVER;  
        tme.dwHoverTime = 1;  
        m_bTracking = _TrackMouseEvent(&tme);  
    }  
 
    CButton::OnMouseMove(nFlags, point);
}
 
void CMenuBtn::OnLButtonDown(UINT nFlags, CPoint point) 
{
    if(m_nCtrlState != CTRL_SELECTED)
    {
        m_nCtrlState = CTRL_SELECTED;
        m_bMenuOn = TRUE;
        Invalidate();
    }
 
    CButton::OnLButtonDown(nFlags, point);
}
 
LRESULT CMenuBtn::OnMouseLeave(WPARAM     wParam,LPARAM   lParam)       
{   
    if(m_bMenuOn)
    {
        m_nCtrlState = CTRL_SELECTED;
        Invalidate();
    }
    else
    {
        m_nCtrlState = CTRL_NOFOCUS;
        Invalidate();
    }
 
    m_bTracking = FALSE; 
    return 0;       
}       
 
LRESULT CMenuBtn::OnMouseHover(WPARAM wParam,LPARAM lParam)
{
    if (m_nCtrlState != CTRL_FOCUS)
    {
        m_nCtrlState = CTRL_FOCUS;
        Invalidate();
    }
 
    m_bTracking = FALSE;
    return 0;
}
 
void CMenuBtn::SetMenuOn(BOOL bMenuOn)
{
    m_bMenuOn = bMenuOn;
    Invalidate();
}

第三类按钮(CStaticBtn.h)
#ifndef __STATICBTN_H__
#define __STATICBTN_H__
 
#include "BaseBtn.h"
 
class CStaticBtn : public CBaseBtn
{
public:
    CStaticBtn();
    ~CStaticBtn();
 
public:
    virtual void Init(UINT uImageID);
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
};
 
 
#endif

第三类按钮(CStaticBtn.cpp)
#include "stdafx.h"
#include "StaticBtn.h"
#include "Public.h"
 
CStaticBtn::CStaticBtn()
{
 
}
 
CStaticBtn::~CStaticBtn()
{
 
}
 
void CStaticBtn::Init(UINT uImageID)
{
    SetButtonStyle(BS_OWNERDRAW);
 
    LoadPicture(m_Image, uImageID);
    m_nSrcWidth = m_Image.GetWidth();
    m_nSrcHeight = m_Image.GetHeight();
 
    SetWindowPos(NULL, 0, 0, m_nSrcWidth, m_nSrcHeight, SWP_NOMOVE|SWP_NOACTIVATE);
}
 
void CStaticBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    if (m_Image.IsNull())
        return;
 
    CRect rcBtutton;
    GetClientRect(rcBtutton);
 
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
 
    CRect rcSrc = CRect(0, 0, m_nSrcWidth, m_nSrcHeight);
    m_Image.Draw(pDC->m_hDC, rcBtutton, rcSrc);
}

使用方法:
CNoraml m_NorBtn;

m_NorBtn.Init(UNIT);

因为NormalBtn和MenuBtn需要相应鼠标事件,有图片切换,为了更好的图片切换效果使用双缓冲绘图。双缓冲绘图需要先创建一张画布(CBaseBtn::DrawItem()函数)

    CBitmap memBitmap;
    memBitmap.CreateCompatibleBitmap(pDC, buttonRect.Width(), buttonRect.Height());
    dcMem.SelectObject(memBitmap);
    dcMem.FillSolidRect(buttonRect, RGB(255,0,255));    //设置画布颜色

所以虽然用了虽然PNG图片有透明属性,但是画布无法设置透明属性,最后的结果是虽然PNG图片背景透明了,因为画布的存在,无法做出一个不规程的按钮出来。
而StaticBtn使用的是单缓冲,没有画布的存在,利用PNG图片的透明属性,可以做出一个不规则的按钮。但是单缓冲绘图对于图片的切换效果不好,所以只用来做一个不响应鼠标消息的静态按钮。未来有空我将会写《MFC 之 CButton 控件重绘(GDI+篇)》利用GDI+绘图来解决这个问题。

完整的项目工程下载地址:http://download.csdn.net/detail/yuzhenxiong0823/7167827

原文:https://blog.csdn.net/yuzhenxiong0823/article/details/23278763 
 

你可能感兴趣的:(MFC,MFC-自绘)