CListCtrl控件功能扩展总结(三)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

  前面写过两篇CListCtrl控件的开发总结,最近在开发和应用当中又发现了几个比较有趣的问题,主要是关于自绘滚动条的。从我的感觉来说,做CListCtrl控件(我们一直在讨论report风格)的自绘滚动条是比较复杂的,因为里边有很多特殊的地方,很可能会让你备受挫折。
   
    先说一下实现自绘滚动条的思路。首先要隐藏CListCtrl自带的滚动条,如果你简单的认为加上LVS_NOSCROLL风格就能搞定的话,你一定会大失所望,具体我们后面会讲到。然后就是要封装自己的滚动条控件了,考虑到有竖直滚动条和水平滚动条两种,我们的封装可能还要费一番周折。除了要响应消息自绘外,滚动条控件还要向parent控件(即CListCtrl)发送相应的WM_VSCROLL和WM_HSCROLL消息及消息参数。
最后,CListCtrl控件要响应这两个消息并进行相应处理,这个过程需要清楚地理解SCROLLINFO结构体中各个变量含义并进行应用,另外就是处理一些UI绘制和刷新上的麻烦。
    好了,下面我们就重点总结一下上面过程中会遇到的难题,并给出解决方法。

 

    一、隐藏CListCtrl自带滚动条
    CWnd类有一系列的关于Scroll的函数,感觉好像有很多方法可以实现我们的目的。
    1、调用EnableScrollBarCtrl直接将不需要的类型的滚动条disable掉;
    2、调用GetScrollBarCtrl得到滚动条指针,然后用ShowWindow(SW_HIDE)将其隐藏掉;
    3、调用ShowScrollBar直接隐藏。
    遗憾的是,对于report类型的CListCtrl来说,上面的方法全部无效。(好像对于其他非report类型的CListCtrl控件或者CListView控件有些方法是有效的,没有进行具体验证。)其实用spy++查看一下就知道,CListCtrl中的滚动条根本不是窗口,也就是说滚动条不是scroll bar控件,只是CListCtrl自行绘制上去的假滚动条。因此上面这些对于scroll bar操作的函数都无效也就可以理解了,大家可以留意一下GetScrollBarCtrl函数返回的全是NULL。

    那么我们能不能通过修改CListCtrl的窗口风格来实现呢?
    涉及到滚动条的风格有两个,一个是通用的窗口风格WS_HSCROLL和WS_VSCROLL,另一个是列表控件专有风格LVS_NOSCROLL。
    先说LVS_NOSCROLL。如果你给CListCtrl设置该风格的话,你会发现list中关于scroll的窗口过程都被屏蔽了,也就是说,CListCtrl将只显示设定的列表窗口区域,对于区域以外的包括UI显示和消息处理在内的这些过程,将全部忽略。这样的话,隐藏原有滚动条并加载自己的滚动条这个思路将行不通。而且根据MSKB ID为137520文章所说,对于report类型的列表控件,设置LVS_NOSCROLL风格还要面临header控件不能正常显示的问题。
    再来看WS_HSCROLL和WS_VSCROLL。如果只是简单的通过调用ModifyStyle去掉窗口WS_HSCROLL或WS_VSCROLL风格是没作用的,我们需要在每次重新计算窗口的客户区域的时候都调用ModifyStyle设置scroll风格才行,这样CListCtrl将没有机会自动为窗口加上滚动条,代码如下:

   

    void CXXListCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)             
    {                                                                                               
        ModifyStyle( WS_HSCROLL | WS_VSCROLL, 0 ); // 去掉水平滚动条和竖直滚动条                   
        CListCtrl::OnNcCalcSize(bCalcValidRects, lpncsp);                                          
    }                                                                                              

 

    麻烦还没完,在XP窗口风格下上面的代码没有任何问题。但是当我们链接Windows经典窗口风格的代码库时,上面的代码就不能实现隐藏滚动条的功能了。具体原因不是很清楚,我猜想可能是Windows的不同窗口风格库的内部窗口过程不同引起的。
    还有解决的办法吗?只要我们想,总会有办法!那就是调用Windows的API函FlatSB_EnableScrollBar。你只要在你的自绘listctrl类的合适的位置调用以下代码,控件的滚动条将完美地被隐藏起来,而且只需要调用一次就可以:


    InitializeFlatSB(this->m_hWnd);                                                 
    FlatSB_EnableScrollBar(this->m_hWnd, SB_BOTH, ESB_DISABLE_BOTH);                 


    具体关于该函数的细节大家可以去查阅MSDN,但是我并没有想明白为什么这个API函数能做到EnableScrollBarCtrl成员函数做不到的功能,没有源码无从考证:(

 

    二、结构体SCROLLINFO
    在这里我并不想过多讨论关于自绘滚动条控件的实现问题,因为看上去思路很简单,并且实现起来也只是细节和完善性的工作。我认为这一块的问题在于一些概念的理解和把握,其中最重要的就是结构体SCROLLINFO。
    首先说一下GetScrollInfo和SetScrollInfo这两个函数。CListCtrl类和CScrollBar类都有这两个成员函数,其中CListCtrl类的成员函数是从CWnd继承而来。对于CScrollBar类来说,GetScrollInfo用来得到滚动条的滚动信息,也就是结构体SCROLLINFO中包含的内容;SetScrollInfo用来设置滚动信息使滚动条进行相应的滚动。我们可以理解为CScrollBar类通过这两个函数完成滚动条正确的位置滚动和绘制。前面提到,CListCtrl控件自带的滚动条并不是CScrollBar控件,而是自己画上去的假窗口,因此实际上是通过CLIstCtrl的GetScrollInfo和SetScrollInfo函数完成了滚动条位置信息的查询和设置。而且在CListCtrl中,这些信息是有其特殊性的,后面讲SCROLLINFO的时候会详细说明。
    那么当我们把CListCtrl的滚动条隐藏了,甚至用API将其disable了,GetScrollInfo和SetScrollInfo还会正常工作吗?回答是肯定的。用CListCtrl自带的滚动条和用自己封装的滚动条的区别在于:
    1、用CListCtrl的滚动条,可通过GetScrollInfo查询滚动信息,通过SetScrollInfo可使滚动条调整位置,且list客户区会自动滚动;用户通过操作滚动条可以滚动list客户区,且改变list的滚动信息;
    2、用自己的滚动条,调用CListCtrl的GetScrollInfo可查询滚动信息,通过SetScrollInfo可设置滚动信息但滚动条控件不会自动调整位置,但list客户区可以自动滚动;用户操作滚动条,需要通过调用CScrollBar的SetScrollInfo进行设置才能影响滚动条绘制,而list客户区不会自动滚动,此时list的滚动信息不会被自动修改。
    因此,加自己的滚动条实际上是将list和滚动条的滚动信息一致化的问题。或者你也可以完全抛弃CListCtrl中保存的SCROLLINFO信息,完全用scroll bar的信息。无论哪种方法,都必须对结构体SCROLLINFO中的参数意义有比较深刻的理解。

 

    SCROLLINFO的定义如下:
    typedef struct tagSCROLLINFO
    {
        UINT    cbSize;
        UINT    fMask;
        int     nMin;
        int     nMax;
        UINT    nPage;
        int     nPos;
        int     nTrackPos;
    }   SCROLLINFO, FAR *LPSCROLLINFO;
    typedef SCROLLINFO CONST *LPCSCROLLINFO;

 

    cbSize是该结构体的字节数,每次应用之前设置为sizeof(SCROLLINFO);
    fMask指明下面的几个参数哪些是有效值,具体请参考MSDN;
    nMin和nMax指明了滚动条最小和最大滚动位置。字面上很好理解,但是这个位置以什么为单位呢?MSDN上并没有说明。其实单位并没有规定和限制,只要在这个结构体的参数中统一就可以。比如在CListCtrl中就以控件中的行为单位,nMin为0,nMax一般为list的总行数。
    nPage为页大小,也就是你点击滚动条上滑块以外的区域时,滚动条会滚动一页,而页的大小就是由该值指定;同时,滚动条绘制滑块的大小时也会依据此值;
    nPos为滑块当前的位置,也就是滚动位置;
    nTrackPos是用户拖动滑块时的即时位置,该值一般用于响应滚动条消息时与SB_THUMBTRACK消息一起作为消息参数,而不能用于设置滚动条信息。
   
    OK,现在可以完善我们的思路了。加载自绘滚动条的步骤如下:
    1、隐藏CListCtrl原有滚动条;
    2、封装继承于CScrollBar的自绘滚动条控件,根据SCROLLINFO完成滚动条绘制,并将用户操作封装成WM_HSCROLL或WM_VSCROLL消息传递给父类CListCtrl。以竖直滚动条为例,我们要将WM_VSCROLL消息的消息参数分为以下几类:SB_LINEDOWN,SB_LINEUP,SB_PAGEDOWN,SB_PAGEUP,SB_THUMBTRACK和SB_THUMBPOSITION,其意义分别为向下移动一个位置,向上移动一个位置,向下移动一页,向上移动一页,滑块当前正在被拖动的位置和滑块被结束拖动到某位置。CListCtrl接收到消息以后需要根据类型调用滚动条的SetScrollInfo设置滚动信息,使滚动条绘制滚动位置,并调用Scroll函数滚动list的客户区;
    3、ClistCtrl子类负责初始化滚动条控件,设置控件尺寸及位置,并响应OnSize函数随时改变控件大小位置。还要响应WM_MOUSEWHEEL消息使滚动条控件进行正确滚动。当然还有刚才提到的接收滚动条控件的消息,并进行相应处理。

    看上去应该没什么问题了,但是你还是会遇到一些麻烦。

 

    三、SB_THUMBTRACK和SB_THUMBPOSITION
    滚动条控件的消息码是在OnVScroll或OnHScroll响应函数中作为nSBCode参数被传递的,指明了当前的操作类型。但是对于CListCtrl来说,以上两个消息码却比较特殊,因为在CScrollBar中给CListCtrl发送带有这两个消息码的消息,响应函数并不会做出响应。也就是说,CListCtrl内部自动处理了该消息,并没有调用OnVScroll或OnHScroll做响应。具体为什么这样设计,可能是出于某种考虑;但是如果我们要对这两个操作自己特有的处理,或者我们应用的SCROLLINFO中的单位与CListCtrl默认的不统一的话,list的默认响应将满足不了我们的需要。
    要解决这个问题,可以自己定义新的消息码来代替。
   
    四、滚动条绘制问题
    当你按照上面步骤写好代码,操作滚动条的时候,你可能失望的看到你的滚动条并不能正确绘制,而且现象很特别,好像是绘制函数出了问题。
    如果要深入的理解这个问题的原因,可以看一下我前面写的一篇博文——“Windows窗口相关的一些概念解释”。简单一点说,就是CListCtrl的窗口风格没有设置正确。我们自己的滚动条肯定是要时刻保持在list窗口的上方,因此我们需要在CListCtrl中写上这样的代码:


    scrollCtrl.Create(WS_CHILD|WS_VISIBLE|WS_GROUP|SBS_VERT, scrollRect, this, ID_SCROLL_XX);
    scrollCtrl.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);  


    可以看到,滚动条控件是作为list窗口的子窗口被创建的,而且被放在窗口的z-order的最上方,因为它一定在list窗口及其子窗口的最上面显示。如果这个时候你的list窗口是自绘控件,或者说上面放置了其他控件作为子窗口,那么滚动条的刷新一定会出问题,原因是因为你没有给滚动条控件设置WS_CLIPSIBLINGS风格。
    这样可以了吗?此时你还要为CListCtrl子类加上WS_CLIPCHILDREN风格,原因是你的滚动条控件是顶层窗口,系统会认为在刷新list窗口时它是不用刷新的,这样滚动条和list窗口重合的部分在刷新上会出现问题;当我们给list窗口设置了WS_CLIPCHILDREN风格之后,系统就会在list窗口刷新时告诉重合区域不用重画,从而保证滚动条绘制正确。

 

    好了,几个比较关键的问题都讲完了,这篇就写到这吧。在公司写效率确实高一些,呵呵。如果有写的不正确的地方,希望大家告诉我,谢谢。

 

