今天我们讲解的是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);
根据以上对按钮的四种相应操作就可以实现四态变化了!
难点:
在绘制过程中,根据不同的消息做不同的相应操作以及更换状态标识这里绘制的难点。
今天的更新就到这里了~
我是糯诺诺米团,一名C++开发程序媛~