MFC自绘-WzdButton按钮类

来源:互联网 发布:淘宝网首页不显示图片 编辑:程序博客网 时间:2024/06/08 12:22

这次来说说在窗口类里用到的按钮类的设计。
还是先看头文件:

#include "WzdImage.h"class CWzdButton : public CButton{    DECLARE_DYNAMIC(CWzdButton)protected:    bool           m_bExpand;        // 能否拉伸    bool           m_isHovering;     // 是否悬停    COLORREF       m_crTextColor;    // 字体颜色    CWzdImage      m_imageButton;    // 按钮图片public:    CWzdButton();    virtual ~CWzdButton();    // 加载位图    bool SetButtonImage(LPCTSTR pszFileName, bool bExpandImage = false);    bool SetButtonImage(HINSTANCE hInstance, LPCTSTR pszResourceName, bool bExpandImage = false);    bool SetTextColor(COLORREF crTextColor);    // 设置字体颜色    bool FixButtonSize();    // 调整按钮大小protected:    virtual void PreSubclassWindow();   // 子类化    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);    // 界面绘画函数    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);    afx_msg void OnMouseMove(UINT nFlags, CPoint point);    afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);    afx_msg BOOL OnEraseBkgnd(CDC* pDC);    DECLARE_MESSAGE_MAP()};

同样需要加载图片,因此包含WzdImage.h。
m_bExpand控制按钮图片能否根据按钮大小拉伸,m_bHovering标记鼠标是否悬停。

接着先看看构造函数,默认不拉伸、没有悬停、字体颜色为黑色。

CWzdButton::CWzdButton(): m_bExpand(false), m_isHovering(false), m_crTextColor(RGB(0,0,0)){}

同样有两种加载图片的方式,资源加载和路径加载,还有设置字体颜色的接口。

bool CWzdButton::SetButtonImage(LPCTSTR pszFileName, bool bExpandImage/*=false*/){    if (NULL == pszFileName) return false;    // 加载位图    m_bExpand = bExpandImage;    if (!m_imageButton.IsNull())    {        m_imageButton.DestroyImage();    }    m_imageButton.LoadImage(pszFileName);    if (!m_bExpand)        FixButtonSize();  // 调整按钮大小    if (GetSafeHwnd())        Invalidate(FALSE);    return true;}bool CWzdButton::SetButtonImage(HINSTANCE hInstance,LPCTSTR pszResourceName, bool bExpandImage/*=false*/){    if (NULL == pszResourceName) return false;    // 加载位图    m_bExpand = bExpandImage;    if (!m_imageButton.IsNull())    {        m_imageButton.DestroyImage();    }    m_imageButton.LoadImage(hInstance,pszResourceName);    if (!m_bExpand)        FixButtonSize(); // 调整按钮大小    if (GetSafeHwnd())        Invalidate(FALSE);    return true;}bool CWzdButton::SetTextColor(COLORREF crTextColor){    m_crTextColor = crTextColor;    if (GetSafeHwnd()) Invalidate(FALSE);    return true;}

FixButtonSize(),用于在按钮不拉伸时,改变按钮的大小。为什么按钮背景图宽度要除去4呢?默认采用的图片都是4种按钮背景(正常、悬停、点击、无效)水平排列,所以按钮大小就是图片大小的四分之一。

bool CWzdButton::FixButtonSize(){    if (!m_imageButton.IsNull() && GetSafeHwnd())    {        SetWindowPos(NULL, 0, 0, m_imageButton.GetWidth() / 4, m_imageButton.GetHeight(), SWP_NOMOVE);        return true;    }    return false;}

可以看到有PreSubclassWindow(),它是在按钮不是动态创建的时候,在创建之前会调用到这个函数。在这里只改变风格,让按钮支持自绘。

void CWzdButton::PreSubclassWindow(){    SetButtonStyle(GetButtonStyle() | BS_OWNERDRAW);    CButton::PreSubclassWindow();}

那动态创建的时候自然就是在OnCreate()里改变风格。

int CWzdButton::OnCreate(LPCREATESTRUCT lpCreateStruct){    if (-1 == CButton::OnCreate(lpCreateStruct)) return -1;    SetButtonStyle(GetButtonStyle() | BS_OWNERDRAW);    return 0;}

最关键的就是重写DrawItem()绘制按钮。先绘制背景,因为在WzdDialog窗口中设置了WS_CLIPCHILDREN 属性,窗口不对子控件背景进行重绘。而这里使用的是PNG透明图片,不自绘背景会是默认画刷的颜色,而我们需要窗口的背景色(只支持单色背景)。接着是根据按钮状态绘画不同的图像,最后绘画文字。

void CWzdButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct){    CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);    CRect rcClient;    GetClientRect(rcClient);    //CRect ParRect;    //GetWindowRect(&ParRect);    //GetParent()->ScreenToClient(&ParRect);    // 获取父窗口的背景,自己绘制背景,防止窗口背景重绘时的闪烁    CDC* BkDc= GetParent()->GetDC();    pDC->BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(),         BkDc, 0, 0, SRCCOPY);    bool bDisable = !!((lpDrawItemStruct->itemState & ODS_DISABLED));    bool bButtonDown = !!((lpDrawItemStruct->itemState & ODS_SELECTED));    if (!m_imageButton.IsNull())    {        // 计算位图位置        int nWidth = m_imageButton.GetWidth() / 4;        int nDrawPos = 0;        if (bDisable)            nDrawPos = nWidth * 3;        else if (bButtonDown)            nDrawPos = nWidth * 2;        else if (m_isHovering)            nDrawPos = nWidth * 1;        // 绘画按钮        if (!m_bExpand)            m_imageButton.DrawImage(pDC , 0, 0, rcClient.Width(),            rcClient.Height(), nDrawPos, 0);        else            m_imageButton.DrawImage(pDC, 0, 0, rcClient.Width(),            rcClient.Height(), nDrawPos, 0, nWidth, m_imageButton.GetHeight());    }    // 绘画字体    CString strText;    GetWindowText(strText);    rcClient.top+=1;    pDC->SetBkMode(TRANSPARENT);    if (bDisable)        pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));    else        pDC->SetTextColor(m_crTextColor);    pDC->DrawText(strText, strText.GetLength(), rcClient,        DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);}

响应鼠标移动,重载OnMouseMove。m_isHovering是鼠标悬停在按钮上,TrackMouseEvent那段代码是因为MouseLeave的消息发送存在问题,需要自己来触发MouseLeave消息,实现鼠标离开时m_isHovering状态的改变。

void CWzdButton::OnMouseMove(UINT nFlags, CPoint point){    if (!m_isHovering)    {        m_isHovering = true;        Invalidate(FALSE);        // 注册消息        TRACKMOUSEEVENT TrackMouseEvent;        TrackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);        TrackMouseEvent.dwFlags = TME_LEAVE;        TrackMouseEvent.hwndTrack = GetSafeHwnd();        TrackMouseEvent.dwHoverTime = HOVER_DEFAULT;        _TrackMouseEvent(&TrackMouseEvent);    }    CButton::OnMouseMove(nFlags, point);}void CWzdButton::OnMouseLeave(){    m_isHovering = false;    Invalidate(FALSE);    CButton::OnMouseLeave();}
0 0
原创粉丝点击