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