MFC总结之CListCtrl用法及技巧(二)

续第一篇:MFC总结之CListCtrl用法及技巧(一) http://blog.csdn.net/zwgdft/article/details/7560592

本篇重点介绍:止拖动表头、让第一列居中显示、设置行高与字体、虚拟列表技术、点击表头时进行归类、向上与向下移动、动态调整大小问题、避免闪烁问题

6、禁止拖动表头

重载OnNotify消息响应函数,屏蔽两个消息通知码:HDN_BEGINTRACKW 和HDN_DIVIDERDBLCLICKW。示例如下:

  1. BOOL CXXXX::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  2. {
  3. // TODO: Add your specialized code here and/or call the base class
  4. //屏蔽两个消息通知码,使得禁止拖动List表头
  5. NMHEADER* pNMHeader = (NMHEADER*)lParam;
  6. if(((pNMHeader->hdr.code == HDN_BEGINTRACKW) |
  7. (pNMHeader->hdr.code == HDN_DIVIDERDBLCLICKW)))
  8. {
  9. *pResult = TRUE;
  10. return TRUE;
  11. }
  12. return CDialog::OnNotify(wParam, lParam, pResult);
  13. }

7、让第一列居中显示

在插入列时,我们可以通过参数nFormat来设置文本居中显示,但是这种设置对于第一列是没有作用的。这时我们可以考虑将我们的内容从第二列开始插入(设置为居中显示)。先插入第一列,然后删除第一列,这样原先的第二列就充当了第一列。

8、设置行高和字体

设置CListCtrl的行高没有函数接口,可以通过自绘来实现,但是比较麻烦。有一个比较简单的方法是通过使用一个空白的图像将行撑起来,使其高度发生变化。示例如下:

  1. CImageList m_image;
  2. m_image.Create(1,24,ILC_COLOR32,1,0);
  3. m_listInfo.SetImageList(&m_image, LVSIL_SMALL);

对于字体的设置,我们可以使用SetFont函数来实现。以修改CListView的字体为例,在OnInitialUpdate函数中插入列之前调用SetFontSelf函数(该函数自定义,如下示例所示)。首先创建一个字体,然后调用SetFont进行设置。需要注意的是,在退出时需要delete 掉创建的字体,避免内存泄露。

  1. //设置字体和大小
  2. void CMyListView::SetFontSelf(int nHeight, LPCTSTR lpszFacename)
  3. {
  4. //先删除原有字体
  5. if(m_font != NULL)
  6. delete m_font;
  7. m_font = new CFont;
  8. //创建字体
  9. m_font->CreateFont(
  10. nHeight,                   // nHeight
  11. 0,                         // nWidth
  12. 0,                         // nEscapement
  13. 0,                         // nOrientation
  14. FW_NORMAL,                 // nWeight
  15. FALSE,                     // bItalic
  16. FALSE,                     // bUnderline
  17. 0,                         // cStrikeOut
  18. ANSI_CHARSET,              // nCharSet
  19. OUT_DEFAULT_PRECIS,        // nOutPrecision
  20. CLIP_DEFAULT_PRECIS,       // nClipPrecision
  21. DEFAULT_QUALITY,           // nQuality
  22. DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
  23. lpszFacename);             // lpszFacename
  24. //设置字体
  25. CListCtrl &theCtrl = GetListCtrl();     //获取控制权,引用变量
  26. theCtrl.SetFont(m_font, TRUE);
  27. }

9、虚拟列表技术

给一个链接,介绍的比较详细:http://hi.baidu.com/qi_xian/blog/item/929b04ce27d02c0592457ef8.html

当数据量大时,使用InsertItem插入数据的过程是很漫长的。这时我们有两个方法来解决该问题:一是使用CListCtrl的虚拟列表技术,二是采用分页显示的方法。对于虚拟列表技术,上述链接中的文章讲的很详细,我用过它的比较简单的方法,后来改用了分页方法。

使用虚拟列表技术,有三点需要搞清楚:

 使用虚拟技术时,需要将CListCtrl控件的Owner Data属性设置为ture。

 给虚拟列表添加元素时,不需要使用InserItem函数,通过调用SetItemCount设置数据总个数,然后由系统产生不同的消息,在相应的消息响应函数中完成插入工作。

 虚拟列表向父窗口发送的消息有三种: ⑴ 当它需要数据时,发送LVN_GETDISPINFO消息; ⑵ 当用户试图查找某个元素时,发送LVN_ODFINDITEM消息; ⑶当需要缓冲数据时,发送 LVN_ODCACHEHINT消息。