转自 http://blog.sina.com.cn/s/blog_48f93b530100eg3z.html

提升CListCtrl功能扩展控件深度开发指南 CListCtrl是一个在Windows编程中常用的控件,它允许开发者在应用程序中展示和管理列表。该控件常用于显示数据集合,如文件列表、数据库记录等,并支持包括排序、选择等多种交互功能CListCtrl不仅基础功能强大,同时它还提供了丰富的扩展性,使得开发者能够根据具体需求定制更高级的功能CListCtrl扩展功能通过它的消息映射和消息处理能力来实现。例如,通过响应LVN_ITEMCHANGED消息,可以捕捉到用户与列表项的交互事件。 阅读详情

相关推荐

实现带按钮功能的自定义CListCtrl控件

CListCtrlWindows编程中常用的列表视图控件,用于在界面上展示和管理数据。其提供了不同的视图模式来展示项目,如列表、图标和详细信息等。它能够处理包括文本、位图和图标在内的各种数据类型,并支持多种操作,如添加、删除、排序等。当列表项被选中或鼠标悬停时,通常会有不同的显示效果。为了实现自定义的高亮显示和选择效果,可以通过重写函数来实现。// 设置文本颜色// 设置背景颜色// 根据项的状态自定义绘制// 设置选中项的文本和背景色// 白色文本// 暗青色背景break;

weixin_42360733的博客 774

CListCtrl 自绘 含滚动条

挺不错的自绘列表框 含滚动条 分享一下

MFC中扩展CListCtrl实现单元格编辑框与下拉框功能

CListCtrl是 MFC 中用于显示和操作列表数据的核心控件之一,支持多种视图模式,如报表视图(LVS_REPORT)、图标视图(LVS_ICON)等。在报表视图下,可通过和InsertItem方法构建表格结构,并使用填充单元格内容。m_listCtrl.InsertColumn(0, _T("姓名"), LVCFMT_LEFT, 100);m_listCtrl.InsertItem(0, _T("张"));

weixin_35756690的博客 1203

CListCtrl控件功能扩展总结

<br />文章来源: http://blog.sina.com.cn/s/blog_48f93b530100eg3z.html<br /> <br /> <br /> <br />    前面写过两篇CListCtrl控件的开发总结,最近在开发和应用当中又发现了几个比较有趣的问题,主要是关于自绘滚动条的。从我的感觉来说,做CListCtrl控件(我们一直在讨论report风格)的自绘滚动条是比较复杂的,因为里边有很多特殊的地方,很可能会让你备受挫折。<br />   <br />    先说一下实现自绘滚

xdsoft365的专栏 1149

怎么隐藏滚动条?

