在操手MFC的时候,经常会抱怨MFC界面不如其他的框架或语言,比如VB,C#等等,面对MS在系统上的不断更新换代,我们也越来越追求软件的视觉效果,譬如我们会更喜欢win7下的玻璃效果,看起来很炫。

在接触MFC的时候,实在忍不住对MFC的bulider的仰慕之情,因为他把之前的win32 c编程(注意,里面没有面向对象)和C++有机的结合起来了(这时OO跑进来了),让我们更多的专注于软件的功能设计方面,减少了程序繁杂(真心真诚的佩服win32走过来的那些来程序员们)。

每天都有新的收获,当然不仅仅是软件方面的,因为最近讲师在教我们设计自己的U,其实这个看起来还是蛮有难度的,实际上也很有难度,但是讲师说的没错,了解硬件上的架构只是,或许对于我们软件方面的同学来说,也是不无益处的。

上主题吧。

CXPButton类是一个很不错的按钮类,代码阅读起来也很简单,不是非常难,只要是我们对windows编程有所了解的话。难点也不多,主要是对鼠标消息的处理上,比如鼠标到了按钮的上面但是没有按下是什么情形,鼠标按钮按下了又是什么情形,这个都是要体现出来的呀,不然人机交互就苦难了,大众也不会喜欢的。

另外我觉得在美术的设计上也是挺有难度的,就是很多都知道什么什么样的东西看起来很酷,但是就不知道它怎么去设计,就是所谓的知其然而不起所以然。

还有在消息的阅读上也有难度,比较生疏的地方就是,WM_MOUSELEAVE和WM_MOUSEHOVER这两个鼠标消息,windows默认是不处理这两个消息的,但是在自定义按钮过程当中又要用到它们。

所以要触发它们。

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

上面的代码就是我们所需要的。当鼠标在按钮上停留或者走出按钮区域的话,就(才)会触发两个消息。

在CXPButton当中只要我们熟练如何运用GDI(再在加上一点点的艺术天分),便可以做出非常酷的按钮。

下面是源代码:

#if !defined(AFX_XPBUTTON_H__44CD5B2A_756E_4939_9261_E0034E0F2DEF__INCLUDED_)
#define AFX_XPBUTTON_H__44CD5B2A_756E_4939_9261_E0034E0F2DEF__INCLUDED_#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// XPButton.h : header file
///
// CXPButton windowclass CXPButton : public CButton
{
// Construction
public:CXPButton();// Attributes
protected://按钮的外边框CPen m_BoundryPen;//鼠标指针置于按钮之上时按钮的内边框CPen m_InsideBoundryPenLeft;CPen m_InsideBoundryPenRight;CPen m_InsideBoundryPenTop;CPen m_InsideBoundryPenBottom;//按钮获得焦点时按钮的内边框CPen m_InsideBoundryPenLeftSel;CPen m_InsideBoundryPenRightSel;CPen m_InsideBoundryPenTopSel;CPen m_InsideBoundryPenBottomSel;//按钮的底色,包括有效和无效两种状态CBrush m_FillActive;CBrush m_FillInactive;//按钮的状态BOOL m_bOver;  //鼠标位于按钮之上时该值为true,反之为flaseBOOL m_bTracking; //在鼠标按下没有释放时该值为trueBOOL m_bSelected;    //按钮被按下是该值为trueBOOL m_bFocus;   //按钮为当前焦点所在时该值为true// Operations
public:// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CXPButton)protected:virtual void PreSubclassWindow();//}}AFX_VIRTUAL// Implementation
public:virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);virtual void DoGradientFill(CDC *pDC, CRect* rect);virtual void DrawInsideBorder(CDC *pDC, CRect* rect);virtual ~CXPButton();// Generated message map functions
protected://{{AFX_MSG(CXPButton)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_MSGDECLARE_MESSAGE_MAP()
};///{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_XPBUTTON_H__44CD5B2A_756E_4939_9261_E0034E0F2DEF__INCLUDED_)

  

