前面写过两篇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);
}