在C++界面开发中,WLT::CListCtrl和MFC的CListCtrl都没有自动排序功能,不过他们都提供了一个回调函数,通过SortItems或者SortItemsEx方法来进行。激活SortItems方法,需要接受Column的Click事件,然后设置合适的数据,就可以实现自动排序了。
CListCtrl的排序
微软的VC++实在是个弱智的IDE,编程10小时,至少有5小时是在和windows作斗争,还是C++Builder好啊。不过微软横行霸道,Borland已经没有turbo c时代的雄风了,现在做WinCE的程序,不用VC++还不行。
CListCtrl是个让人头痛不已的控件,十分难用。CListCtrl的排序,是通过调用SortItems函数实现的。
BOOL SortItems(
PFNLVCOMPARE pfnCompare,
DWORD_PTR dwData
);
其中,
pfnCompare
是排序时被调用的回调函数,
dwData是调用SortItems时传给回调函数的参数,是回调函数的第三个参数。
pfnCompare的定义是:
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,
LPARAM lParamSort);
其中,lParam1、lParam2是和两个列表项相关的参数,这个参数在调用InsertItem/SetItem时,被存储于LVITEM::
lParam中。这个参数被用于标定列表项,是我们在排序和查找列表项的“特征”,就像人名用于标定一个人一样。设置LVITEM::
lParam是排序的关键,不设置这个变量,就无法找到进行比较的两个项目,调用SortItems()就不起作用。这一点,MSDN里面没有说的很清楚。
知道排序的原理,那么来看看具体的实现方法:
1. 添加回调函数
//********************************
// Call back funtion for sorting
//********************************
static int CALLBACK
MyCompareProc(LPARAM lParam1, //lParam1 and lParam2 are set //in LVITEM::lParam
LPARAM lParam2, //In this case, we associate
//it with item index;
LPARAM lParamSort //The parameter transfered
//from SortItem();
)
{
CSPListCtrl * pListCtrl = (CSPListCtrl*)lParamSort;
LVFINDINFO pInfo1, pInfo2;
pInfo1.flags = LVFI_PARAM;
pInfo2.flags = LVFI_PARAM;
pInfo1.lParam = lParam1;
pInfo2.lParam = lParam2;
int ind1 = pListCtrl->FindItem(&pInfo1);//根据在
//Insert/SetItem时
//指定的参数找到
//被比较的项目
int ind2 = pListCtrl->FindItem(&pInfo2);
//本例根据第一列项目(item)的名字排序,故读取项目的text:
//GetItemText第一个参数是项目号,实际是List行号,
//第二个参数是子项目号,实际是项目的列号,本例是0
//代表只对第一列的名字排序:
CString strItem1 = pListCtrl->GetItemText(ind1,0);
CString strItem2 = pListCtrl->GetItemText(ind2,0);
//进行比较,m_iSortAsc是自定义CListCtrl类中的int类型标志变量.
//用于指定按照降序还是升序排序:
return pListCtrl->m_iSortAsc ? lstrcmp( strItem1, strItem2 )
: lstrcmp( strItem2, strItem1 );
}
2. 在自定义的CListCtrl派生类中定义SortItem函数:
BOOL CSPListCtrl::SortItem(int sortup)
{
m_iSortAsc=sortup;
SortItems(MyCompareProc,(DWORD_PTR)this);
return 1;
}
3. 在插入/设置项目时,设置项目的标识参数lParam
没有这一步,是调用SortItems函数失败的关键。代码如下:
...............
//Insert items for the item:
item.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_STATE|LVIF_PARAM;
item.iItem =nrow;
item.iSubItem=ncol;
item.pszText=text;
item.iImage=nimg;
item.state=state;
//The parameter identifies the item:
item.lParam=(LPARAM)(nrow*100+ncol);
//Insert item:
if(nrow>=GetRowCount()&&ncol==0)
{
re=CListCtrl::InsertItem(&item);
}
//If the item exists
else if((nrow<GetRowCount()&&ncol<GetColCount())||ncol>0)
{
re=CListCtrl::SetItem(&item);
}
...............
4. 在使用ListCtrl的对话框类中,调用我们的派生类的SortItem函数:
...................
m_pListMain=(CSPListCtrl *) GetDlgItem(IDC_LISTMAIN);
...................
m_pListMain->SortItem();
...................
这里再就CListCtrl的项目说明一下。CListCtrl的项目分为项目和子项目,项目(item)就是列表某一行的第一列的元素,项目号实际就是行号,而该行第一列之后的叫子项目(subitem),子项目号实际就是列号。添加项目需要先添加第一列,再用InserItem()函数添加,而子项目的添加则不同,在添加列以后,只要调用SetItem()函数即可。