首页 > 代码库 > 在ListCtrl中进行排序
在ListCtrl中进行排序
列表控件(CListCtrl)的顶部有一排按钮,用户可以通过选择不同的列来对记录进行排序。但是 CListCtrl并没有自动排序的功能,我们需要自己添加一个用于排序的回调函数来比较两个数据的大小,此外还需要响应排序按钮被点击的消息。下面讲述一下具体的做法。
CListCtrl提供了用于排序的函数,函数原型为:BOOL CListCtrl::SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData )。其中第一个参数为全局排序函数的地址,第二个参数为用户数据,你可以根据你的需要传递一个数据或是指针。该函数返回-1代表第一项排应在第二项前面,返回1代表第一项排应在第二项后面,返回0代表两项相等。
用于排序的函数原形为:int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort),其中第三个参数为调用者传递的数据(即调用SortItems时的第二个参数dwData)。第一和第二个参数为用于比较的两项的ItemData,你可以通过DWORD CListCtrl::GetItemData( int nItem )/BOOL CListCtrl::SetItemData( int nItem, DWORD dwData )来对每一项的ItemData进行存取。在添加项时选用特定的CListCtrl::InsertItem也可以设置该值。由于你在排序时只能通过该值来确定项的位置所以你应该比较明确的确定该值的含义。
最后一点,我们需要知道什么时候需要排序,实现这点可以在父窗口中对LVN_COLUMNCLICK消息进行处理来实现。
下面我们看一个例子,这个例子是一个派生类,并支持顺序/倒序两种方式排序。为了简单我对全局数据进行排序,而在实际应用中会有多组需要排序的数据,所以需要通过传递参数的方式来告诉派序函数需要对什么数据进行排序。
一、在父窗口中对LVN_COLUMNCLICK消息进行处理来实现
二、.h头文件:
static int sort_column; // 记录点击的列
static bool method; // 记录比较方法
static int CALLBACK MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
三、.cpp文件实现:
1 int CViewFileDlg::sort_column = 0; // 记录点击的列 2 bool CViewFileDlg::method = true;; // 记录比较方法
//处理消息
1 void CViewFileDlg::OnLvnColumnclickList1(NMHDR *pNMHDR, LRESULT *pResult) 2 { 3 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); 4 // TODO: Add your control notification handler code here 5 CViewFileDlg::sort_column = pNMLV->iSubItem;//点击的列 6 int count = m_listcontrol.GetItemCount(); 7 8 for (int i=0;i<count;i++) 9 m_listcontrol.SetItemData(i,i); // 每行的比较关键字,此处为列序号(点击的列号),可以设置为其他比较函数的第一二个参数 10 m_listcontrol.SortItems(MyCompareProc,(DWORD_PTR)&m_listcontrol);//排序第二个参数是比较函数的第三个参数 11 12 //取反排序模式后,才能进行下次排序 13 CViewFileDlg::method = !CViewFileDlg::method; 14 15 *pResult =0; 16 }
//排序函数实现
1 int CALLBACK CViewFileDlg::MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 2 { 3 // 从参数中提取所需比较lc的两行数据 4 int row1 = (int) lParam1; 5 int row2 = (int) lParam2; 6 CListCtrl* lc = (CListCtrl*)lParamSort; 7 8 CString lp1 = lc->GetItemText(row1, sort_column); 9 CString lp2 = lc->GetItemText(row2, sort_column); 10 11 // 比较,对不同的列,不同比较,注意记录前一次排序方向,下一次要相反排序
12 if (sort_column == 0 || sort_column == 2) //根据列的数据类型选择比较的类型
13 { 14 // int型比较 15 if (method) 16 return atoi(lp1)-atoi(lp2); 17 else 18 return atoi(lp2)-atoi(lp1); 19 } 20 else 21 { 22 // 文字型比较 23 if (method) 24 return lp1.CompareNoCase(lp2); 25 else 26 return lp2.CompareNoCase(lp1); 27 } 28 return 0; 29 }