应客户要求,在点击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<LPNMLISTVIEW>(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解决。