当我们使用LVN_GETDISPINFO 的消息处理函数来插入元素时,必须首先检查列表请求的是什么数据(如LVIF_TEXT、LVIF_IMAGE等),然后插入不同的子项。示例如下:

  1. void CDataAnalysis::OnLvnGetdispinfoAnalysisList(NMHDR *pNMHDR, LRESULT *pResult)
  2. {
  3. NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
  4. // TODO: Add your control notification handler code here
  5. LV_ITEM* pItem= &(pDispInfo)->item;
  6. int iItemIndex= pItem->iItem;
  7. size_t converted = 0;
  8. wchar_t wStr[30];            //Unicode字符串
  9. if (pItem->mask & LVIF_TEXT) //字符串缓冲区有效
  10. {
  11. switch(pItem->iSubItem)
  12. {
  13. case 0: //填充数据项的名字,xxxxx表示要填充的字符
  14. mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
  15. lstrcpy(pItem->pszText,wStr);
  16. break;
  17. case 1: //填充子项1
  18. mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
  19. lstrcpy(pItem->pszText,wStr);
  20. break;
  21. case 2: //填充子项2
  22. mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);
  23. lstrcpy(pItem->pszText,wStr);
  24. break;
  25. case 3: //填充子项3
  26. lstrcpy(pItem->pszText,xxxxxx);
  27. break;
  28. }
  29. }
  30. *pResult = 0;
  31. }

10、点击表头时进行归类排序

系统通过发送LVM_SORTITEMS消息来处理归类问题,在该消息的处理函数中需要调用一个回调函数,这个回调函数需要我们来设计,以完成不同的归类方法。回调函数原型如下:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)

针对上述回调函数,有以下几点需要搞清楚:

 对于参数lparam1和lparam2,分别为CListCtrl的两行数据,是用于比较的对象。通过CListCtrl的成员函数SetItemData来设置,该函数原型:

 int SetItemData(int nIndex,  DWORD_PTR dwItemData )

其第一个参数为行号,第二个参数指明了该行对应的参数。参数dwItemData 通常设为一行参数的数组,如: pData[2][2] = {{1, 3},{2, 3}}; 每次使用pData[i]作为dwItemData。

 对于参数lParamSort,用于指明列项,即第几列。该参数和回调函数一同通过CListCtrl的成员函数SortItems来设置,其函数原型为:

 BOOL SortItems( PFNLVCOMPARE pfnCompare,DWORD_PTR dwData )

参数 pfnCompare 为回调函数入口地址, 参数dwData 为列项。

③ SetItemData在初始插入数据时进行调用来设置,SortItems则在点击列表头时响应的消息处理函数中进行设置。

示例如下:

  1. //初始化列表视图控件
  2. BOOL CDataAnalysis::InitListCtl()
  3. {
  4. //其他处理,包括设置风格,插入列等等
  5. //插入行
  6. for(int i=0; i<LineNum; i++)
  7. {
  8. //要将char*转换为wchar_t*
  9. mbstowcs_s(&converted, wStr, 30, m_analysis[i].Date, _TRUNCATE);
  10. m_listAnalysis.InsertItem(i, wStr);                             //日期
  11. mbstowcs_s(&converted, wStr, 30, m_analysis[i].Time, _TRUNCATE);
  12. m_listAnalysis.SetItemText(i, 1, wStr);                         //时间
  13. mbstowcs_s(&converted, wStr, 30, m_analysis[i].ID, _TRUNCATE);
  14. m_listAnalysis.SetItemText(i, 2, wStr);                         //ID
  15. m_listAnalysis.SetItemText(i, 3, m_analysis[i].lpszEvent);      //事件
  16. //设置回调函数的参数
  17. m_listAnalysis.SetItemData(i, (LPARAM)(m_analysis+i));
  18. }
  19. return TRUE;
  20. }
  21. void CDataAnalysis::OnHdnItemclickAnalysisList(NMHDR *pNMHDR, LRESULT *pResult)
  22. {
  23. LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
  24. // TODO: Add your control notification handler code here
  25. //设置回调函数的参数和入口地址
  26. m_listAnalysis.SortItems(SortFunc, phdr->iItem);
  27. *pResult = 0;
  28. }
  29. //排序的回调函数
  30. int CALLBACK SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  31. {
  32. int result;     //返回值
  33. //两行的参数,用于比较
  34. ANALYSISFORMAT* pAnalysis1 = (ANALYSISFORMAT*)lParam1;
  35. ANALYSISFORMAT* pAnalysis2 = (ANALYSISFORMAT*)lParam2;
  36. //排序
  37. switch(lParamSort)
  38. {
  39. case 0:     //日期
  40. result = strcmp(pAnalysis1->Date, pAnalysis2->Date);
  41. break;
  42. case 1:     //时间
  43. result = strcmp(pAnalysis1->Time, pAnalysis2->Time);
  44. break;
  45. case 2:     //ID
  46. result = strcmp(pAnalysis1->ID, pAnalysis2->ID);
  47. break;
  48. case 3:     //事件
  49. result = wcscmp(pAnalysis1->lpszEvent, pAnalysis2->lpszEvent);
  50. break;
  51. default:
  52. break;
  53. }
  54. return result;
  55. }