// XPButton.cpp : implementation file
//#include "stdafx.h"
#include "XPButton.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif/
// CXPButtonCXPButton::CXPButton()
{m_BoundryPen.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0, 0, 0));m_InsideBoundryPenLeft.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(250, 196, 88)); m_InsideBoundryPenRight.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(251, 202, 106));m_InsideBoundryPenTop.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(252, 210, 121));m_InsideBoundryPenBottom.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(229, 151, 0));m_FillActive.CreateSolidBrush(RGB(223, 222, 236));m_FillInactive.CreateSolidBrush(RGB(222, 223, 236));m_InsideBoundryPenLeftSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(153, 198, 252)); m_InsideBoundryPenTopSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255));m_InsideBoundryPenRightSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(162, 189, 252));m_InsideBoundryPenBottomSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255));m_bOver = m_bSelected = m_bTracking = m_bFocus = FALSE;}CXPButton::~CXPButton()
{m_BoundryPen.DeleteObject();m_InsideBoundryPenLeft.DeleteObject();m_InsideBoundryPenRight.DeleteObject();m_InsideBoundryPenTop.DeleteObject();m_InsideBoundryPenBottom.DeleteObject();m_FillActive.DeleteObject();m_FillInactive.DeleteObject();m_InsideBoundryPenLeftSel.DeleteObject();m_InsideBoundryPenTopSel.DeleteObject();m_InsideBoundryPenRightSel.DeleteObject();m_InsideBoundryPenBottomSel.DeleteObject();}BEGIN_MESSAGE_MAP(CXPButton, CButton)//{{AFX_MSG_MAP(CXPButton)ON_WM_MOUSEMOVE()ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)//}}AFX_MSG_MAP
END_MESSAGE_MAP()/
// CXPButton message handlers//添加Owner Draw属性
void CXPButton::PreSubclassWindow()
{// TODO: Add your specialized code here and/or call the base classCButton::PreSubclassWindow();ModifyStyle(0, BS_OWNERDRAW);
}void CXPButton::OnMouseMove(UINT nFlags, CPoint point)
{// TODO: Add your message handler code here and/or call defaultif (!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);
}LRESULT CXPButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{m_bOver = FALSE;m_bTracking = FALSE;InvalidateRect(NULL, FALSE);/**/return 0;
}LRESULT CXPButton::OnMouseHover(WPARAM wParam, LPARAM lParam)
{m_bOver = TRUE;InvalidateRect(NULL);return 0;
}void CXPButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{//从lpDrawItemStruct获取控件的相关信息CRect rect =  lpDrawItemStruct->rcItem;CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);int nSaveDC=pDC->SaveDC();UINT state = lpDrawItemStruct->itemState;POINT pt ;TCHAR strText[MAX_PATH + 1] = L"我爱你";::GetWindowText(m_hWnd, strText, MAX_PATH);/*获取文本原色*///画按钮的外边框,它是一个半径为5的圆角矩形pt.x = 5;pt.y = 5;CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);pDC->RoundRect(&rect, pt);//获取按钮的状态if (state & ODS_FOCUS){m_bFocus = TRUE;m_bSelected = TRUE;}else{m_bFocus = FALSE;m_bSelected = FALSE;}if (state & ODS_SELECTED || state & ODS_DEFAULT){m_bFocus = TRUE;}pDC->SelectObject(hOldPen);rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));//根据按钮的状态填充按钮的底色CBrush* pOldBrush;if (m_bOver){pOldBrush = pDC->SelectObject(&m_FillActive);DoGradientFill(pDC, &rect);}else{pOldBrush = pDC->SelectObject(&m_FillInactive);DoGradientFill(pDC, &rect);}//根据按钮的状态绘制内边框if (m_bOver || m_bSelected)DrawInsideBorder(pDC, &rect);pDC->SelectObject(pOldBrush);//显示按钮的文本if (strText!=NULL){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);elsepDC->DrawState(pt, szExtent, strText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);pDC->SelectObject(hOldFont);pDC->SetBkMode(nMode);}pDC->RestoreDC(nSaveDC);
}//绘制按钮的底色
void CXPButton::DoGradientFill(CDC *pDC, CRect* rect)
{CBrush brBk[64];int nWidth = rect->Width();    int nHeight = rect->Height();CRect rct;/*for (int i = 0; i < 64; i ++){if (m_bOver){if (m_bFocus)brBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 3)));elsebrBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 5)));}else{if (m_bFocus)brBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 4)));elsebrBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 5)));}}int i;for (i = rect->top; i <= nHeight + 2; i ++) {rct.SetRect(rect->left, i, nWidth + 2, i + 1);pDC->FillRect(&rct, &brBk[((i * 63) / nHeight)]);}*/int i;brBk[0].CreateSolidBrush(RGB(255,0,0));brBk[1].CreateSolidBrush(RGB(0,0,0));brBk[2].CreateSolidBrush(RGB(0,0,255));brBk[3].CreateSolidBrush(RGB(0,255,0));CBitmap bitmap;BITMAP bmp;bitmap.LoadBitmapW(IDB_QQ);bitmap.GetBitmap(&bmp);CDC MemDC;MemDC.CreateCompatibleDC(pDC);if(m_bOver){CBitmap * OldBitmap = MemDC.SelectObject(&bitmap);pDC->BitBlt(0,0,bmp.bmWidth,bmp.bmHeight,&MemDC,0,0,SRCAND);MemDC.SelectObject(OldBitmap);/*if(m_bFocus)//鼠标+焦点pDC ->FillRect(rect,&brBk[0]);//红else//鼠标+无焦点pDC ->FillRect(rect,&brBk[1]);//黑*/}else{CBitmap * OldBitmap = MemDC.SelectObject(&bitmap);pDC->StretchBlt(0,0,bmp.bmWidth+10,bmp.bmHeight+10,&MemDC,0,0,bmp.bmWidth,bmp.bmHeight,SRCAND);MemDC.SelectObject(OldBitmap);/*if(m_bFocus)//无鼠标+焦点pDC ->FillRect(rect,&brBk[2]);//蓝elsepDC ->FillRect(rect,&brBk[3]);//绿*/}/*for (i = 0; i< 64; i ++)brBk[i].DeleteObject();*/
}//绘制按钮的内边框
void CXPButton::DrawInsideBorder(CDC *pDC, CRect* rect)
{CPen *pLeft, *pRight, *pTop, *pBottom;if (m_bSelected && !m_bOver){pLeft = & m_InsideBoundryPenLeftSel;pRight = &m_InsideBoundryPenRightSel;pTop = &m_InsideBoundryPenTopSel;pBottom = &m_InsideBoundryPenBottomSel;}else{pLeft = &m_InsideBoundryPenLeft;pRight = &m_InsideBoundryPenRight;pTop = &m_InsideBoundryPenTop;pBottom = &m_InsideBoundryPenBottom;}CPoint oldPoint = pDC->MoveTo(rect->left, rect->bottom - 1);CPen* pOldPen = pDC->SelectObject(pLeft);pDC->LineTo(rect->left, rect->top + 1);pDC->SelectObject(pRight);pDC->MoveTo(rect->right - 1, rect->bottom - 1);pDC->LineTo(rect->right - 1, rect->top);pDC->SelectObject(pTop);pDC->MoveTo(rect->left - 1, rect->top);pDC->LineTo(rect->right - 1, rect->top);pDC->SelectObject(pBottom);pDC->MoveTo(rect->left, rect->bottom);pDC->LineTo(rect->right - 1, rect->bottom);pDC->SelectObject(pOldPen);pDC->MoveTo(oldPoint);if (m_bSelected && !m_bOver)DrawFocusRect(pDC->m_hDC,rect);
}

  

