Button控件自绘

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Button控件自绘相关的知识,希望对你有一定的参考价值。

1. 派生CButton

2. 重写PreSubclassWindow函数,设置BS_OWNERDRAW属性

  void CButtonEx::PreSubclassWindow() {

   // TODO: 在此添加专用代码和/或调用基类  

  UINT nStyle = GetButtonStyle();  

  SetButtonStyle(nStyle | BS_OWNERDRAW);

   CButton::PreSubclassWindow();

  }

3. 重写DrawItem函数实现Button重绘

ButtonEx.h

技术分享图片
/* @Button自绘控件类设计
*根据鼠标动作绘制相对应的button形态
*鼠标动作:停止、按下、弹起
*button形态:
*/
#pragma once

// CButtonEx
class CButtonEx : public CButton
{
    DECLARE_DYNAMIC(CButtonEx)

public:
    CButtonEx();
    virtual ~CButtonEx();


protected:
    DECLARE_MESSAGE_MAP()
    afx_msg void OnKillFocus(CWnd* pNewWnd);
    afx_msg void OnCaptureChanged(CWnd *pWnd);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);

    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    virtual void PreSubclassWindow();
    void DrawTheIcon(CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect, BOOL IsPressed/*, BOOL IsDisabled*/);

public:
    void SetIcon(int nIconInId, int nIconOutId = NULL, BYTE cx = 32, BYTE cy = 32);
    
private:
    BOOL m_MouseOnButton;
    HICON m_hIconIn;
    HICON m_hIconOut;
    BYTE m_cyIcon;
    BYTE m_cxIcon;
    
    int m_nAlign;
};
View Code

ButtonEx.cpp

技术分享图片
// ButtonEx.cpp : 实现文件
//

#include "stdafx.h"
#include "mfcctrlstu.h"
#include "ButtonEx.h"

#include "ButtonBase.h"

// CButtonEx

IMPLEMENT_DYNAMIC(CButtonEx, CButton)

CButtonEx::CButtonEx()
{
    m_MouseOnButton = FALSE;
    m_nAlign = ST_ALIGN_HORIZ;
}

CButtonEx::~CButtonEx()
{
    if (m_hIconIn != NULL) ::DeleteObject(m_hIconIn);
    if (m_hIconOut != NULL) ::DeleteObject(m_hIconOut);
}


BEGIN_MESSAGE_MAP(CButtonEx, CButton)
    ON_WM_MOUSEMOVE()
    ON_WM_KILLFOCUS()
    ON_WM_CAPTURECHANGED()
END_MESSAGE_MAP()

// CButtonEx 消息处理程序
void CButtonEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    CRect itemRect = lpDrawItemStruct->rcItem;

    BOOL bIsPressed  = (lpDrawItemStruct->itemState & ODS_SELECTED);
    BOOL bIsFocused  = (lpDrawItemStruct->itemState & ODS_FOCUS);
    BOOL bIsDisabled = (lpDrawItemStruct->itemState & ODS_DISABLED);
    CButtonBase *pButton = NULL;
    if (bIsPressed)
    {
        pButton = new CPressButton();
    }
    else if (m_MouseOnButton)
    {
        pButton = new CMouseOnButton();
    }
    else
    {
        pButton = new CFlatButton();
    }
    // 属性初始化
    CString strTitle="";
    GetWindowText(strTitle);
    COLORREF color = RGB(255,0,0);
    pButton->SetButtonText(strTitle);
    pButton->SetBkColor(color);
    pButton->SetTextColor(color);
    pButton->SetIcon(m_hIconIn, m_hIconOut,m_cxIcon, m_cyIcon);
    pButton->SetGroupLignMode(m_nAlign);
    pButton->Draw(pDC, itemRect);

    delete pButton;
    pButton = NULL;
}

void CButtonEx::PreSubclassWindow()
{
    // TODO: 在此添加专用代码和/或调用基类
    UINT nStyle = GetButtonStyle();
    SetButtonStyle(nStyle | BS_OWNERDRAW);

    CButton::PreSubclassWindow();
}

