关于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的附加数据里面添加该行的索引,这其实并不绝对,你也可以添加别的数据,只要有益于排序就行了。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
非常好用的CListCtrl加强版。 从CListCtrl继承,完全兼容CListCtrl. 它有以下特性: • The background of the sorted column can be displayed in a different color (like the detailed view of Windows XP Explorer). • The header of the sorted column can display an arrow that indicates the sort direction (like the detailed view of Windows XP Explorer). • You can give the user the opportunity to hide or redisplay selected columns by just clicking on the header control with the right mouse button (see picture below). • You can hide or redisplay a selected column entirely. • In contrast to the original list view control, the first column can have the LVCFMT_CENTER or LVCFMT_RIGHT style, too. For this feature, the list view control must have the LVS_OWNERDRAWFIXED style. • The label attributes state icon, small icon, and selection can always be shown in the leftmost column, independent of the order of the columns. For this feature, the listview control must have the LVS_OWNERDRAWFIXED style. • You can supply tooltips not only for the whole item, but also for the small icon, the state icon, and each subitem label. • The extended styles LVS_EX_CHECKBOXES, LVS_EX_ONECLICKACTIVATE, LVS_EX_SUBITEMIMAGES, LVS_EX_TWOCLICKACTIVATE, and LVS_EX_UNDERLINEHOT will be supported even if the list view control has the LVS_OWNERDRAWFIXED style. • If the LVS_EX_CHECKBOXES style has been applied and a selected item will be checked/unchecked, all other selected items will be checked/unchecked, too. • If the LVS_EX_LABELTIP style has been applied, not only the partially hidden text of the item label will be unfolded but also the partially hidden text of each subitem label. Note: The LVS_EX_LABELTIP style will be supported under all operating systems. • Tooltips and expanded labels can be displayed simultaneously. • The current state of the list view control (column widths, column order, hidden columns, and sort column and direction) can be saved and restored.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值