11、向上与向下移动

有时需要向上或向下移动表项内容,这里给出向上移动的方法,向下移动的方法类似。

① 利用第2节所述的内容获取行号nItem,判断行号是否为行首,如果不是行首则进入②;

② 获取第nItem行的所有子项内容;

③ 删除第nItem行,并在nItem-1的位置重新插入原先的第nItem行的内容;

④ 使nItem-1的位置高亮显示

示例如下:

  1. /*************************上移子项**************************/
  2. void CStudyTestDlg::OnPageup()
  3. {
  4. if (nItem == 0)
  5. {
  6. MessageBox("该子项已经位于第一行!");
  7. return;
  8. }
  9. // 提取内容
  10. CString temp[4];
  11. int i;
  12. for(i=0;i<4;i++)
  13. temp[i] = m_ListCtrl.GetItemText(nItem, i);
  14. // 删除
  15. m_ListCtrl.DeleteItem(nItem);
  16. // 在nItem-1位置处插入
  17. for (i=0; i<4; i++)
  18. m_ListCtrl.SetItemText(nItem-1,i,temp[i]);
  19. //高亮显示
  20. UINT flag = LVIS_SELECTED|LVIS_FOCUSED;
  21. m_ListCtrl.SetItemState(--nItem, flag, flag);
  22. }
  23. /*************************下移子项**************************/
  24. void CStudyTestDlg::OnPagedown()
  25. {
  26. if (nItem == m_ListCtrl.GetItemCount()-1)
  27. {
  28. MessageBox("该子项已经位于最后一行!");
  29. return;
  30. }
  31. // 提取内容
  32. CString temp[4];
  33. int i;
  34. for (i=0; i<4; i++)
  35. temp[i] = m_ListCtrl.GetItemText(nItem, i);
  36. // 删除
  37. m_ListCtrl.DeleteItem(nItem);
  38. // 在nItem+1位置处插入
  39. for (i=0; i<4; i++)
  40. m_ListCtrl.SetItemText(nItem+1, i,temp[i]);
  41. //高亮显示
  42. UINT flag = LVIS_SELECTED|LVIS_FOCUSED;
  43. m_ListCtrl.SetItemState(++nItem, flag, flag);
  44. }

12、避免闪烁问题

这个问题在我的前面一篇博文有提到。

http://blog.csdn.net/zwgdft/article/details/7394318

13、动态调整大小

有时由于不确定软件运行时的电脑屏幕大小,需要根据屏幕大小动态设置CListCtrl控件的大小。动态大小的设置时,需要注意不要将高度和宽度设置的超过区域限制,否则就没有滚动条了,导致部分内容无法查看。以我遇到的一个例子来说,其情况见第12节提到的那篇博文所述:将View划分为三个窗格,在左上角View上有个CPropertySheet,其上有几个CPropertyPage,每个属性页上有个CListCtrl,供用户查看信息。那么这时需要设置的CListCtrl的大小即为:

宽度 = 左上角View宽度

高度 = 左上角View高度 - 属性页的Tab项高度

调用MoveWindow函数进行设置即可。

------------------全文完--------------------

from:http://blog.csdn.net/zwgdft/article/details/7565331

时间: 2024-10-23 07:24:53

MFC总结之CListCtrl用法及技巧(二)的相关文章

MFC总结之CListCtrl用法及技巧(一)

本文根据本人在项目中的应用,来谈谈CListCtrl的部分用法及技巧.当初学习时,查了很多资料,零零碎碎的作了些记录,现在主要是来做个总结,方便以后查阅.主要包括以下十三点内容:基本操作.获取选中行的行号.复选框操作.动态设置选中行的字体颜色.设置选中行的背景颜色.禁止拖动表头.让第一列居中显示.设置行高与字体.虚拟列表技术.点击表头时进行归类.向上与向下移动.动态调整大小问题.避免闪烁问题. 分为两篇来进行总结.本篇重点总结:基本操作.获取选中行的行号.复选框操作.动态设置选中行的字体颜色.设

