重写MFC的CSliderCtrl 控件
Posted zuixime0515
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重写MFC的CSliderCtrl 控件相关的知识,希望对你有一定的参考价值。
需要的控件演示效果
默认的光标是蓝色
当鼠标悬浮在slider或者拖动的时候则是白色
整个控件的显示效果具体如图1-1,描述了整个控件需要的UI效果
实现原理
MFC自带的CSliderCtrl控件UI个人觉得比较不美观,为了实现个性化的slider控件绘制,用户常常需要自己重写slider控件,其中也有很多种不同的写法,下面我就将自己的一种实现写出来,若是有不当的地方则请指出,我一定会好好修改。为了更清楚地知道重写需要重写哪些函数以及CSliderCtrl的一些接口,需要查看相关的MSDN文档,这是我自己当时重写的查看的官方文档链接,CSliderCtrl官方参考文档。
定义控件需要的颜色
控件的颜色设置在控件演示效果中已经说明了,默认的光标是蓝色,其他时候则是灰白色,所以我会预先定义这两种颜色,分别是蓝色和灰白色,具体的颜色定义如下所示:
#define G_BASE_CCCCCC RGB(204,204,204)
#define G_BASE_0078D6 RGB(0, 120, 214)
#define TRACK_HOVERTHUMB_COLOR G_BASE_CCCCCC
#define TRACK_DEGAULTTHUMB_COLOR G_BASE_0078D6
重写CSliderCtrl类
为了实现自己定制的Slider控件效果,需要继承CSliderCtrl类,并且改写其中的几个方法,在这个类中我分别定义了2个笔刷和2个画笔对象,用于绘制图形时指定颜色。为了其中可以实现鼠标拖动和鼠标移开以及初始形状设置,我重写了OnPaint、OnMouseMove、OnMouseLeave以及OnEraseBkgnd方法。具体的头文件定义如下:
class MySlider: public CSliderCtrl
{
DECLARE_DYNCREATE(MySlider)
public:
MySlider();
virtual ~MySlider();
virtual void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
protected:
afx_msg void OnPaint();
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnMouseLeave();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
DECLARE_MESSAGE_MAP()
private:
bool m_bHoverThumb;
CBrush m_hoverBrush;
Cpen m_hoverPen;
CBrush m__defaultBrush;
CPen m_defaultPen;
}
上面是关于slider控件的实现定义,下面则是实现这些方法,代码不多,也很方便阅读^^。
BEGIN_MESSAGE_MAP(MySlider, CSliderCtrl)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_MOUSEMOVE()
ON_WM_MOUSELEAVE()
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
END_MESSAGE_MAP()
IMPLEMENT_DYNCREATE(MySlider, CSliderCtrl);
MySlider::MySlider(): m_hoverBrush(TRACK_HOVERTHUMB_COLOR),m_hoverPen(PS_SOLID, 1, TRACK_HOVERTHUMB_COLOR), m_defaultBrush(TRACK_DEGAULTTHUMB_COLOR), m_defaultPen(PS_SOLID, 1, TRACK_DEGAULTTHUMB_COLOR){
m_bHoverThumb = FALSE;
}
MySlider::~MySlider(){}
void MySlider::OnPaint()
{
CClientDC dc(this);
CSliderCtrl::OnPaint();
// 这里分别绘制thumb左边和右边,两边分开绘制
CRect rect,rectaimL,rectaimR;
GetChannelRect(&rect);
rectaimL = rect;
rectaimR = rect;
GetThumbRect(&rect);
rectaimL.top = rect.top;
rectaimL.bottom = rect.bottom;
rectaimL.right = rect.left;
rectaimR.top = rect.top;
rectaimR.bottom = rect.bottom;
rectaimR.left = rect.right;
CBrush brush(G_EDIT_OPT_BK);
dc.FillRect(rectaimL,&brush);
dc.FillRect(rectaimR,&brush);
CBrush brushS(G_BASE_WHITE);
int rectaimH = rect.Height()/3;
rectaimL.top += rectaimH;
rectaimL.bottom -= rectaimH;
rectaimR.top += rectaimH;
rectaimR.bottom -= rectaimH;
dc.FillRect(rectaimL,&brushS);
dc.FillRect(rectaimR,&brushS);
}
void MySlider::OnCustomDraw(NMHDR * pNMHDR, LRESULT *pResult)
{
NMCUSTOMDRAW nmcd = *(LPNMCUSTOMDRAW)pNMHDR;
if ( nmcd.dwDrawStage == CDDS_PREPAINT )
{
// return CDRF_NOTIFYITEMDRAW so that we will get subsequent
// CDDS_ITEMPREPAINT notifications
*pResult = CDRF_NOTIFYITEMDRAW ;
return;
}
else if (nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
{
if ( nmcd.dwItemSpec == TBCD_THUMB )
{
*pResult = CDRF_DODEFAULT;
CBrush* pBrush = NULL;
CPen* pPen = NULL;
switch(nmcd.uItemState)
{
case 0:
if(m_bHoverThumb && IsWindowEnabled())
{
pBrush = &m_hoverBrush;
pPen = &m_hoverPen;
}
else if(IsWindowEnabled())
{
pBrush = &m_defaultBrush;
pPen = &m_defaultPen;
}
else
{
pBrush = &m_hoverBrush;
pPen = &m_hoverPen;
}
break;
case CDIS_SELECTED:
pBrush = &m_hoverBrush;
pPen = &m_hoverPen;
break;
default:
pBrush = &m_defaultBrush;
pPen = &m_defaultPen;
break;
}
CDC *pdc = CDC::FromHandle(nmcd.hdc);
CBrush * pOldBrush = pdc->SelectObject(pBrush);
CPen* pOldPen = pdc->SelectObject(pPen);
CRect rcThumb,rcChannel,rcPaint;
GetThumbRect(&rcThumb);
GetChannelRect(rcChannel);
rcPaint = rcThumb;
rcPaint.bottom = rcChannel.bottom + 1;
pdc->Rectangle(rcPaint);
pdc->BeginPath();
pdc->MoveTo(rcPaint.right, rcPaint.bottom);
pdc->LineTo(rcPaint.left, rcPaint.bottom);
pdc->LineTo(rcPaint.CenterPoint().x, rcThumb.bottom - 1);
pdc->LineTo(rcPaint.right, rcPaint.bottom);
pdc->EndPath();
pdc->FillPath();
pdc->SelectObject(pOldBrush);
pdc->SelectObject(pOldPen);
*pResult = CDRF_SKIPDEFAULT;
}
}
}
void MySlider::OnMouseMove(UINT nFlags, CPoint point)
{
CRect rc;
GetThumbRect(&rc);
if(rc.PtInRect(point))
m_bHoverThumb = TRUE;
else
m_bHoverThumb = FALSE;
CSliderCtrl::OnMouseMove(nFlags, point);
}
void MySlider::OnMouseLeave()
{
m_bHoverThumb = FALSE;
CSliderCtrl::OnMouseLeave();
}
BOOL MySlider::OnEraseBkgnd(CDC* pDC)
{
CRect rect,rectaim;
GetClientRect(&rect);
rectaim = rect;
GetThumbRect(&rect);
rectaim.top = rect.top;
rectaim.bottom = rect.bottom;
CBrush brush(G_EDIT_OPT_BK);
pDC->FillRect(rectaim,&brush);
return TRUE;
}
重绘结束
到这里Slider重绘就结束了,自己重绘的控件的使用方法和CSliderCtrl控件使用方法是一样的,都需要注意setbuddy,不然会没法绑定数据,从而导致滑动thumb的时候没法改变其他数据;若是有描述不当的地方,请告诉我哦!
以上是关于重写MFC的CSliderCtrl 控件的主要内容,如果未能解决你的问题,请参考以下文章