写点什么

MFC|框架下按钮的自绘

  • 2022 年 7 月 16 日
  • 本文字数:2076 字

    阅读完需:约 7 分钟

今天我们讲解的是 MFC 框架下 CButton 的自绘。

前提:

我们在做界面时,尤其是做测试功能时,大多数情况都是点击一个按钮,显示出要测试的功能。

这时候,我们是不需要优化按钮的显示的。

但是,当我们在实际开发时,只是在按钮上显示文本这种功能已经不能满足我们的需求了,甚至有些时候会显示图片。

接下来我们就会 CButton 控件的自绘进行说明吧!

对于按钮这个控件,还是有一些特殊的。

这些特殊点是在哪里呢?

我们想要对 CButton 上的文字进行更换颜色,这是不能做到的,除非你重写 DrawItem 函数。

只能做到的是修改字体的风格。

所以,我们直接来讲解下如何重写 DrawItem 进行控件重绘。

显示效果实现:

实现功能:按钮文字、背景四态变化

四态包含了:常态、聚焦、按下、禁用

重绘 CButton 的机制是在 DrawItem 中实现的,与前一个控件 CStatic 的介绍不一致(在 OnPaint 中重绘)哦~大家记得要区分开。

虽然重绘的函数不一致,但是实现的套路都是一样的。

实现思路如下:

第一步:设置字体

第二步:设置四态背景图片

第三步:设置文本风格

注意:我们在任何重绘的时候,一定要记得需要先绘制图片再绘制文本!!

绘制字体

CFont		*font = GetFont();CFont		*OldFont = dc.SelectObject(font);
复制代码

绘制四态文字颜色、背景

这里我们可以用一个成员变量来记录按钮的四种状态,假设定义一个枚举类型。

enum ENUM_ButtonState{   ButtonState_Normal, //常态   ButtonState_Focus,  //聚焦   ButtonState_Press, //按下   ButtonState_Disable, //禁用};
复制代码

我们使用 switch 的方式,根据当前按钮的状态,更换背景以及文字的颜色值

switch(m_enumState){case ButtonState_Normal:{}break;case ButtonState_Focus:{}break;case ButtonState_Press:{}breaks;case ButtonState_Disable:{}break;}
复制代码

风格:常态

假设当前是按钮常态风格,m_enumState = ButtonState_Normal

按钮常态有一些繁琐,包含了两种风格

1:鼠标按下后,鼠标离开了按钮,此时需要显示按下图片效果

2:只是普通的显示

为了实现功能 1 的实现,我们需要定义一个是否按下状态的标识,

当鼠标移开控件时,且当前是按下状态以及鼠标是不是跟踪状态?如果是,属于风格 1,否则属于风格 2

实际代码实现,如下:

switch(m_nbuttonState){case 0:   //常态{	//当鼠标离开后,并且是按下状态时,常态也是按下状态	if (m_bcheck == TRUE  && m_bOver == FALSE && m_bTwoStatesFlages == true)	{		pDC->SetTextColor(m_crColorDown);                pDC->SetBackColor(m_crBackDown);	}	else	{		pDC->SetTextColor(m_crColorNormal);                pDC->SetBackColor(m_crBackNormal);	}}break;
复制代码

风格:按下

风格:聚焦

风格:禁用


以上三种风格,与常态的相比会比较简单了,只是做文本颜色值以及图片的替换而已。这里也就不做说明了。

绘制文字风格

文字风格只是根据文本的风格:靠左、靠右、居中以及垂直居中的设置。

使用 DrawText 等方式绘制。

按钮四态更改

想要实现按钮风格的四态变化,我们需要重写按钮的对应消息

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnMouseHover(UINT nFlags, CPoint point);
afx_msg void OnMouseLeave();
复制代码

鼠标按下消息操作

思路:

前提,当前状态是禁用时,不做任何处理

其次,鼠标按下,更改按钮状态枚举类型并设置选中状态

m_enumState = ButtonState_Press;


更改状态后刷新控件

if (!(m_nbuttonState == ButtonState_Disable))  //此时不是禁止时{	m_bcheck = TRUE;	m_nbuttonState = ButtonState_Press;		//此时按钮为按下状态	RefreshButtonStatus();	Invalidate(FALSE);}
复制代码

鼠标移动消息操作

思路:

当前鼠标不是跟踪状态时,需要设置跟踪状态。


if (!m_bTracking)  {    m_bOver = TRUE;    TRACKMOUSEEVENT tme;    ZeroMemory(&tme , sizeof(TRACKMOUSEEVENT) );  tme.cbSize = sizeof(TRACKMOUSEEVENT);    tme.hwndTrack = this->GetSafeHwnd() ;    tme.dwFlags = TME_LEAVE | TME_HOVER;    tme.dwHoverTime = 1;    if(::_TrackMouseEvent(&tme) )    m_bTracking = TRUE;}
复制代码

鼠标聚焦操作

在按钮中做鼠标聚焦操作时,用到的是 OnMouseHover 消息

思路:

只有在不是禁用状态时,按钮的状态改变才会生效。

if ( m_nbuttonState != ButtonState_Disable ){  m_nbuttonState = ButtonState_Focus;//聚焦  RefreshButtonStatus();}m_bOver = TRUE;
Invalidate(FALSE);
复制代码

鼠标离开操作

思路:

当状态不是禁用时,将状态更改成常态

在鼠标离开控件后,需要将跟踪状态设置成不跟踪

if ( m_nbuttonState != ButtonState_Disable){  m_nbuttonState = ButtonState_Normal;  RefreshButtonStatus();}m_bOver = FALSE;m_bTracking = FALSE;Invalidate(FALSE);
复制代码

总结:

根据以上对按钮的四种相应操作就可以实现四态变化了!

难点:

在绘制过程中,根据不同的消息做不同的相应操作以及更换状态标识这里绘制的难点。


今天的讲解就到这里了!

我是中国好公民 st,一名 C++开发程序媛~

发布于: 刚刚阅读数: 3
用户头像

书山有路勤为径,学海无涯苦作舟 2022.07.01 加入

擅长语言:C++ 涉及语言:Python

评论

发布
暂无评论
MFC|框架下按钮的自绘_c++_中国好公民st_InfoQ写作社区