0

0

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

php中文网

php中文网

发布时间:2016-06-07 15:48:19

|

1546人浏览过

|

来源于php中文网

原创

本篇重点介绍: 禁 止拖动表头、让第一列居中显示、设置行高与字体、虚拟列表技术、点击表头时进行归类、向上与向下移动、动态调整大小问题、避免闪烁问题 。 6 、禁止拖动表头 重载 OnNotify 消息响应函数,屏蔽两个消息通知码: HDN_BEGINTRACKW 和 HDN_DIV

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


 6、禁止拖动表头

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

[cpp] view plaincopy

  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.   
  13.     return CDialog::OnNotify(wParam, lParam, pResult);  
  14. }  

 7、让第一列居中显示

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


 8、设置行高和字体

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

[cpp] view plaincopy

  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 掉创建的字体,避免内存泄露。

[cpp] view plaincopy

  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.     //设置字体  
  26.     CListCtrl &theCtrl = GetListCtrl();     //获取控制权,引用变量  
  27.     theCtrl.SetFont(m_font, TRUE);  
  28. }  



 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等),然后插入不同的子项。示例如下:

[cpp] view plaincopy

  1. void CDataAnalysis::OnLvnGetdispinfoAnalysisList(NMHDR *pNMHDR, LRESULT *pResult)  
  2. {  
  3.     NMLVDISPINFO *pDispInfo = reinterpret_cast(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.   
  31.     *pResult = 0;  
  32. }  



 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来设置,其函数原型为:

Git版本控制与工作流 中文WORD版
Git版本控制与工作流 中文WORD版

篇文章是针对git版本控制和工作流的总结,如果有些朋友之前还没使用过git,对git的基本概念和命令不是很熟悉,可以从以下基本教程入手: Git是分布式版本控制系统,与SVN类似的集中化版本控制系统相比,集中化版本控制系统虽然能够令多个团队成员一起协作开发,但有时如果中央服务器宕机的话,谁也无法在宕机期间提交更新和协同开发。甚至有时,中央服务器磁盘故障,恰巧又没有做备份或备份没及时,那就可能有丢失数据的风险。感兴趣的朋友可以过来看看

下载

                    BOOL SortItems( PFNLVCOMPARE pfnCompare,DWORD_PTR dwData )

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

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

示例如下:

[cpp] view plaincopy

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

 11、向上与向下移动

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

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

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

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

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

示例如下:

[cpp] view plaincopy

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

 12、避免闪烁问题

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

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

 

13、动态调整大小

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

                                              宽度 = 左上角View宽度

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

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


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

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

2

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

56

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

30

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

59

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

25

2026.03.03

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

79

2026.02.28

Golang 工程化架构设计:可维护与可演进系统构建
Golang 工程化架构设计:可维护与可演进系统构建

Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。

61

2026.02.28

Golang 性能分析与运行时机制:构建高性能程序
Golang 性能分析与运行时机制:构建高性能程序

Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。

50

2026.02.28

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

47

2026.02.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MongoDB 教程
MongoDB 教程

共17课时 | 3.1万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号