列表控件(CListCtrl)的排序功能不像其它直接調(diào)用API就可以完成的功能一樣.它比較復雜.今天將我的一點體會簡單地談一下. 列表控件的頂部有一排按鈕,用戶可以通過選擇不同的列來對記錄進行排序。但是 CListCtrl并沒有自動排序的功能,我們需要自己添加一個用于排序的回調(diào)函數(shù)來比較兩個數(shù)據(jù)的大小,此外還需要響應排序按鈕被點擊的消息?;卣{(diào)函數(shù)就好像是一個中斷處理函數(shù),操作系統(tǒng)在符合你設定的條件時自動調(diào)用。
·CListCtrl提供了用于排序的函數(shù)
函數(shù)原型為:
BOOL CListCtrl::SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData);
其中第一個參數(shù)為全局排序函數(shù)(它就是回調(diào)函數(shù))的地址,
第二個參數(shù)為用戶數(shù)據(jù),你可以根據(jù)你的需要傳遞一個數(shù)據(jù)或是指針。
該函數(shù)返回-1,代表第一項排應在第二項前面;
返回1代表第一項排應在第二項后面;
返回0代表兩項相等。·排序函數(shù)原形為:
int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
其中第三個參數(shù)為調(diào)用者傳遞的數(shù)據(jù)(即調(diào)用SortItems時的第二個參數(shù)dwData)。
第一和第二個參數(shù)為用于比較的兩項的ItemData,你可以通過DWORD CListCtrl::GetItemData( int nItem )/
BOOL CListCtrl::SetItemData( int nItem, DWORD dwData )來對每一項的ItemData進行存取。在添加項時選用特定的CListCtrl::InsertItem也可以設置該值。由于你在排序時只能通過該值來確定項的位置所以你應該比較明確的確定該值的含義。
·我們什么時候需要排序(消息映射)呢?
實現(xiàn)這點可以在父窗口中對LVN_COLUMNCLICK消息進行處理來實現(xiàn)。例子:
//排序回調(diào)函數(shù)實現(xiàn)
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.
//以第一列為根據(jù)排序
CListCtrl* pListCtrl = (CListCtrl*) lParamSort;
CString strItem1 = pListCtrl->GetItemText(lParam1, 0);
CString strItem2 = pListCtrl->GetItemText(lParam2, 0);
//比較兩個數(shù)
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 //調(diào)用排序函數(shù)
m_ShowData.SortItems( MyCompareProc, (DWORD)&m_ShowData );
*pResult = 0;}
整個過程是這樣的: 當你點擊列表控件的表頭時,此時它會向父窗口發(fā)送LVN_COLUMNCLICK消息,此時響應函數(shù)OnColumnclickList(),在該函數(shù)里面再調(diào)用列表控件的SortItems()成員函數(shù),它會自動調(diào)用排序函數(shù),完成排序功能.
首先,要讓CListCtrl能響應點擊Column header的操作,方法是響應對應的LVN_COLUMNCLICK消息,然后在對應的消息處理函數(shù)中執(zhí)行自己的排序。其方法是調(diào)用CListCtrl 類中的成員函數(shù)SortItems()函數(shù),不過在調(diào)用之前,依據(jù)msdn的指示,一定要對所有需要排序的行調(diào)用CListCtrl的 SetItemData( int nItem, DWORD dwData )函數(shù),一般的設置方法為:
for(int i = 0; i < listCtrl.GetItemCount(); ++i)
{
SetItemData(i,i);
}
這樣寫的原因下面馬上就會指出。
接下來就是調(diào)用CListCtrl的排序函數(shù)SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData ),其中第一個參數(shù)為比較函數(shù)(回調(diào)函數(shù)),其函數(shù)格式按照msdn上的說法應該為:
int CALLBACK listCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
這里的lParam1和lParam2都是系統(tǒng)傳給這個回調(diào)函數(shù)的,具體數(shù)值就是上面SetItemData函數(shù)中的dwData,所以剛才用了 SetItemData(i,i)的語句(至于能否將dwData設置成其他的數(shù)值,我認為應該也是沒有問題的,只要你覺得用這樣的參數(shù)在回調(diào)的排序函數(shù)中使用方便就行了)第二個參數(shù)是輸入給這個回調(diào)函數(shù)的一個參數(shù),一般都是對應CListCtrl對象的指針
最后就是實現(xiàn)那個回調(diào)函數(shù)了,msdn上說這個函數(shù)必須為獨立的函數(shù),或者是某個類中的靜態(tài)函數(shù),這點注意一下即可,以下為一個具體的回調(diào)函數(shù)的例子:
///////////////////////////////////////////
//按第六列排序
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("▼"))
{
return _tcscmp(strItem2.GetBuffer(MAX_PATH),strItem1.GetBuffer(MAX_PATH));
}
else if (csStr.Right(1) == CString("▲"))
{
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;
}
//////////////////////////////////////////// </!--v:3.2-->