CListCtrl自动排序及添加排序箭头

应客户要求,在点击CListCtrl列表每列标题时进行排序,类似于WINDOWS资源管理器的效果。

首先在资源中添加LVN_COLUMNCLICK消息,生成OnLvnColumnclickListInfo函数,在函数里进行处理即可。

1.最最笨的方法是点击标题时,依次获取每行的内容,自己比较排序,这里不多说,略过。


2.用控制自带的排序功能。

1)为了能显示箭头,在列表初始化时增加图标,如下

	CHeaderCtrl *pHeaderCtrl=m_ListCtrl.GetHeaderCtrl();

	m_ImageList.Create(16,16,ILC_COLOR16 | ILC_MASK,0,4);
	m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1));//IDI_ICON1和IDI_ICON2是自己资源中的箭头ID,类型为ICON
	m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2));
	pHeaderCtrl->SetImageList(&m_ImageList);//m_ImageList是头文件中申明的CImageList m_ImageList

	

2.进行排序并显示箭头

int sort_column=-1; // 记录点击的列
bool method = false; // 记录比较方法
// 比较函数
static int CALLBACK MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	// 从参数中提取所需比较lc的两行数据	
	int row1 = (int)lParam1;//这里的参数实际是SetItemData函数设置的值,比较的第一列
	int row2 =(int)lParam2;//这里的参数实际是SetItemData函数设置的值,比较的第二列
	CListCtrl* lc= (CListCtrl*)lParamSort;
	CString lp1 = lc->GetItemText(row1,sort_column);
	CString lp2 = lc->GetItemText(row2,sort_column); 
	LPCTSTR s1=(LPCTSTR)lp1; 
	LPCTSTR s2=(LPCTSTR)lp2;
	 // 比较,对不同的列,不同比较,注意记录前一次排序方向,下一次要相反排序		 
	if (method)
	{
		return  strcmp(s2,s1);
	}
	else
	{
		return  strcmp(s1,s2);
	}
}
void CDlgWorklistInfo::OnLvnColumnclickListInfo(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV =reinterpret_cast(pNMHDR);
	
	sort_column = pNMLV->iSubItem;//点击的列

	int count = m_ListCtrl.GetItemCount();

	for (int i = 0; i< count ; i++)
	{
		 
		m_ListCtrl.SetItemData(i,i);//在排序前一定用这个函数设置每行值,类似于自定义索引
		
	}
	// 自定义图标排序箭头样式  
	CHeaderCtrl* pHdrCtrl = m_ListCtrl.GetHeaderCtrl();  
	if(pHdrCtrl && pHdrCtrl->GetSafeHwnd())    
	{  
		int n = pHdrCtrl->GetItemCount();  

		HDITEM hdi={0};  
		TCHAR szBuf[129] = {0};       
		hdi.mask = HDI_TEXT; //取字符掩码     
		hdi.pszText = szBuf; //字符缓冲区     
		hdi.cchTextMax = 128; //缓冲区大小    
		for( int i = 0; i < n; i++ )  
		{  
			hdi.mask = HDI_IMAGE | HDI_FORMAT;  // 读取排序箭头图标状态,必需指定  
			pHdrCtrl->GetItem(i, &hdi);  
			if( i == sort_column )  
			{  
				if( hdi.fmt & HDF_IMAGE )   //前后2次点击同一列时, 已经排序,改变升降序,并切换箭头图标。  
				{  
					hdi.iImage = 1 - hdi.iImage;  
					method = !method;
				}  
				else  //前后点击不同列时图标显示在新点击列头
				{  
					hdi.iImage = 0;  
					hdi.fmt |= HDF_IMAGE | HDF_BITMAP_ON_RIGHT;  
					if (method)//为了保证新点击的列与上次显示一致
					{
						hdi.iImage = 1 - hdi.iImage;
					}
				}  
			}  
			else  
			{  
				hdi.mask = HDI_FORMAT;  
				hdi.fmt &= ~HDF_IMAGE & ~HDF_BITMAP_ON_RIGHT;  
			}  

			pHdrCtrl->SetItem( i, &hdi );  
		}  
	}
	m_ListCtrl.SortItems(MyCompareProc,(DWORD)&m_ListCtrl);//排序第二个参数是比较函数的第三个参数

	*pResult =0;
}


总结:另外网上有说用CMFCListCtrl类(VS2008以上)比较好用,有兴趣可以自己试试。还有调试过程中用的是第三方类继承CListCtrl导致
LPARAM lParam1, LPARAM lParam2
始终传过来是很大的随机值,后面直接换回微软自带的CListCtrl解决。

你可能感兴趣的:(VC学习)