ClistCtrl用法及总结(由怎样隐藏ListCtrl列表头的排序小三角形这个bug学习到的知识)

1 怎样隐藏ListCtrl列表头的排序小三角形 在创建控件是加入|LVS_NOSORTHEADER风格即可. 一下是用法总结: 本文根据本人在项目中的应用,来谈谈CListCtrl的部分用法及技巧.当初学习时,查了很多资料,零零碎碎的作了些记录,现在主要是来做个总结,方便以后查阅.主要包括以下十三点内容:基本操作.获取选中行的行号.复选框操作.动态设置选中行的字体颜色.设置选中行的背景颜色.禁止拖动表头.让第一列居中显示.设置行高与字体.虚拟列表技术.点击表头时进行归类.向上与向下移动.动态调

grep过滤用法介绍(二)

grep过滤用法介绍(二) 背景:(1)alias cgrep='grep --color' (2)cp /etc/passwd  1.txt 1. cgrep -n 'root' 1.txt 包含root所在,行数. 2. cgrep -v 'nologin' 1.txt 不包含nologin. 3. cgrep '[0-9]' 1.txt 包含所有0-9中间数字包含任意一个的行. 4. cgrep '[a-zA-Z]' 1.txt 过滤所有字母. 5.cgrep '^[a-z]' 1.txt

思科命令配置小技巧二:macro命令

在 思科命令配置小技巧一中,我们谈到,使用range命令可以简化我们的配置 但是如果我们经常对一组不连续的端口进行操作 比如 interface-range  fa1/1 ,fa1/3 ,fa1/5 ,fa1/7 ,fa1/11 即使使用range命令也会显得很繁琐 我们总想越简单越好(命令敲再多,工资还是那个数,要是按命令字数算工资多好) 此时交换机的宏命令就派上用场了 suzhouxiaoniu(config)#define interface-range abc fa1/1 ,fa1/3

CSS技巧二

元素缩写 font中属性的放置顺序是严格遵守的,否则不会生效. Font:font-style font-weight font-size font-familiy;(注:font-size和font-family是font的必须属性,并且font-size一定要放在font-family的前面) Margin:margin-top margin-right margin-bottom margin-bottom ; Padding:padding-top padding-right paddi

SQL开发技巧(二)

本系列文章旨在收集在开发过程中遇到的一些常用的SQL语句,然后整理归档,本系列文章基于SQLServer系列,且版本为SQLServer2005及以上…… 文章系列目录 SQL开发技巧(一) SQL开发技巧(二) 本文内容简介 这篇文章主要介绍以下内容: 快速查询表的总记录数 非递归查询树形结构表的所有子节点 清除查询缓存 编程中构建Where语句的小技巧 如何进行跨服务器的数据库查询 快速查询表的总记录数 什么,你还在用select count(*) from xxx?难道没有园友告诉你用se

Eclipse用法和技巧二十八:Eclipse插件Easy Explore的今世

先说明一下easyexplore插件的功能,easyexplore是一个类似于 Windows Explorer的Eclipse插件,它可以帮助你在不退出Eclipse的环境下迅速浏览本地文件系统. 具体可以看图: 前一阵子项目组来了一批新员工,在配置开发环境的时候,发现有的员工可以安装easyexplore插件,有的安装无效.经过分析发现,有的员工用的Eclipse是从Android开发网站上下载的,adt-bundle-windows包里面的,Eclipse的版本是JUNO版本,有的员工的E

grep用法简介之二

上一篇文章总结了一些grep基本用法.在这次的内容里介绍grep和正则表达式结合使用的方法. 首先介绍下正则表达式,正则表达式非基本和扩展两种. 名词释义:正则表达式:正则表达式其实就是描述某些复杂规则字符串的代码集合. 元字符:在正则表达式中具有特殊意义的专用字符 正则表达式 基本正则表达式元字符: ^ :表示行首    $ :表示行尾      ^$:表示空白行      * :表示星之前字符的0个或任意个字符,例如:a*:表示0个a或任意一个a的字符,所以就是全显示出来了.      .

Eclipse用法和技巧二十四:当git遇上eclipse

git是非常优秀的代码管理工具,eclipse是非常不错的,免费的IDE.工作中两者碰到一起,有点麻烦了:eclipse对于每个项目会生成一些特定的文件,而这些文件又不是项目必须的,并且每个人的配置是不一样的,所以这些文件不好放入版本库随代码统一管理.刚开始的时候,本人是在执行 git add 或者git reset这些命令的时候指定文件,这个就没有直接来 git add .这样的命令方便了.接下来就介绍一个一劳永逸的方法:        步骤一:进入当前项目仓库的.git目录,进入info目录