void CButtonEx::OnMouseMove(UINT nFlags, CPoint point)
{
    CWnd* pWnd;  // Finestra attiva
    CWnd* pParent; // Finestra che contiene il bottone

    CButton::OnMouseMove(nFlags, point);

    // If the mouse enter the button with the left button pressed
    // then do nothing
    if (nFlags & MK_LBUTTON && m_MouseOnButton == FALSE) return;

    // If our button is not flat then do nothing
    //if (m_bIsFlat == FALSE) return;

    pWnd = GetActiveWindow();
    pParent = GetOwner();

    if ((GetCapture() != this) && 
        (
#ifndef ST_LIKEIE
        pWnd != NULL && 
#endif
        pParent != NULL)) 
    {
        m_MouseOnButton = TRUE;
        //SetFocus();    // Thanks Ralph!
        SetCapture();
        Invalidate();
    }
    else
    {
        CRect rc;
        GetClientRect(&rc);
        if (!rc.PtInRect(point))
        {
            // Redraw only if mouse goes out
            if (m_MouseOnButton == TRUE)
            {
                m_MouseOnButton = FALSE;
                Invalidate();
            }
            // If user is NOT pressing left button then release capture!
            if (!(nFlags & MK_LBUTTON)) ReleaseCapture();
        }
    }
}

void CButtonEx::OnKillFocus(CWnd* pNewWnd)
{
    CButton::OnKillFocus(pNewWnd);

    // If our button is not flat then do nothing
    //if (m_bIsFlat == FALSE) return;

    if (m_MouseOnButton == TRUE)
    {
        m_MouseOnButton = FALSE;
        Invalidate();
    }
}

void CButtonEx::OnCaptureChanged(CWnd *pWnd)
{
    if (m_MouseOnButton == TRUE)
    {
        ReleaseCapture();
        Invalidate();
    }

    // Call base message handler
    CButton::OnCaptureChanged(pWnd);
} // End of OnCaptureChanged

void CButtonEx::SetIcon(int nIconInId, int nIconOutId, BYTE cx, BYTE cy)
{
    HINSTANCE hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nIconInId),RT_GROUP_ICON);
    // Set icon when the mouse is IN the button
    m_hIconIn = (HICON)::LoadImage(hInstResource/*AfxGetApp()->m_hInstance*/, MAKEINTRESOURCE(nIconInId), IMAGE_ICON, 0, 0, 0);

    // Set icon when the mouse is OUT the button
    m_hIconOut = (nIconOutId == NULL) ? m_hIconIn : (HICON)::LoadImage(hInstResource/*AfxGetApp()->m_hInstance*/, MAKEINTRESOURCE(nIconOutId), IMAGE_ICON, 0, 0, 0);

    m_cxIcon = cx;
    m_cyIcon = cy;

    RedrawWindow();
} // End of SetIcon

void CButtonEx::DrawTheIcon(CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect, BOOL IsPressed/*, BOOL IsDisabled*/)
{
    CRect iconRect = rcItem;

    // 根据对齐方式进行布局
    switch (m_nAlign)
    {
    case ST_ALIGN_HORIZ:
        if (title->IsEmpty())
        {
            // Center the icon horizontally
            iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        }
        else
        {
            // L‘icona deve vedersi subito dentro il focus rect
            iconRect.left += 3;  
            captionRect->left += m_cxIcon + 3;
        }
        // Center the icon vertically
        iconRect.top += ((iconRect.Height() - m_cyIcon)/2);
        break;
    case ST_ALIGN_VERT:
        // Center the icon horizontally
        iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        if (title->IsEmpty())
        {
            // Center the icon vertically
            iconRect.top += ((iconRect.Height() - m_cyIcon)/2);           
        }
        else
        {
            captionRect->top += m_cyIcon;
        }
        break;
    }

    // If button is pressed then press the icon also
    if (IsPressed) iconRect.OffsetRect(1, 1);
    // Ole‘!
    pDC->DrawState(iconRect.TopLeft(), 
        iconRect.Size(), 
        (m_MouseOnButton == TRUE || IsPressed) ? m_hIconIn : m_hIconOut, 
        DSS_NORMAL,
        /*(IsDisabled ? DSS_DISABLED : DSS_NORMAL), */
        (CBrush*)NULL);
} // End of DrawTheIcon
View Code

 ButtonBase.h

技术分享图片
/*
*    
*/
#pragma once

