MFC (2)Button控件自绘实现

    首先来看MFC里面的CButton类源码。如果需要按钮跟界面能很好的匹配的话,一种方法就是设置CButton类的函数参数,另一种方法就是仿照CButton类设计一个新的类,实现Button的自绘。

   CButton类源码如下:

class CButton : public CWnd
{
	DECLARE_DYNAMIC(CButton)

// Constructors
public:
	CButton();
	virtual BOOL Create(LPCTSTR lpszCaption, DWORD dwStyle,
				const RECT& rect, CWnd* pParentWnd, UINT nID);

// Attributes
	UINT GetState() const;
	void SetState(BOOL bHighlight);
	int GetCheck() const;
	void SetCheck(int nCheck);
	UINT GetButtonStyle() const;
	void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE);

	HICON SetIcon(HICON hIcon);
	HICON GetIcon() const;
	HBITMAP SetBitmap(HBITMAP hBitmap);
	HBITMAP GetBitmap() const;
	HCURSOR SetCursor(HCURSOR hCursor);
	HCURSOR GetCursor();

#if (_WIN32_WINNT >= 0x501)
	AFX_ANSI_DEPRECATED BOOL GetIdealSize(_Out_ LPSIZE psize) const;
	AFX_ANSI_DEPRECATED BOOL SetImageList(_In_ PBUTTON_IMAGELIST pbuttonImagelist);
	AFX_ANSI_DEPRECATED BOOL GetImageList(_In_ PBUTTON_IMAGELIST pbuttonImagelist) const;
	AFX_ANSI_DEPRECATED BOOL SetTextMargin(_In_ LPRECT pmargin);
	AFX_ANSI_DEPRECATED BOOL GetTextMargin(_Out_ LPRECT pmargin) const;
#endif  // (_WIN32_WINNT >= 0x501)

#if ( _WIN32_WINNT >= 0x0600 ) && defined(UNICODE)
	CString GetNote() const;
	_Check_return_ BOOL GetNote(_Out_z_cap_(*pcchNote) LPTSTR lpszNote, _Inout_ UINT* pcchNote) const;
	BOOL SetNote(_In_z_ LPCTSTR lpszNote);
	UINT GetNoteLength() const;
	BOOL GetSplitInfo(_Out_ PBUTTON_SPLITINFO pInfo) const;
	BOOL SetSplitInfo(_In_ PBUTTON_SPLITINFO pInfo);
	UINT GetSplitStyle() const;
	BOOL SetSplitStyle(_In_ UINT nStyle);
	BOOL GetSplitSize(_Out_ LPSIZE pSize) const;
	BOOL SetSplitSize(_In_ LPSIZE pSize);
	CImageList* GetSplitImageList() const;
	BOOL SetSplitImageList(_In_ CImageList* pSplitImageList);
	TCHAR GetSplitGlyph() const;
	BOOL SetSplitGlyph(_In_ TCHAR chGlyph);
	BOOL SetDropDownState(_In_ BOOL fDropDown);

	// Sets whether the action associated with the button requires elevated permissions.
	// If elevated permissions are required then the button should display an elevated icon.
	HICON SetShield(_In_ BOOL fElevationRequired);
#endif // ( _WIN32_WINNT >= 0x600 ) && defined(UNICODE)

// Overridables (for owner draw only)
	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

// Implementation
public:
	virtual ~CButton();
protected:
	virtual BOOL OnChildNotify(UINT, WPARAM, LPARAM, LRESULT*);
};

 自绘VincentButton类如下:

#ifndef _VINCENT_BUTTON_H_
#define _VINCENT_BUTTON_H_

class VincentButton : public CButton
{
public:
	VincentButton();
	virtual ~VincentButton();

    // 填充按钮中间部分的渐变色
	virtual void GradientFill(CDC *pDC, CRect* rect);

    // 绘制边框
	virtual void DrawBorder(CDC *pDC, CRect* rect);

    // 改写自CButton类
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

protected:
    virtual void PreSubclassWindow();

    // MFC标准消息映射函数

	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);


protected:
	DECLARE_MESSAGE_MAP()

public:
    // 正常状态下按钮的边框
    CPen m_penBorderNormal;
    // 按钮获得焦点时的边框或者鼠标滑过或者停留在按钮上
    CPen m_penBorderOnFocus;
    // 按钮状态
    bool m_bMouseOn;        // 鼠标在按钮上
    bool m_bMouseClick;     // 点击鼠标
    bool m_bMouseUp;        // 鼠标按键抬起
    bool m_bFocus;          // 鼠标获得焦点

    CRect m_rect;
};

#endif



// VincentButton.cpp : implementation file
//

#include "stdafx.h"
#include "VincentButton.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

VincentButton::VincentButton()
{
    m_penBorderNormal.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0x23, 0xC5, 0xCE));
    m_penBorderOnFocus.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0xFF, 0x00, 0xFF));

    m_bMouseOn = false;
    m_bMouseClick = false;
    m_bMouseUp = true;
    m_bFocus = false;
}

VincentButton::~VincentButton()
{
    m_penBorderNormal.DeleteObject();
    m_penBorderOnFocus.DeleteObject();
}


BEGIN_MESSAGE_MAP(VincentButton, CButton)
    ON_WM_MOUSEMOVE()
    ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
    ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

#pragma warning(push)
#pragma warning(disable:4800)
void VincentButton::OnMouseMove(UINT nFlags, CPoint point)
{
    if (!m_bMouseUp)
    {
        TRACKMOUSEEVENT tme;

        tme.cbSize = sizeof(tme);
        tme.hwndTrack = m_hWnd;
        tme.dwFlags = TME_LEAVE | TME_HOVER;
        tme.dwHoverTime = 1;

        m_bMouseOn = _TrackMouseEvent(&tme);
    }

    CButton::OnMouseMove(nFlags, point);
}
#pragma warning(pop)

