MFC 之 CButton 控件重绘(GDI篇)
2014-04-09 17:24
411 查看
最近在为公司用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)
基类代码(BaseBtn.cpp)
第一类button(NormalBtn.h)
第一类button(NormalBtn. cpp)
第二类按钮(CMenu.h)
第二类按钮(CButton.cpp)
第三类按钮(CStaticBtn.h)
第三类按钮(CStaticBtn.cpp)
使用方法:
CNoraml m_NorBtn;
m_NorBtn.Init(UNIT);
因为NormalBtn和MenuBtn需要相应鼠标事件,有图片切换,为了更好的图片切换效果使用双缓冲绘图。双缓冲绘图需要先创建一张画布(CBaseBtn::DrawItem()函数)
所以虽然用了虽然PNG图片有透明属性,但是画布无法设置透明属性,最后的结果是虽然PNG图片背景透明了,因为画布的存在,无法做出一个不规程的按钮出来。
而StaticBtn使用的是单缓冲,没有画布的存在,利用PNG图片的透明属性,可以做出一个不规则的按钮。但是单缓冲绘图对于图片的切换效果不好,所以只用来做一个不响应鼠标消息的静态按钮。未来有空我将会写《MFC 之 CButton 控件重绘(GDI+篇)》利用GDI+绘图来解决这个问题。
完整的项目工程下载地址:http://download.csdn.net/detail/yuzhenxiong0823/7167827
目前为止,做了三种类型的按钮,分别是:
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 <atlimage.h> #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
相关文章推荐
- MFC 之 CButton 控件重绘(GDI篇)
- MFC 之 CButton 控件重绘(GDI+篇)
- MFC重绘控件篇---按钮CButton
- MFC重绘控件使CPU占用100%解决方法
- MFC Cbutton、Cstatic、Edit/控件修改字体及颜色
- VC/MFC按钮(CButton)控件
- CButton控件:mfc自绘按钮类,1张图片显示多种状态的方法
- CButton控件:mfc自绘按钮类,1张图片显示多种状态的方法
- MFC重绘控件篇---按钮CListBox
- MFC控件完全重绘从CWnd开始
- CButton控件:mfc自绘按钮类,1张图片显示多种状态的方法
- VC MFC按钮(CButton)控件
- CButton控件:mfc自绘按钮类,1张图片显示多种状态的方法
- MFC中动态创建列表控件及其刷新重绘的方法
- MFC之窗口控件更新重绘相关函数
- CButton控件:mfc自绘按钮类,1张图片显示多种状态的方法
- CButton控件:mfc自绘按钮类,1张图片显示多种状态的方法
- MFC控件完全重绘从CWnd开始
- MFC控件背景重绘
- CButton控件:mfc自绘按钮类,1张图片显示多种状态的方法