关于CListView和CListCtrl的排序!

今天用到了这些知识,所以记忆下来,方便以后查询!

  CListView的排序和CListCtrl的排序基本相似,所以在这里一并提一下。

 
什么时候排序?

  当用户点击表头的时候,自然要触发排序函数,进行排序。

  如上图所示,点击时间这一列头,要触发排序。

 
如何响应点击表头这一动作?

点击表头时,触发LVN_COLUMNCLICK消息,我们只需要添加相应的函数就行了。在CListCtrl里时触发LVN_COLUMNCLICK,在CListView里面确是触发==LVN_COLUMNCLICK,也就是反射消息。

一般来说,排序的时候我们的列头都要显示一张向上或者向下的图标,以提醒用户是升序排还是降序排,所以在响应LVN_COLUMNCLICK消息的时候我们一般要建立一张图像列表。

你要在你的对话框程序里面加一个CImageList对象(CListCtrl),或者在你的CXXListView(CListView派生类)类里加一个CImageList对象,指针也行,析构的时候记得删除就行了。

在对话框程序的InitDialog函数,或者在CXXListView的InitialUpdate函数里面添加要用到的图片。

void CXXListView::OnInitialUpdate()
{
	CListView::OnInitialUpdate();
	CListCtrl &list = GetListCtrl();   //得到内置的ClistCtrl引用
	pHeaderImg = new CImageList;       //pHeaderImg是CImageList对象的指针,成员变量
	pHeaderImg->Create(22, 22, ILC_COLOR32 | ILC_MASK, 2, 2); //创建一个图像列表
	CBitmap b1, b2, b3;
	b1.LoadBitmap(IDB_DOWN);  //向下图片
	b2.LoadBitmap(IDB_UP);    //向上图片
	b3.LoadBitmap(IDB_BLANK); //空白图片
	pHeaderImg->Add(&b1, RGB(255, 255, 255));
	pHeaderImg->Add(&b2, RGB(255, 255, 255));
	pHeaderImg->Add(&b3, RGB(255, 255, 255));
	list.GetHeaderCtrl()->SetImageList(pHeaderImg);  //设置列头的图像列表
}

  看一下我添加的三张bitmap:

 至于为什么要添加一张空白的位图,我后面自然会说明

还有在Dlg中或者CXXListView里面还要添加一个int型的变量,用来记录之前点击的列数,如下面的代码中m_nCurSortCol就是这样一个变量,初始化m_nCurSortCol = -1,还需要添加一个变量用来记录排序的方向,BOOL型就可以满足需求了,因为就两种状态,向上排或者向下排,下面代码里的m_bOrder就是这么一个变量,初始化m_bOrder
= FALSE.

图片添加好了之后我们就可以来排序了。在ClistCtrl里面你大可以这么写:

void CXXDlg::OnColumnclick(NMHDR *pNMHDR, LRESULT *pResult)
{
	NMLISTVIEW *p = (NM_LISTVIEW *)pNMHDR;
	int nSub = p->iSubItem; /*得到点击的列数*/
	CHeaderCtrl *pHeader = m_list.GetHeaderCtrl();  /*得到列头的指针,m_list是你的对话框程序里面的CListCtrl控件对应的对象*/
	HDITEM hdi = { HDI_IMAGE | HDI_FORMAT };  /*关于HDITEM,你可以视他为一些控制信息的集合*/
	/*pHeader可以通过GetItem(m_nCurSortCol, &hdi);获得m_nCurSortCol列的一些信息,如是不是显示图像之类的*/
	/*pHeader可以也通过SetItem(m_nCurSortCol, &hdi)设置m_nCurSortCol列的一些状态,如显示图像之类的*/
	if (nSub != m_nCurSortCol) /*点击了不同的列*/
	{
		if (m_nCurSortCol > -1)
		{
			pHeader->GetItem(m_nCurSortCol, &hdi); /*获取当前有哪些开关状态*/
			hdi.iImage &= ~HDF_IMAGE;  /*移除图标*/
			pHeader->SetItem(m_nCurSortCol, &hdi);
		}
		m_nCurSortCol = nSub;
	}
	else /*点击了相同的列*/
	{
		m_bOrder = !m_bOrder;
	}
	pHeader->GetItem(nSub, &hdi); /*获取开关状态*/
	hdi.fmt |= HDF_IMAGE;   /*显示图标*/
	hdi.iImage = m_bOrder;  /*图标方向,实际上是图像列表里面的图标的索引号*/
	pHeader->SetItem(nSub, &hdi);  /*设置表头表项的状态*/

    //很有必要,将索引项填入每一个item的附加数据里面
	int num = m_list.GetItemCount(); /*获得总共的列数*/
	while(num--)
		m_list.SetItemData(num, num);

	PFNLVCOMPARE fns[] = { bySender, bySubject, byTime };  /*三个排序函数*/
	m_list.SortItems(fns[m_nCurSortCol], (DWORD)this); //开始排序,很有必要将自己的指针传给排序函数
	*pResult = 0;
}

  一般来说,这么写没一点错误,对于CXXListView来说,却有一些问题,我不知道是只有我自己遇到了这样的问题还是怎么的,那就是图片屏蔽不了了,对于一列,我可以将它的图片开关打开,但是却关不了,点击了一列之后,再点击另外一列,原来一列的图标并不消失,真是奇了怪了,不过也有方法解决,这也是我为什么载入一张空白位图的原因,既然关不了,那就画一张空白位图吧,效果相同。