MFC按钮CXPButton类,代码阅读起来还是挺不错的相关推荐

  1. 也谈C#之Json,从Json字符串到类代码

    也谈C#之Json,从Json字符串到类代码 原文:也谈C#之Json,从Json字符串到类代码  阅读目录 json转类对象 逆思考 从json字符串自动生成C#类  json转类对象 自从.net ...

  2. 【无标题】c++ MFC图像处理CImage类常用操作代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9598974.html 我看了一下发现关于c++下的CImage图像处理类 的图像处理相关的介绍 ...

  3. VC++ 绘制线条 OnLButtonDown函数(DrawView.cpp) 利用SDK全局函数实现画线功能 利用MFC的CDC类实现画线功能 利用MFC的CClientDC类实现画线功能

    目录 绘制线条 OnLButtonDown函数(DrawView.cpp) 利用SDK全局函数实现画线功能 利用MFC的CDC类实现画线功能 利用MFC的CClientDC类实现画线功能 接上:VC+ ...

  4. 代码阅读工具学习总结

    代码阅读工具:Source Navigator和Source Insight 一.Source Insight实用技巧: Source Insight(下文的SI指的也是它)就是这样的一个东西: Wi ...

  5. 谈谈技术原则,技术学习方法,代码阅读及其它

    一.选用技术的原则 比较规范的软件开发过程要到有限的几个公司才能学到.偶现在所采用的方法都是圡方法,主程序员,测试驱动,文档和代码写在一起,原型.但基本上坚持几个原则: 在工作上以实用为主导,哪个实用 ...

  6. 谈谈技术原则,技术学习方法,代码阅读及其他的(引用)

    这篇文章是前一阵在水木BBS上和别人讨论中偶自己发言的摘编,是偶这几年开发过程完全经验式的总结.完全个人经验,供批判. 一.选用技术的原则 比较规范的软件开发过程要到有限的几个公司才能学到.偶现在所采 ...

  7. VC MFC按钮(CButton)控件

    VC MFC按钮(CButton)控件 2012年11月11日 19:15   作者:TCEO   分类:技术文章   浏览:4,298   按钮控件 1如何在按钮控件上显示图片 首先确定你要显示在按 ...

  8. 脚本病毒分析扫描专题1-VBA代码阅读扫盲、宏病毒分析

    1.Office Macor MS office宏的编程语言是Visual Basic For Applications(VBA). 微软在1994年发行的Excel5.0版本中,即具备了VBA的宏功 ...

  9. 驱动、MFC项目改名、代码移植技巧,复制别人项目中的界面资源以及合并项目

    驱动.MFC项目改名.代码移植技巧,复制别人项目中的界面资源以及合并项目 驱动.MFC项目改名.代码移植技巧 复制别人项目中的界面资源 还有一种方法 双击项目中的*.rc文件,打开vs后无反应,无法打 ...

