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消息进行处理来实现。例子:
static int CALLBACK MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { // lParamSort contains a pointer to the list view control. // The lParam of an item is just its index. //以第一列为根据排序 CListCtrl* pListCtrl = (CListCtrl*) lParamSort; CString strItem1 = pListCtrl->GetItemText(lParam1, 0); CString strItem2 = pListCtrl->GetItemText(lParam2, 0); //比较两个数 LPCTSTR s1=(LPCTSTR)strItem1; LPCTSTR s2=(LPCTSTR)strItem2; int n1=atoi(s1); int n2=atoi(s2);if (n1>n2) return -1; else return 1; } void C***::OnColumnclickList(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here //调用排序函数 m_ShowData.SortItems( MyCompareProc, (DWORD)&m_ShowData ); *pResult = 0; }
整个过程是这样的: 当你点击列表控件的表头时,此时它会向父窗口发送LVN_COLUMNCLICK消息,此时响应函数OnColumnclickList(),在该函数里面再调用列表控件的SortItems()成员函数,它会自动调用排序函数,完成排序功能.
首先,要让CListCtrl能响应点击Column header的操作,方法是响应对应的LVN_COLUMNCLICK消息,然后在对应的消息处理函数中执行自己的排序。其方法是调用CListCtrl 类中的成员函数SortItems()函数,不过在调用之前,依据msdn的指示,一定要对所有需要排序的行调用CListCtrl的 SetItemData(int nItem,DWORD dwData)函数,一般的设置方法为:
for(int i = 0; i < listCtrl.GetItemCount(); ++i) { SetItemData(i,i); }
这样写的原因下面马上就会指出。
接下来就是调用CListCtrl的排序函数SortItems( PFNLVCOMPARE pfnCompare,DWORD dwData ),其中第一个参数为比较函数(回调函数),其函数格式按照msdn上的说法应该为:
int CALLBACK listCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
这里的lParam1和lParam2都是系统传给这个回调函数的,具体数值就是上面SetItemData函数中的dwData,第二个参数是输入给这个回调函数的一个参数,一般都是对应CListCtrl对象的指针
最后就是实现那个回调函数了,msdn上说这个函数必须为独立的函数,或者是某个类中的静态函数,这点注意一下即可,以下为一个具体的回调函数的例子:
//按第六列排序 int CALLBACK listCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { CListCtrl* pListCtrl = (CListCtrl*)lParamSort; CString strItem1 = pListCtrl->GetItemText(lParam1,5); CString strItem2 = pListCtrl->GetItemText(lParam2,5); LVCOLUMN Vol; CString csStr(""); TCHAR szCol[MAX_PATH]; Vol.pszText = szCol; Vol.mask=LVCF_TEXT; Vol.cchTextMax=sizeof(szCol); pListCtrl->GetColumn(0,&Vol); csStr = CString(Vol.pszText); if (csStr.Right(1) == CString("L")) { return _tcscmp(strItem2.GetBuffer(MAX_PATH),strItem1.GetBuffer(MAX_PATH)); } else if (csStr.Right(1) == CString("R")) { return _tcscmp(strItem1.GetBuffer(MAX_PATH),strItem2.GetBuffer(MAX_PATH)); } else { return _tcscmp(strItem1.GetBuffer(MAX_PATH),strItem2.GetBuffer(MAX_PATH)); } } void CManageView::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here CListCtrl &m_ListCtrl = GetListCtrl();for(int i = 0; i < m_ListCtrl.GetItemCount(); ++i) m_ListCtrl.SetItemData(i,i); m_ListCtrl.SortItems(listCompare,(LPARAM)&m_ListCtrl); *pResult = 0; }