enum TEXT_ICON_ALIGN
{
    ST_ALIGN_HORIZ = 0, 
    ST_ALIGN_VERT
};

class CButtonBase
{
public:
    CButtonBase(){};
    virtual ~CButtonBase(){};

    virtual void Draw(CDC *pDC, CRect itemRect) = 0;      // button绘制

    virtual void SetButtonText(CString StrText)=0;
    virtual void SetBkColor(COLORREF color)=0;
    virtual void SetTextColor(COLORREF color)=0;
    virtual void SetIcon(HICON hIconIn=NULL, HICON hIconOut=NULL, BYTE m_cyIcon=32,BYTE m_cxIcon=32)=0;
    virtual void SetGroupLignMode(int nAlignType = ST_ALIGN_HORIZ)=0;

protected:
    CString m_strText;           // 文本内容
    COLORREF m_bkColor;          // 背景色
    COLORREF m_TextColor;        // 文本颜色

    HICON m_hIconIn;            // 图标1 
    HICON m_hIconOut;           // 图标2;
    BYTE m_cyIcon;              
    BYTE m_cxIcon;

    int m_nAlign;               // 文本、icon对齐方式
};

class CMouseOnButton : public CButtonBase
{
public:
    CMouseOnButton();
    virtual ~CMouseOnButton();

    void Draw(CDC *pDC, CRect itemRect);
    void SetButtonText(CString StrText){m_strText=StrText;}
    void SetBkColor(COLORREF color){m_bkColor=color;}
    void SetTextColor(COLORREF color){m_TextColor=color;}
    void SetIcon(HICON hIconIn=NULL, HICON hIconOut=NULL,BYTE cyIcon=32,BYTE cxIcon=32)
    {
        m_hIconIn=hIconIn;
        m_hIconOut=hIconOut;
        m_cxIcon = cxIcon;
        m_cyIcon = cyIcon;
    }
    void SetGroupLignMode(int nAlignType = ST_ALIGN_HORIZ){m_nAlign=nAlignType;}

private:    
    void DrawTheIcon(CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect);
};

class CFlatButton : public CButtonBase
{
public:
    CFlatButton();
    virtual ~CFlatButton();

    void Draw(CDC *pDC, CRect itemRect);
    void SetButtonText(CString StrText){m_strText=StrText;}
    void SetBkColor(COLORREF color){m_bkColor=color;}
    void SetTextColor(COLORREF color){m_TextColor=color;}
    void SetIcon(HICON hIconIn=NULL, HICON hIconOut=NULL,BYTE cyIcon=32,BYTE cxIcon=32)
    {
        m_hIconIn=hIconIn;
        m_hIconOut=hIconOut;
        m_cxIcon = cxIcon;
        m_cyIcon = cyIcon;
    }
    void SetGroupLignMode(int nAlignType = ST_ALIGN_HORIZ){m_nAlign=nAlignType;}

private:    
    void DrawTheIcon(CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect);
};

class CPressButton : public CButtonBase
{
public:
    CPressButton();
    virtual ~CPressButton();

    void Draw(CDC *pDC, CRect itemRect);
    void SetButtonText(CString StrText){m_strText=StrText;}
    void SetBkColor(COLORREF color){m_bkColor=color;}
    void SetTextColor(COLORREF color){m_TextColor=color;}
    void SetIcon(HICON hIconIn=NULL, HICON hIconOut=NULL,BYTE cyIcon=32,BYTE cxIcon=32)
    {
        m_hIconIn=hIconIn;
        m_hIconOut=hIconOut;
        m_cxIcon = cxIcon;
        m_cyIcon = cyIcon;
    }
    void SetGroupLignMode(int nAlignType = ST_ALIGN_HORIZ){m_nAlign=nAlignType;}

private:    
    void DrawTheIcon(CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect);
};
View Code

 ButtonBase.cpp

技术分享图片
#include "stdafx.h"
#include "ButtonBase.h"

// 平按钮类实现
CFlatButton::CFlatButton()
{
    m_strText = "";          
    m_bkColor = RGB(0,0,0);          
    m_TextColor = RGB(0,0,0);         
    m_hIconIn = NULL;          
    m_hIconOut = NULL;         
    m_cyIcon = 32;           
    m_cxIcon = 32;
    m_nAlign = 0;           
}