最新文章

  1. MYSQL实现ORDER BY LIMIT的方法以及优先队列(堆排序)
  2. Java里边什么是值传递和引用传递?两个有什么区别
  3. 平板电脑安装软件_概述嵌入式工业平板电脑的安装方法和注意事项!
  4. Enum,Int,String的互相转换 枚举转换
  5. pdf sdk for android,Android 自带PDF SDK
  6. 如何避免ASP.NET网页初次加载缓慢
  7. 人脸图像特征提取方法(HOG、Dlib、CNN)简述
  8. Flink 1.11 Unaligned Checkpoint 解析
  9. Qt QString to char*
  10. 爱,是尘世间人人追求的人生之最,是生活中无处不在的美
  11. cmake简洁教程 - 第五篇
  12. NB-IOT模块与MQTT.fx使用MQTT协议通讯
  13. 矩阵中的entries是什么
  14. 苹果电脑/macbookpro 拔出电源充电器但还是显示充电的解决办法
  15. 人脸识别、二维码电子签到,让会议会展入场更加智能!
  16. GitLab设置受保护的分支
  17. IPGuard忘记控制台密码处理方法
  18. gRPC(四)基础:gRPC流
  19. 用CentOS 7安装cadence搭建适合IC Design的科研环境(四)——IC617、MMSIM151、calibre2015安装过程step by step
  20. 超图控制图层的显示与隐藏

热门文章

  1. html阅读开放试用阶段,泰克为不同行业提供100种应用功能免费试用
  2. Apache httpd设置HTTPS双向认证
  3. ios 设备方向判断
  4. ad远程控制用户计算机,远程控制电脑|远程控制计算机|怎样远程控制电脑 - ManageEngine Remote Access Plus...
  5. mysql server远程连接_MySql server:开放mysql远程连接
  6. php jquery教程下载,jquery怎么下载和引用
  7. mysql可视化导入csv文件_我们如何将数据从.CSV文件导入MySQL表?
  8. c语言逆序输出字符串指针,菜鸟求助-如何用指针法将一串字符按单词的倒序输出?如:i love yo...
  9. wordcount代码_Scala小案例之wordcount
  10. 计算机基础知识精品课程,计算机应用基础精品课