MFC CListCtrl 列表框排序 单击列头排序(完整源码)

初级代码游戏的专栏介绍与文章目录-CSDN博客

        这是一个通用CListCtrl排序的源代码。

  • 对列表框CListCtrl进行排序,使用列表框的自定义排序功能SortItems
  • 支持任意多个排序列和多种排序规则
  • 单击列头排序可在控件通知HDN_ITEMCLICK事件中调用,示例代码就在头文件里

目录

一、关键技术

二、完整源码

三、代码详解

3.1 排序类型

3.2 排序的列

3.3 排序入口

3.4 回调函数

3.5 使用


一、关键技术

        CListCtrl::SortItems(回调函数,回调函数参数):

BOOL SortItems(PFNLVCOMPARE pfnCompare,DWORD_PTR dwData);

        该函数通过回调函数比较两个列,参数为(列索引1,列索引2,回调函数参数)。

        比较函数为:

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

        返回值规则为负值表示第一个排前面,正值表示第二个排前面,相当于用第一个减第二个。

        执行SortItems的时候会不断调用CompareFunc来确定排序关系,参数为要比较的两个行的索引以及SortItems的dwData,dwData我们可以设置为一个指针,从而包含需要的任何数据。 

        大致的执行流程是这样的:

SortItems(比较函数,参数)
------比较函数(0,1,参数)
------比较函数(1,2,参数)
------不断调用比较函数
完成

        本代码用回调函数参数传递排序规则,还将itemdata藏在一个临时列里面(动机是什么我忘了,如果没使用itemdata可以删掉相关代码,如果发现有什么用可以告诉我。感觉当初我应该不是傻了,应该是有理由的)。

        这个代码最早写于2000年,现在这个版本是可以用在VS2017的。

二、完整源码

头文件:

//SortList.h#pragma once//通用CListCtrl排序
//这个文件最早写于2000年
//对列表框CListCtrl进行排序,使用列表框的自定义排序功能SortItems
//支持任意多个排序列和多种排序规则
//单击列头排序可在控件通知HDN_ITEMCLICK事件中调用
//示例:
/*
void CTestDlg::OnHdnItemclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);// TODO: 在此添加控件通知处理程序代码*pResult = 0;static map<int, bool > map_isInc;//记录上次的排序状态map_isInc[phdr->iItem] = !map_isInc[phdr->iItem];//同一列每次取反CList<CompareFunc_Col> sortparam;CompareFunc_Col col;col.idCol = phdr->iItem;col.isInc = map_isInc[phdr->iItem];col.sorttype = enum_SortType::sorttype_str;sortparam.AddTail(col);SortList(&m_List1, &sortparam);
}
*///排序类型,数值还是字符串
enum enum_SortType
{sorttype_str,sorttype_istr,sorttype_trimstr,sorttype_itrimstr,sorttype_rtrimstr,sorttype_irtrimstr,sorttype_long,sorttype_double,
};//排序的一个列
class CompareFunc_Col
{
public:int idCol = 0;int sorttype = sorttype_str;BOOL isInc = true;
};//排序调用此功能即可,参数为一个或多个排序的列
void SortList(CListCtrl* pl, CList<CompareFunc_Col> * pSortCols);//取得列索引,-1表示没找到(辅助函数,排序功能并不需要这个函数)
int GetColIndex(CListCtrl * pl, _TCHAR* Col);

实现文件:

//SortList.cpp#include "pch.h" //预编译头文件,是否需要取决于项目设置
#include "SortList.h"int GetColIndex(CListCtrl* pl, _TCHAR* Col)
{LVCOLUMN lvcol;_TCHAR str[256];int ii;lvcol.mask = LVCF_TEXT;lvcol.pszText = str;lvcol.cchTextMax = 256;ii = 0;while (pl->GetColumn(ii, &lvcol)){if (NULL != Col && 0 == _tcscmp(Col, str))return ii;ii++;}return -1;
}
int CompareStr(const _TCHAR* str1, const _TCHAR* str2, int type)
{CString cstr, cstr2;int ret;double d;cstr = str1;cstr2 = str2;switch (type){case sorttype_str:ret = _tcscmp(cstr, cstr2);break;case sorttype_istr:ret = _tcsicmp(cstr, cstr2);break;case sorttype_trimstr:ret = _tcscmp(cstr.Trim(), cstr2.Trim());break;case sorttype_itrimstr:ret = _tcsicmp(cstr.Trim(), cstr2.Trim());break;case sorttype_rtrimstr:ret = _tcscmp(cstr.TrimRight(), cstr2.TrimRight());break;case sorttype_irtrimstr:ret = _tcsicmp(cstr.TrimRight(), cstr2.TrimRight());break;case sorttype_long:ret = _ttol(cstr) - _ttol(cstr2);break;case sorttype_double:d = _ttof(cstr) - _ttof(cstr2);if (d > 0)ret = 1;else if (0 == d)ret = 0;else ret = -1;break;default:ret = 0;break;}return ret;
}//用于排序的回调函数的参数
struct CompareFunc_lParamSort
{CListCtrl* pl;CList<CompareFunc_Col>* pSortCols;
};//用于排序的回调函数,lParamSort为CompareFunc_lParamSort
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{CompareFunc_lParamSort* pparam;CompareFunc_Col* pcol;CString cstr, cstr2;POSITION pos;int ret;int ci;pparam = (CompareFunc_lParamSort*)lParamSort;ci = 0;pos = pparam->pSortCols->GetHeadPosition();while (NULL != pos){pcol = &pparam->pSortCols->GetNext(pos);cstr = pparam->pl->GetItemText((int)lParam1, pcol->idCol);cstr2 = pparam->pl->GetItemText((int)lParam2, pcol->idCol);ret = CompareStr(cstr, cstr2, pcol->sorttype);if (0 != ret){if (pcol->isInc){return ret;}else{return -ret;}}}return 0;
}void SortList(CListCtrl* pl, CList<CompareFunc_Col>* pSortCols)
{_TCHAR str[256];int ii, ci;//保存原来的ItemData到新列ci = pl->InsertColumn(pl->GetHeaderCtrl()->GetItemCount(), TEXT("_temp"));ii = pl->GetItemCount();while (ii--){_i64tot_s(pl->GetItemData(ii), str, 256, 10);pl->SetItemText(ii, ci, str);}//设置IetmDataii = pl->GetItemCount();while (ii--)pl->SetItemData(ii, ii);//排序CompareFunc_lParamSort CompareParam;CompareParam.pl = pl;CompareParam.pSortCols = pSortCols;pl->SortItems(CompareFunc, (DWORD_PTR)&CompareParam);//恢复ItemDataii = pl->GetItemCount();while (ii--){pl->SetItemData(ii, _ttoi64(pl->GetItemText(ii, ci)));}//删除临时列pl->DeleteColumn(ci);
}

三、代码详解

3.1 排序类型

//排序类型,数值还是字符串
enum enum_SortType
{sorttype_str,sorttype_istr,sorttype_trimstr,sorttype_itrimstr,sorttype_rtrimstr,sorttype_irtrimstr,sorttype_long,sorttype_double,
};

        这是我自己定义的排序类型,包括整数、双精度和各种字符串方式,i表示忽略大小写,trim表示忽略前后空白字符,rtrim表示只忽略右边的空白字符。你也可以增加自己的方式,甚至通过参数直接传递比较函数。

3.2 排序的列

//排序的一个列
class CompareFunc_Col
{
public:int idCol = 0;int sorttype = sorttype_str;BOOL isInc = true;
};

        idCol 列的索引

        sorttype 前面介绍的排序类型

        isInc 是否是增量排序

3.3 排序入口

//排序调用此功能即可,参数为一个或多个排序的列
void SortList(CListCtrl* pl, CList<CompareFunc_Col> * pSortCols);

        参数是要排序的CListCtrl和要排序的列(因为支持多个,所以参数是CList,当初我还不懂STL,放现在肯定用vector了)。

        排序入口做了两件事:

  • 保存ItemData到临时列,排序完成后再恢复(有点怀疑是因为排序的时候ItemData混乱了)
  • 设置参数调用CListCtrl的SortItems排序

3.4 回调函数

        回调函数的第三个参数用来传递外部数据:

//用于排序的回调函数的参数
struct CompareFunc_lParamSort
{CListCtrl* pl;CList<CompareFunc_Col>* pSortCols;
};

         看起来按照CListCtrl的设计,告诉你行的索引你就知道全部了??由于回调函数的参数只包含两个行的索引,所以我们必须把一切都塞在第三个参数里面,所以必须使用一个结构,把CListCtrl指针和排序规则放进去。

        回调函数里面则根据规则获取数据比较。