CFlatButton::~CFlatButton()
{

}

void CFlatButton::Draw( CDC *pDC, CRect itemRect )
{
    itemRect.DeflateRect(1,1);
    CPen pen3DDKShadow(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); // Black
    CPen *pOldPen = pDC->SelectObject(&pen3DDKShadow);
    //CBrush bkBrush(m_bkColor);
    //pDC->FillRect(&itemRect, &bkBrush);
    CRect rcICon = itemRect;
    DrawTheIcon(pDC, &m_strText, &rcICon,&itemRect);
    pDC->SetBkMode(TRANSPARENT);
    pDC->DrawText(m_strText, &itemRect,DT_SINGLELINE|DT_CENTER);
    pDC->SetTextColor(m_TextColor);

    pDC->SelectObject(pOldPen);
}

void CFlatButton::DrawTheIcon( CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect )
{
    CRect iconRect = rcItem;

    // 根据对齐方式进行布局
    switch (m_nAlign)
    {
    case ST_ALIGN_HORIZ:
        if (title->IsEmpty())
        {
            // Center the icon horizontally
            iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        }
        else
        {
            // L‘icona deve vedersi subito dentro il focus rect
            iconRect.left += 3;  
            captionRect->left += m_cxIcon + 3;
        }
        // Center the icon vertically
        iconRect.top += ((iconRect.Height() - m_cyIcon)/2);
        break;
    case ST_ALIGN_VERT:
        // Center the icon horizontally
        iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        if (title->IsEmpty())
        {
            // Center the icon vertically
            iconRect.top += ((iconRect.Height() - m_cyIcon)/2);           
        }
        else
        {
            captionRect->top += m_cyIcon;
        }
        break;
    }

    pDC->DrawState(iconRect.TopLeft(), iconRect.Size(), m_hIconOut, DSS_NORMAL,(CBrush*)NULL);
}

CMouseOnButton::CMouseOnButton()
{
    m_strText = "";          
    m_bkColor = RGB(0,0,0);          
    m_TextColor = RGB(0,0,0);         
    m_hIconIn = NULL;          
    m_hIconOut = NULL;         
    m_cyIcon = 32;           
    m_cxIcon = 32;
    m_nAlign = 0;   
}

CMouseOnButton::~CMouseOnButton()
{

}

void CMouseOnButton::Draw( CDC *pDC, CRect itemRect)
{
    CPen penBtnHiLight(PS_SOLID, 0, GetSysColor(COLOR_BTNHILIGHT)); // White
    CPen pen3DLight(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT));       // Light gray
    CPen penBtnShadow(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));   // Dark gray
    CPen pen3DDKShadow(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); // Black

    CPen *pOldPen = pDC->SelectObject(&penBtnHiLight);
    pDC->MoveTo(itemRect.left, itemRect.bottom-1);
    pDC->LineTo(itemRect.left, itemRect.top);
    pDC->LineTo(itemRect.right, itemRect.top);
    // Disegno i bordi a destra e in basso
    // Dark gray line
    pDC->SelectObject(penBtnShadow);
    pDC->MoveTo(itemRect.left, itemRect.bottom-1);
    pDC->LineTo(itemRect.right-1, itemRect.bottom-1);
    pDC->LineTo(itemRect.right-1, itemRect.top-1);
    
    itemRect.DeflateRect(1,1);
    pDC->SelectObject(&pen3DDKShadow);
    //CBrush bkBrush(m_bkColor);
    //pDC->FillRect(&itemRect, &bkBrush);
    CRect rcICon = itemRect;
    DrawTheIcon(pDC, &m_strText, &rcICon,&itemRect);
    pDC->SetBkMode(TRANSPARENT);
    pDC->DrawText(m_strText, &itemRect,DT_SINGLELINE|DT_CENTER);
    pDC->SetTextColor(m_TextColor);

    pDC->SelectObject(pOldPen);
}