void CXXListView::OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	int nSub = pNMLV->iSubItem; /*得到点击的列数*/
	CHeaderCtrl *pHeader = GetListCtrl().GetHeaderCtrl();
	HDITEM hdi = { HDI_IMAGE | HDI_FORMAT };

	if (nSub != m_nCurSortCol) /*点击了不同的列*/
	{
		if (m_nCurSortCol > -1)
		{
			pHeader->GetItem(m_nCurSortCol, &hdi); /*获取当前有哪些开关状态*/
			hdi.iImage = 2;  /*改变图标索引,2指向原来的空白位图*/
			pHeader->SetItem(m_nCurSortCol, &hdi);
		}
		m_nCurSortCol = nSub;
	}
	else /*点击了相同的列*/
	{
		m_bOrder = !m_bOrder;  /*m_bOrder是BOOL类型,用来几录当前的排序顺序,这里反序*/
	}
	pHeader->GetItem(nSub, &hdi); /*获取开关状态*/
	hdi.fmt |= HDF_IMAGE;   /*显示图标*/
	hdi.iImage = m_bOrder;  /*设置图标索引,BOOL其实就是0, 1*/
	pHeader->SetItem(nSub, &hdi);

    int num = GetListCtrl().GetItemCount(); //获得行数
	while(num--)   //设置该列的索引号到附加数据里面
		GetListCtrl.SetItemData(num, num);

	PFNLVCOMPARE fns[] = { bySender, bySubject, byTime };
	GetListCtrl().SortItems(fns[m_nCurSortCol], (DWORD)this);
	*pResult = 0;
}

前面的bySender, bySubject, byTime其实都是排序函数,这些函数需要你自己来实现,我实现一个就行了,其余都类似,需要注意的是,这些函数都必须是静态函数,基本上是这种形式:

static int CALLBACK bySender(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);//按照发件人排序

  然后怎么排序呢?

lparam1和lparam2并不是要比较行的索引,而是要比较行的附加数据,也就是你之前SetItemData里面的数据,我们这样来排序,假设按照发件人来排序,先获取数据,再比较。还是以CXXListView为例:

int CALLBACK CXXView::bySender(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) /*按照发件人排序*/
{
	CXXListView *pView = (CEmailListView *)lParamSort;
	int n1 = lParam1; //获得附加数据,前面存入item的行数
	int n2 = lParam2;

	CString str1 = pView->GetListCtrl().GetItemText(n1, 0); //获取发件人那一行的文字
    CString str2 = pView->GetListCtrl().GetItemText(n2, 0);
	if (pView->m_bOrder) //根据排序顺序来排
		return str2 > str1;
	else
		return str1 > str2;
}

      bySubject, byTime也是类似的写,怎么排序,看你自己的排法了,看一下我的成果吧!

PS:往一个Item的附加数据里面添加该行的索引,这其实并不绝对,你也可以添加别的数据,只要有益于排序就行了。