3.5 使用

//单击列头排序可在控件通知HDN_ITEMCLICK事件中调用
//示例:
/*
void CTestDlg::OnHdnItemclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);// TODO: 在此添加控件通知处理程序代码*pResult = 0;static map<int, bool > map_isInc;//记录上次的排序状态map_isInc[phdr->iItem] = !map_isInc[phdr->iItem];//同一列每次取反CList<CompareFunc_Col> sortparam;CompareFunc_Col col;col.idCol = phdr->iItem;col.isInc = map_isInc[phdr->iItem];col.sorttype = enum_SortType::sorttype_str;sortparam.AddTail(col);SortList(&m_List1, &sortparam);
}
*/

         上面的代码在列表框控件的HDN_ITEMCLICK事件通知里处理,只使用单击的列排序,连续单击多个列头可实现复合排序的效果,重复单击同一个列头则改变递增、递减。

        这个代码我用了很多年。

(这里是结束)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/767460.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络行为管理系统招标模板

项目名称&#xff1a;网络行为管理系统招标 一、项目背景 随着信息技术的迅猛发展&#xff0c;网络安全和数据保护已成为企业和组织面临的关键挑战。为了确保网络环境的安全、合规&#xff0c;并实现对网络行为的有效管理和审计&#xff0c;我们特此启动网络行为管理系统的招…

AI程序员革命:探析Devin的登场与编程未来

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

基于python+vue超市货品信息管理系统flask-django-php-nodejs

在此基础上&#xff0c;结合现有超市货品信息管理体系的特点&#xff0c;运用新技术&#xff0c;构建了以 python为基础的超市货品信息管理信息化管理体系。首先&#xff0c;以需求为依据&#xff0c;根据需求分析结果进行了系统的设计&#xff0c;并将其划分为管理员和用户二种…

每日一练:LeeCode-498、对角线遍历【二维数组+边界判断】

给你一个大小为 m x n 的矩阵 mat &#xff0c;请以对角线遍历的顺序&#xff0c;用一个数组返回这个矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;mat [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,4,7,5,3,6,8,9] 示例 2&#xff1a; 输入&#xff1a;ma…

C语言分支和循环

目录 一.分支 一.if 二.if else 三.if else嵌套 四.else if 五.switch语句 二.循环 一.while (do while&#xff09;break : 二.for函数&#xff1a; 三.goto语句: 四.猜数字: 一.分支 一.if if要条件为真才执行为假不执行而且if只能执行后面第一条如果要执行多条就…

Ubuntu共享文件夹创建及访问 Windows 最简单的方法!

第一步&#xff1a;在Windows下随便建一个文件夹&#xff0c;这里我是在D盘建了一个文件夹叫share 第二步&#xff1a;安装VMware tools&#xff0c;这里就不细说了 第三步&#xff1a;vmware的上方选择 虚拟机-->设置 第四步&#xff1a; 在虚拟机设置里面选择 选项-…

EFcore的实体类配置

1 约定配置 约定大于配置&#xff0c;框架默认了许多实体类配置的规则&#xff0c;在约定规则不满足要求时&#xff0c;可以显示地定义规则 1 数据库表明在不指定的情况下&#xff0c;默认使用的是数据库上下文类【DBContext】中DbSet 的属性名&#xff1b; 2 数据库表列的名字…

19、【qlib】【其他组件/特性/主题】任务管理

简介 工作流部分介绍了如何松耦合地运行研究流程,但使用qrun时只能执行单个任务。为了自动地生成和执行不同的任务,任务管理模块提供了一整套流程,包括任务生成、任务存储、任务训练及任务收集。借助这个模块,用户可以在不同时间段、不同损失函数或甚至不同模型下自动运行…

简单的简单

现在有一个函数需要同时修改2个列表list且他们要保持相同长度&#xff0c;列表中的数据计算是CPU计算密集型&#xff0c;然后有很多个访问程序去读取这两个列表的值 import threading # 创建锁对象 lock threading.Lock() # 全局变量 global_list1 [] global_list2 [] def m…

摘录笔记——2024年3月22日

目录 一、背景 1.1 新人的选择困局 1.2 高人才密度环境下普通员工的成长效率困局 1.3 业务发展和个人成长的二元对立困局 1.4 中年打工人低费效比引发的职场生涯终结困局 二、人的本质 2.1 人的本质的定义 2.2 由“人的本质”引出的几个关键过程 2.2.1 认知指引实践&a…

Pillow 一文读懂

Pillow 简介、特点和安装 Pillow 简介 Pillow作为python的第三方图像处理库&#xff0c;提供了广泛的文件格式支持&#xff0c;强大的图像处理能力&#xff0c;主要包括图像储存、图像显示、格式转换以及基本的图像处理操作等。 PIL(Python Image Library)是python的第三方图…

IPV6协议之RIPNG

目录 前言&#xff1a; 一、RIPNG与RIP的区别 二、如何配置RIPNG 如何解决RIPNG环路问题呢&#xff1f; 控制RIPNG的选路 1、修改RIPNG默认优先级 2.配置接口附加开销值从而干涉RIPNG的选路 RIPNG拓展配置 1.RIPNG的认证 配置RIPNG进程下的IPsec认证&#xff1a; 配…

C++默认构造函数(二)

目录 构造函数补充 构造函数初始化列表的使用 赋值运算符重载函数 运算符重载函数介绍 运算符重载函数的使用 赋值运算符重载函数 赋值运算符重载函数的使用 拷贝构造函数和赋值运算符重载函数 重载前置和后置 前置 后置 重载流插入<<与流提取>> 流插…

Navicat 干货 | 探索 PostgreSQL 的外部数据包装器和统计函数

PostgreSQL 因其稳定性和可扩展性而广受青睐&#xff0c;为开发人员和数据管理员提供了许多有用的函数。在这些函数中&#xff0c;file_fdw_handler、file_fdw_validator、pg_stat_statements、pg_stat_statements_info 以及 pg_stat_statements_reset 是其中的重要函数&#x…

白学的小知识[js.事件]

一、事件的常用绑定方式 1 、行内绑定&#xff0c;语法&#xff1a; <标签 属性列表 事件"事件处理的程序" /> <button onclick"addNode();">创建节点</button> 行内绑定&#xff1a;行内绑定的方式所有的行为&#xff08;结构、样式、…

C语言:htoi十六进制转十进制

编写函数htoi(s), 把由十六进制数字组成的字符串&#xff08;包含可选的前缀0X和0x&#xff09;&#xff0c;转化为与之等价的整数值, 字符串中包含的字符可以是0 - 9&#xff0c;A - F&#xff0c;a - f // 把由十六进制数字组成的字符串(包含可选的前缀0X和0x)&#xff0c;转…

鸿蒙:@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

在实际应用开发中&#xff0c;应用会根据开发需要&#xff0c;封装自己的数据模型。对于多层嵌套的情况&#xff0c;比如二维数组&#xff0c;或者数组项class&#xff0c;或者class的属性是class&#xff0c;他们的第二层的属性变化是无法观察到的。这就引出了Observed/Object…

AJAX介绍使用案例

文章目录 一、AJAX概念二、AJAX快速入门1、编写AjaxServlet&#xff0c;并使用response输出字符&#xff08;后台代码&#xff09;2、创建XMLHttpRequest对象&#xff1a;用于和服务器交换数据 & 3、向服务器发送请求 & 4、获取服务器响应数据 三、案例-验证用户是否存…

由浅入深一步步了解什么是哈希(概念向)

文章目录 什么是哈希哈希函数直接定址法除留余数法 哈希冲突闭散列线性探测法二次探测法负载因子和闭散列的扩容 开散列开散列的扩容 非整形关键码 什么是哈希 我们来重新认识一下数据查找的过程&#xff1a; 在顺序结构以及平衡树中&#xff0c;记录的关键码与其存储位置之间…

【自然语言处理】统计中文分词技术(一):1、分词与频度统计

文章目录 一、词与分词1、词 vs 词素2、世界语言分类 二、分词的原因与基本原因1、为什么要分词2、分词规范3、分词的主要难点-切分歧义如何排除切分歧义利用词法信息利用句法信息利用语义信息利用语用、语境信息 4、分词的主要难点-未登录词未登录词如何识别未登录词 三、分词…