void CMouseOnButton::DrawTheIcon( CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect )
{
    CRect iconRect = rcItem;

    // 根据对齐方式进行布局
    switch (m_nAlign)
    {
    case ST_ALIGN_HORIZ:
        if (title->IsEmpty())
        {
            // Center the icon horizontally
            iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        }
        else
        {
            // L‘icona deve vedersi subito dentro il focus rect
            iconRect.left += 3;  
            captionRect->left += m_cxIcon + 3;
        }
        // Center the icon vertically
        iconRect.top += ((iconRect.Height() - m_cyIcon)/2);
        break;
    case ST_ALIGN_VERT:
        // Center the icon horizontally
        iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        if (title->IsEmpty())
        {
            // Center the icon vertically
            iconRect.top += ((iconRect.Height() - m_cyIcon)/2);           
        }
        else
        {
            captionRect->top += m_cyIcon;
        }
        break;
    }

    pDC->DrawState(iconRect.TopLeft(), iconRect.Size(), m_hIconOut, DSS_NORMAL,(CBrush*)NULL);
}

// PressButton类实现
CPressButton::CPressButton()
{
    m_strText = "";          
    m_bkColor = RGB(0,0,0);          
    m_TextColor = RGB(0,0,0);         
    m_hIconIn = NULL;          
    m_hIconOut = NULL;         
    m_cyIcon = 32;           
    m_cxIcon = 32;
    m_nAlign = 0;   
}

CPressButton::~CPressButton()
{

}

void CPressButton::Draw( CDC *pDC, CRect itemRect )
{
    CPen penBtnHiLight(PS_SOLID, 0, GetSysColor(COLOR_BTNHILIGHT)); // Bianco
    CPen penBtnShadow(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));   // Grigio scuro

    // Disegno i bordi a sinistra e in alto
    // Dark gray line
    CPen *pOldPen = pDC->SelectObject(&penBtnShadow);
    pDC->MoveTo(itemRect.left, itemRect.bottom-1);
    pDC->LineTo(itemRect.left, itemRect.top);
    pDC->LineTo(itemRect.right, itemRect.top);
    // Disegno i bordi a destra e in basso
    // White line
    pDC->SelectObject(penBtnHiLight);
    pDC->MoveTo(itemRect.left, itemRect.bottom-1);
    pDC->LineTo(itemRect.right-1, itemRect.bottom-1);
    pDC->LineTo(itemRect.right-1, itemRect.top-1);
    
    itemRect.DeflateRect(1,1);
//    pDC->SelectObject(&pen3DDKShadow);
    //CBrush bkBrush(m_bkColor);
    //pDC->FillRect(&itemRect, &bkBrush);
    CRect rcICon = itemRect;
    DrawTheIcon(pDC, &m_strText, &rcICon,&itemRect);
    pDC->SetBkMode(TRANSPARENT);
    pDC->DrawText(m_strText, &itemRect,DT_SINGLELINE|DT_CENTER);
    pDC->SetTextColor(m_TextColor);

    pDC->SelectObject(pOldPen);
}

void CPressButton::DrawTheIcon( CDC* pDC, CString* title, RECT* rcItem, CRect* captionRect )
{

    CRect iconRect = rcItem;

    // 根据对齐方式进行布局
    switch (m_nAlign)
    {
    case ST_ALIGN_HORIZ:
        if (title->IsEmpty())
        {
            // Center the icon horizontally
            iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        }
        else
        {
            // L‘icona deve vedersi subito dentro il focus rect
            iconRect.left += 3;  
            captionRect->left += m_cxIcon + 3;
        }
        // Center the icon vertically
        iconRect.top += ((iconRect.Height() - m_cyIcon)/2);
        break;
    case ST_ALIGN_VERT:
        // Center the icon horizontally
        iconRect.left += ((iconRect.Width() - m_cxIcon)/2);
        if (title->IsEmpty())
        {
            // Center the icon vertically
            iconRect.top += ((iconRect.Height() - m_cyIcon)/2);           
        }
        else
        {
            captionRect->top += m_cyIcon;
        }
        break;
    }

    pDC->DrawState(iconRect.TopLeft(), iconRect.Size(), m_hIconIn, DSS_NORMAL,(CBrush*)NULL);
}
View Code

 

以上是关于Button控件自绘的主要内容,如果未能解决你的问题,请参考以下文章

mfc 作业day002

自绘listCtrl控件选中该行高亮(模拟windows)

控件的自绘

控件自绘DRAWITEMSTRUCT

用c/c++混合编程方式为ios/android实现一个自绘日期选择控件

VC自绘控件框架