一般来说,有以下方法:1:设置滚动大小为0 void CYourView::OnInitialUpdate(){CFormView::OnInitialUpdate();SetScrollSizes(MM_TEXT, CSize(0, 0));//加上这句就没有了。}2:InitializeFlatSB(m_hWnd);FlatSB_EnableScrollBar(m_hWnd,

liyonghust的专栏 2304

windows标准控件

使用Windows标准控件 我们在前面曾提到过,控件是一些行为标准化了的窗口,一般用于对话框或其它窗口中充当与用户交互的元素。在Visual C++中,可以使用的控件分成类: (1) Windows标准控件 Windows标准控件Windows操作系统提供,在Windows 95中还提供了一些新增的控件。所有这些控件对象都是可编程的,我们可以使用Visual C++提供的对话框编辑...

weixin_30875157的博客 643

winForm中如何控制listView的滚动条高手请进

this.lvwInfoList.EnsureVisible(this.lvwInfoList.Items.Count   -   1);//自动滚动到指定行

weixin_34324081的博客 1477

windows的滚动条使用

背景 在毕业快一年的工作时间中,对windows编程的某些特性并不够熟悉,例如滚动条的使用。在一次需求中需要用到滚动条,在开发过程中走了不少弯路,因此需要做一些笔记总结一下学习到的内容。 先推荐几个写的特别好的博客: Windows编程之滚动条—滚动条消息 C语言Windows程序设计-> 第八天-> 滚动条 Windows编程之滚动条—滚动条信息函数 基本滚动条的使用是...

alcc34716的博客 458

CListCtrl控件功能扩展(滚动条)总结

CListCtrl控件功能扩展(滚动条)总结()<br />C++学习笔记2010-04-01 10:51:11阅读151评论0  字号:大中小 订阅<br />转自http://blog.sina.com.cn/s/blog_48f93b530100eg3z.html<br />前面写过两篇CListCtrl控件的开发总结,最近在开发和应用当中又发现了几个比较有趣的问题,主要是关于自绘滚动条的。从我的感觉来说,做CListCtrl控件(我们一直在讨论report风格)的自绘滚动条是比较复杂的,因为里边有

dehuadeng的专栏 1万+

CListCtrl控件功能扩展:让列表控件更具交互性

CListCtrl控件功能扩展:让列表控件更具交互性 去发现同类优质开源项目:https://gitcode.com/ 项目核心功能/场景 为CListCtrl控件添加编辑框、下拉列表框和时间控件,提升用户交互体验。 项目介绍 在软件开发中,列表控件ListCtrl)是界面设计中常用的元素之一,用以展示数据列表。然而,标准的CListCtrl控件功能上具有一定的局限性,尤其是在用户交互方面。为...

gitblog_06754的博客 360

实现CListCtrl控件内嵌Checkbox的全教程

本文还有配套的精品资源,点击获取 简介:本文介绍在MFC应用程序中如何使用CListCtrl控件实现内嵌Checkbox的功能,以支持用户进行多选操作。我们将涵盖初始化控件、添加列表项、处理用户交互、自定义表头以及扩展控件功能。同时,我们也会解析可能包含复选框功能实现的代码文件,以及如何将这些功能融入到Windows应用界面中,提升用户体验。 1. MFC CLis...

weixin_28988985的博客 1817

CListCtrl控件功能扩展

CListCtrl控件功能扩展 去发现同类优质开源项目:https://gitcode.com/ 简介 本仓库提供了一份详尽的资源文件,主要内容包括如何在CListCtrl中添加编辑框、下拉列表框以及时间控件。通过这份资源,开发者可以有效地扩展CListCtrl控件功能,提升用户交互体验。 资源描述 资源文件详细介绍了CListCtrl控件在原有基础上,通过添加编辑框、下拉列表框和时间控件的方法...

gitblog_06774的博客 380

著名的TreeGridCtrl控件源码基于CLISTCTRL:项目的核心功能/场景

著名的TreeGridCtrl控件源码基于CLISTCTRL:项目的核心功能/场景 去发现同类优质开源项目:https://gitcode.com/ 基于CLISTCTRL的TreeGridCtrl控件源码,实现树形与表格的完美融合。 项目介绍 在现代软件开发领域,数据展示控件的灵活性和功能多样性至关重要。TreeGridCtrl控件源码,正是针对这一需求精心设计的一款控件。它基于CLISTCTR...

gitblog_06709的博客 570

CListCtrl控件

CListCtrl控件 (2007-04-14 11:50:38)   分类:VC++常用控件操作通过这片播客,你可以获得一下信息:1. CListCtrl 样式及设置2. 扩展样式设置3. 数据插入4. 一直选中Item5. 选中和取消选中Item6. 得到CListCtrl中所有行的checkbox的状

海边的猪 1695
上一篇: 使用D3D渲染YUV视频数据
下一篇: 调试Release发布版程序的Crash错误(二)(
maikforever
博客等级 码龄17年 191粉丝 94原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值