时间: 2024-11-05 17:34:52

关于CListView和CListCtrl的排序!的相关文章

CListCtrl控件使用方法总结(zhuan)

列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性值.MFC中使用CListCtrl类来封装列表控件的各种操作.通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID )创建一个窗口, dwStyle中可以使用以下一些列表控件的专用风格: ?LVS_ICON LVS_SMALLICON LVS_LIST LVS_REPORT 这四种风格决定控件的外观,同时

MFC的CListCtrl的使用与技巧

http://blog.csdn.net/artechtor/article/details/2508070 列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性值.MFC中使用CListCtrl类来封装列表控件的各种操作.通过调用 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些列表控件的专用风格: LVS_

C++MFC编程笔记day09 MF界面控件的使用1

一 MFC控件 1 控件介绍 1.1 静态控件包括图片.静态文本和分组框.生成的控件的ID统一是 IDC_STATIC.很少程序中访问和操作,只是使用静态控件显示信息 1.2 编辑框控件,控件类是CEdit,通常使用它接收用户的输入,显示 信息给用户. 1.3 按钮控件包括一般按钮.复选按钮和单元按钮,控件类都是CButton 单选按钮注意,同一组的按钮Tab键顺序的编号连续(Ctrl+d  显示tab顺序),而且编号小的 按钮设置group属性,才能在同一个对话框中,实现多个单选按钮的 多个分

MFC总结

一MFC 的概念和作用 1 什么是MFC? 全称Microsoft Foundation Class Library 我们称之为 微软基础类库,封装了绝大部分WIN32 api 函数,还封装 了程序流程. 1.1 硬盘存在形式就是一个库(静态库/动态库) 1.2 原理上还是一个程序框架 2 为什么使用MFC? 基于框架编程,提供工作效率,减少开发周期,节约开发 成本. 二几个重要头文件 afx.h - MFC 绝大部分类的声明 afxwin.h - 包含了afx.h 和windows.h afx

MFC界面相关

一MFC 的菜单 1 相关类 WIN32 - HMENU MFC - CMenu 类对象 CMenu - 封装了操作菜单的各种API 函数,还封装了很重要成 员 m_hMenu(保存菜单句柄) 2 菜单使用 2.1 添加菜单资源 2.2 设置菜单(将菜单挂到窗口中) 1)在创建主框架窗口的(Create)过程中 2)在框架窗口的WM_CREATE 消息处理中 CMenu menu; menu.LoadMenu CFrameWnd::SetMenu 2.3 设置菜单项状态 ON_WM_INITME

SetProp()、GetProp()、RemoveProp() API接口

感觉这三个接口很少看到,所以就整理了下 1.功能介绍 网站来源:http://blog.csdn.net/ly131420/article/details/8865845 在windows界面设计中,我们和窗口的接触比较多,但是这三个api接口却很少用到,即:SetProp.GetProp.RemoveProp这三个API接口,实际上这三个API接口是和窗口句柄关联起来的,这个非常重要,因为他们可以给窗口设置添加.删除新属性,这就扩展了窗口的关联数据,使得我们可以把任何数据关联到窗口上,在设计一

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

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

mfc的ClistCtrl控件列的排序

在网上看了许多排序的方法,都没看懂,初学者的悲剧,然后就自己弄了个,请大家指正. ClistCtrl控件的行带着一个结构体,不过那结构体不好懂,看得眼花缭乱.好多也弄不明白,就自己写了个结构体,把一行的数据全写入结构体中, 交换两结构体的数据就简单多了. typedef struct { wchar_t id[6];  //编号 wchar_t name[10]; //姓名 wchar_t sex[2];        //性别 int age;              //年龄 wchar_

CListCtrl使用(转)

CListCtrl使用技巧 以下未经说明,listctrl默认view 风格为report 1. CListCtrl 风格 LVS_ICON: 为每个item显示大图标      LVS_SMALLICON: 为每个item显示小图标      LVS_LIST: 显示一列带有小图标的item      LVS_REPORT: 显示item详细资料 直观的理解:windows资源管理器,"查看"标签下的"大图标,小图标,列表,详细资料" 2. 设置listctrl