LRESULT VincentButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
    m_bMouseOn = false;

    InvalidateRect(NULL);

    return 0;
}

LRESULT VincentButton::OnMouseHover(WPARAM wParam, LPARAM lParam)
{
    m_bMouseOn = true;

    InvalidateRect(NULL, FALSE);

    return 0;
}

void VincentButton::OnLButtonDown(UINT nFlags, CPoint point)
{
    m_bMouseOn = true;
    m_bMouseUp = false;
    m_bMouseClick = true;
    m_bFocus = true;


    InvalidateRect(NULL, FALSE);

    CButton::OnLButtonDown(nFlags, point);
}

void VincentButton::OnLButtonUp(UINT nFlags, CPoint point)
{
    m_bMouseUp = true;
    m_bMouseOn = false;
    m_bMouseClick = true;
    m_bFocus = true;

    InvalidateRect(NULL, FALSE);

    CButton::OnLButtonUp(nFlags, point);
}


void VincentButton::GradientFill(CDC *pDC, CRect* rect)
{
    BYTE r = 34;
    BYTE g = 180;
    BYTE b = 227;

    CPen *temp = new CPen;
    CPen *pOldPen = pDC->SelectObject(temp);

    LONG nMiddle = (rect->bottom - rect->top) / 2;
    LONG i = 0;

    for (i = nMiddle; i > rect->top; --i)
    {
        CPen pen(PS_INSIDEFRAME | PS_SOLID, 1,
            RGB(r + 10 * (nMiddle - i), g + 2 * (nMiddle - i), b + (nMiddle - i)));

        pDC->SelectObject(&pen);
        pDC->MoveTo(rect->left, i);
        pDC->LineTo(rect->right, i);
    }

    for (i = nMiddle; i < rect->bottom; ++i)
    {
        CPen pen(PS_INSIDEFRAME | PS_SOLID, 1,
            RGB(r + 10 * (i - nMiddle), g + 2 * (i - nMiddle), b + (i - nMiddle)));

        pDC->SelectObject(&pen);
        pDC->MoveTo(rect->left, i);
        pDC->LineTo(rect->right, i);
    }

    delete temp;

    pDC->SelectObject(pOldPen);
}


void VincentButton::DrawBorder(CDC *pDC, CRect* rect)
{
    CPen *pOldPen ;
    CPoint oldPoint = pDC->MoveTo(rect->left, rect->bottom - 1);


    if (m_bFocus || m_bMouseOn)
    {
        pOldPen = pDC->SelectObject(&m_penBorderOnFocus);
    }
    else
    {
        pOldPen = pDC->SelectObject(&m_penBorderNormal);
    }

    pDC->MoveTo(rect->left, rect->top);
    pDC->LineTo(rect->right - 1, rect->top);
    pDC->LineTo(rect->right - 1, rect->bottom - 1);
    pDC->LineTo(rect->left, rect->bottom - 1);
    pDC->LineTo(rect->left, rect->top);
    pDC->MoveTo(oldPoint);

    pDC->SelectObject(pOldPen);
}

void VincentButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    CRect rect =  lpDrawItemStruct->rcItem;
    CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
    int nSaveDC=pDC->SaveDC();
    UINT state = lpDrawItemStruct->itemState;
    TCHAR strText[MAX_PATH + 1];
    ::GetWindowText(m_hWnd, strText, MAX_PATH);

    CPen* hOldPen = pDC->SelectObject(&m_penBorderNormal);

    if (state & ODS_FOCUS)
    {
        m_bFocus = true;
        m_bMouseClick = true;
    }
    else
    {
        m_bFocus = false;
        m_bMouseClick = false;
    }

    if (state & ODS_SELECTED || state & ODS_DEFAULT)
    {
        m_bFocus = true;
    }

    pDC->SelectObject(hOldPen);

    if (m_bMouseOn)
    {
        hOldPen = pDC->SelectObject(&m_penBorderOnFocus);

        GradientFill(pDC, &rect);
    }
    else
    {
        hOldPen = pDC->SelectObject(&m_penBorderNormal);

        GradientFill(pDC, &rect);
    }
     
    pDC->SelectObject(hOldPen);
    DrawBorder(pDC, &m_rect);

    //显示按钮的文本
    if (strText!=NULL)
    {
        pDC->SetTextColor(RGB(0x3A, 0x5F, 0xCD));
        CFont* hFont = GetFont();
        CFont* hOldFont = pDC->SelectObject(hFont);
        CSize szExtent = pDC->GetTextExtent(strText, lstrlen(strText));
        CPoint pt( rect.CenterPoint().x - szExtent.cx / 2, rect.CenterPoint().y - szExtent.cy / 2);
        if (state & ODS_SELECTED) 
            pt.Offset(1, 1);
        int nMode = pDC->SetBkMode(TRANSPARENT);
        if (state & ODS_DISABLED)
            pDC->DrawState(pt, szExtent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
        else
            pDC->DrawState(pt, szExtent, strText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);
        pDC->SelectObject(hOldFont);
        pDC->SetBkMode(nMode);
    }

    pDC->RestoreDC(nSaveDC);
}

void VincentButton::PreSubclassWindow()
{
    ModifyStyle(0, BS_OWNERDRAW);

    GetClientRect(&m_rect);

    CButton::PreSubclassWindow();
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值