重写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个画笔对象,用于绘制图形时指定颜色。为了其中可以实现鼠标拖动和鼠标移开以及初始形状设置,我重写了OnPaintOnMouseMoveOnMouseLeave以及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的时候没法改变其他数据;若是有描述不当的地方,请告诉我哦!

原文地址:https://www.cnblogs.com/zuixime0515/p/12166101.html

时间: 2024-10-21 20:48:02

重写MFC的CSliderCtrl 控件的相关文章

MFC动态创建控件及添加消息响应

MFC动态创建控件及添加消息响应 分类: 控件技术2013-01-24 14:12 7020人阅读 评论(0) 收藏 举报 转载地址:http://blog.csdn.net/luy3728000/article/details/8193918 动态控件是指在需要时由Create()创建的控件,这与预先在对话框中放置的控件是不同的. 一.创建动态控件: 为了对照,我们先来看一下静态控件的创建. 放置静态控件时必须先建立一个容器,一般是对话框,这时我们在对话框编辑窗口中,从工具窗口中拖出所需控件放

MFC之ComboBox控件

添加内容 ComboBox_AddString(hwndCtl,lpsz) hwndCtl为此组合框的句柄,lpsz为需要添加的字符串,组合框不能直接通过id添加内容,所以需要得到这个控件的句柄,还得使用GetDlgItem()函数. 举例: HWND hwndCombo1 = GetDlgItem(hwnd,IDC_C1); //建立一个组合框,ID可以设置为IDC_C1,然后通过GetDlgItem获取这个组合框的句柄 //如果无法正常显示,需要调整此组合框的最大显示范围,在向下箭头上出现上

MFC可视化 列表控件的使用

1.应该加入头文件 #include <Atlbase.h> 2.示例 类向导给列表控件绑定变量m_list DWORD   dwExStyle=LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP|LVS_EX_ONECLICKACTIVATE|LVS_EX_FLATSB; m_list.ModifyStyle(0,LVS_REPORT|LVS_SINGLESEL|LVS_SHOWSELALWAYS);m_list.SetEx

VC/MFC 在ListCtl 控件中随鼠标移动提示单元格信息

[cpp] view plaincopy BEGIN_MESSAGE_MAP(CTipListCtrl, CListCtrl) //{{AFX_MSG_MAP(CTipListCtrl) ON_WM_MOUSEMOVE() ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTipLis

VC2005从开发MFC ActiveX ocx控件到发布到.net网站的全部过程

开篇语:最近在弄ocx控件发布到asp.net网站上使用,就是用户在使用过程中,自动下载安装ocx控件.(此文章也是总结了网上好多人写的文章,我只是汇总一下,加上部分自己的东西,在这里感谢所有在网上发表相关内容的朋友们.) ActiveX控件用于Web的过程是将控件嵌入主页中,用户通过浏览器访问该主页时,将主页中的控件下载,并在用户机器上注册,以后就可在用户的浏览器上运行.控件下载一次后就驻留在用户本地机器上,下次再访问相同的主页时,可不再下载该控件,而是直接运行用户本地的控件.这里控件容器就是

MFC标签页控件的使用

MFC标签页控件的使用 1.在对话框中添加一个标签页控件,并为此控件关联一个CTabCtrl类变量m_tabctrl. 2.创建若干个对话框资源作为标签页控件的标签. 修改两个属性: Border:    none   // 边界为空,这样它就没了标题栏 Style:      Child   // 这个模板就可以当作另一个窗口的子窗口了在对话框的初始化函数 3,在对话框的初始化函数OnInitDialog中, 添加初始化标签页控件的代码 3.1)  // 添加标签页,并设定标签名     m_

[VC/MFC]虚拟列表控件

[VC/MFC]虚拟列表控件 一.什么是虚拟列表控件 虚拟列表控件是指带有LVS_OWNERDATA风格的列表控件.. 二.为什么使用虚拟列表控件 我们知道,通常使用列表控件CListCtrl,需要调用InsertItem把要显示的数据插入列表中,之后我们就不必关心数据在哪里了,这是因为控件自己开辟了内存空间来保存这些数据.现在假设我们要显示一个数据库,里面的信息量很大,有几十万条记录.通常有两种方法解决这个问题:1是仅仅在ListCtrl中插入少量的数据,比如100个,然后通过[上一页][下一

MFC中Listbox控件的简单使用

MFC中listbox控件是为了显示一系列的文本,每个文本占一行.   Listbox控件可以设置属性为: LBS_CHILD   :(默认)子窗口 LBS_Visible :(默认)可视 LBS_Multiplesel :可选择多行 LBS_Extendedsel :可以使用shift或ctrl选择多行 LBS_SORT:所有行按字母顺序进行排序   对Listbox进行操作: Int listbox.AddString (  LPCTSTR     Str)   :对listbox的首行添加

基于wince的MFC Tab Control控件的使用

1,先建立一个对话框MFC应用程序,然后在工具箱里面把Tab Control控件放到对话框中的合适位置上. 再在对话框类中,声明一个CTabCtrl变量: CTabCtrl m_tab; 变量m_tab用来与对话框中的Tab Control控件交互,为此要在DoDataExchange函数中加入DDX_Control语句: 1 //{{AFX_DATA_MAP(CTABDlg) 2 DDX_Control(pDX, IDC_TAB, m_tab); 3 //}}AFX_DATA_MAP IDC_