本文根据本人在项目中的应用,来谈谈CListCtrl的部分用法及技巧。当初学习时,查了不少资料,零零碎碎的做了些记录,如今主要是来作个总结,方便之后查阅。主要包括如下十三点内容:基本操做、获取选中行的行号、复选框操做、动态设置选中行的字体颜色、设置选中行的背景颜色、禁止拖动表头、让第一列居中显示、设置行高与字体、虚拟列表技术、点击表头时进行归类、向上与向下移动、动态调整大小问题、避免闪烁问题。编程
分为两篇来进行总结。本篇重点总结:基本操做、获取选中行的行号、复选框操做、动态设置选中行的字体颜色、设置选中行的背景颜色windows
分别从下面四点来介绍CListCtrl的基本操做:函数
①设置列表视图显示方式学习
Ⅰ. CListCtrl有四种样式:LVS_ICON、LVS_SMALLICON、LVS_LIST、LSV_REPORT,可经过控件属性来设置。本文所述均为LSV_REPORT属性。字体
Ⅱ. 扩展样式:spa
经常使用的扩展样式有三种:LVS_EX_FULLROWSELECT、LVS_EX_GRIDLINES、LVS_EX_CHECKBOXES,分别对应做用 选中某行时使正行高亮、设置网格线、item前生成Ckeckbox控件。.net
使用SetExtendedStyle(style)函数设置扩展样式,使用GetExtendedStyle()函数获取样式,如:翻译
m_listInfo.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
Ⅲ. 使用CListView时,须要在PreCreateWindow()函数中添加 cs.style | = LVS_REPORT;code
来将其设置为LVS_REPORT风格,不然插入无效。还用另外一种方法来设置风格,即在OnInitialUpate()中获取CListCtrl控制权,而后修改风格,以下所示:orm
CListCtrl &theCtrl =GetListCtrl();
theCtrl.ModifyStyle(0, LVS_REPORT);
②插入操做
先插入列:
int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat, int nWidth, int nSubItem)
插入列时,可指明列号、列名称、列名称显示样式,列宽等信息。对于列号为0的那一列,始终是靠左显示,后面会有修改使其剧中显示的方法,其余列经过设置nFormat属性能够居中显示。
插入行:
int InsertItem( int nItem, LPCTSTRlpszItem )
直接插入一行,nItem指明行号,lpszItem指明该行第0列的信息。
设置信息:
BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText )
设置第nItem行nSubItem列的信息(nItem:0,1,2,3……; nSubItem:1,2,3……)
③删除操做
有三个操做函数:
BOOL DeleteAllItems() -------删除全部的行
BOOL DeleteItem(nItem) --------删除某一行
BOOL DeleteColumn(nCol) -----删除某一列
④获取/设置属性函数
有不少函数了,就不一一介绍了。经常使用的有
int GetItemCount() -------- 获取已插入信息的行数
BOOL SetItemState(int iLink, UINTstate, UINTstateMask ) ---------设置行状态,如高亮显示等
等等
获取选中行的行号,而后对该行进行相关处理,这点在编程中用的很是多。
当鼠标单击item时,控件向父窗口发送NM_CLICK消息,其响应函数为OnNMClickXXXX(NMHDR *pNMHDR, LRESULT *pResult),在该函数下来编写代码获取鼠标点击的行号。
有两种方法来获取行号:第一种是使用GetFirstSelectedItemPosition和GetNextSelectedItem配合来获取;第二种是先获取鼠标位置信息,而后调用HitTest函数来找出行号。示例分别以下:
第一种方法,该示例截自MSDN,可做修改后使用。
第二种方法,该示例来自个人项目,可做修改后使用。
对于LVHITTESTINFO 结构体,其有四个成员,在上述HitTest调用中,其第一个成员做为输入,另外三个做为输出。具体变量含义可查看MSDN。
有时须要在item前面添加一个CheckBox,供用户选择,而后对全部选中项进行处理。
这里涉及到两个问题:第一个,如何添加CheckBox风格;第二个,如何判断某一行的CheckBox状态是否发生改变。
对于第一个问题,在基本操做里已经有所阐述了,即经过SetExtendedStyle函数添加LVS_EX_CHECKBOXES扩展风格。
这里重点探讨第二个问题,首先,操做复选框状态的有两个函数:
BOOL GetCheck(int nItem)-------获取复选框状态
BOOL SetCheck( int nItem, BOOL fCheck = TRUE )-------设置复选框状态
其次,咱们要搞清楚如下四点:
① 当列表的项item改变时,控件会向父窗口发送LVN_ITEMCHANGED消息,所以能够在LVN_ITEMCHANGED消息的响应函数中对复选框的状态进行处理(查询或设置)。
② 鼠标点击CheckBox时,消息的顺序是 NM_CLICK —> LVN_ITEMCHANGED,即CheckBox的状态是在 NM_CLICK消息函数结束后才会发生变化,在NM_CLICK中使用GetCheck无效。
③ 鼠标点击Item(非CheckBox区域)时,消息的顺序是 LVN_ITEMCHANGED —> NM_CLICK。
④ 调用InsertItem 函数时,也会产生LVN_ITEMCHANGED消息。鉴于此,一般会自定义一个BOOL型变量m_bHit 来判断是点击操做仍是插入操做,该变量初始赋FALSE,当有鼠标点击item时赋TRUE, 检测完是否有CheckBox被点击后从新复位为FALSE。
示例以下所示:
有时可能须要设置某行的文字为特殊颜色,以表示某种特殊含义,好比正在下载的信息用绿色,暂停下载的用灰色。
首先,给出一个CodeProject的连接,这篇文章讲的很是好,主要是利用Custom Draw。http://www.codeproject.com/Articles/79/Neat-Stuff-to-Do-in-List-Controls-Using-Custom-Dra
而后,来谈谈个人方法,这里主要谈对选中行的字体颜色进行动态修改,固然也是我经过上面文章和本身实践结合得出的。
咱们须要搞清楚如下几点(能够结合下面修改某一行的字体颜色的方法来看):
① 当控件绘制时,会发送NM_CUSTOMDRAW 消息,该消息的消息响应函数为
②其中,pNMHDR为输入参数,其指向NMLVCUSTOMDRAW结构体,该结构包含了不少信息,包括字体颜色、背景等等,特别是第一个成员,为NMCUSTOMDRAW结构体变量,其包含了Current drawing stage(不知道怎么编译比较好),其可能的值以下图(截自MSDN)所示
③ pResult为输出参数,该参数决定了接下来向windows发送什么消息(与绘制有关的),经过发送该消息咱们能够进入下一步须要的处理阶段。具体输出哪一个值取决于Current drawing stage,其可能的值以下图(截自MSDN)所示
④ 有一点必须注意(英文的,我以为看起来比翻译过来更精确):
One thing to keep in mind is you must always check the draw stage before doing anything else, because your handler will receive many messages, and the draw stage determines what action your code takes.
下面咱们来看看如何修改某一行的字体颜色:
① 首先,咱们应该明白要修改字体颜色,应该在pre-paint 阶段来完成
② 所以,在消息响应函数中,咱们首先判断是否处于pre-paint stage(即pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT),而后经过修改输出值pResult 的值来通知windows咱们须要处理每一个item的消息(即设置 *pResult = CDRF_NOTIFYITEMDRAW)。
③ 再次进入消息响应函数时,咱们判断是否处于Item的pre-paint stage(即pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT),若是是则进行相关处理,即修改字体颜色等等。
④ 处理完了后从新设置 *pResult = CDRF_DODEFAULT,表示咱们再也不须要其余特殊的消息了,默认执行便可。
示例以下:
上面谈的方法主要用于设置静态字体颜色,固然,若是你的列表的信息在不断变化(即用SetItemText不断修改),那么也就实现了动态改变了,不然须要在合适的地方调用重绘函数:
BOOL RedrawItems( int nFirst, int nLast )
表示在nFirst和nLast之间的行须要进行重绘。
设置选中行的背景颜色,能够将选中行以特殊颜色显示,容易明白当前处理的是哪一行。尽管有高亮,可是高亮是基于焦点的,若是你选中了某一行,而后焦点转移了,这是就没法判断你选的是哪一行了。
设置选中行的背景颜色的方法和第四节中讲的修改字体颜色的方法是类似的,都是利用Custom Draw。这里涉及到设置当前选中行为特殊颜色,同时要恢复前一次选中行的颜色,不然就乱了。所以须要记录前一次选中行、当前选中行的行号,相信经过前面的总结,这点并不难实现。而后在当前选中行和前一次选中行之间进行重绘便可。
示例以下: