MFC中使CListCTrl控件排序

列表控件(CList
Ctrl)的排序功能 不像其它直接调用AP I就可以完成的功能一 样.它比较复杂.今天 将我的一点体会简单地 谈一下. 列表控件的顶部有一排 按钮,用户可以通过选 择不同的列来对记录进 行排序。但是 CListCtrl并 没有自动排序的功能, 我们需要自己添加一个 用于排序的回调函数来 比较两个数据的大小, 此外还需要响应排序按 钮被点击的消息。回调 函数就好像是一个中断 处理函数,操作系统在 符合你设定的条件时自 动调用。
·CListCtrl 提供了用于排序的函数
函数原型为:
BOOL CListCtrl: :SortItems ( PFNLVCOMPA RE pfnCompare , DWORD dwData);
其中第一个参数为全局 排序函数(它就是回调 函数)的地址,
第二个参数为用户数据 ,你可以根据你的需要 传递一个数据或是指针 。
该函数返回-1,代表 第一项排应在第二项前 面;
返回1代表第一项排应 在第二项后面;
返回0代表两项相等。 ·排序函数原形为:
int CALLBACK ListCompar e(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort );
其中第三个参数为调用 者传递的数据(即调用 SortItems时 的第二个参数dwDa ta)。
第一和第二个参数为用 于比较的两项的Ite mData,你可以通 过DWORD CListCtrl: :GetItemDa ta( int nItem )/
BOOL CListCtrl: :SetItemDa ta( int nItem, DWORD dwData )来对每一项的Ite mData进行存取。 在添加项时选用特定的 CListCtrl: :InsertIte m也可以设置该值。由 于你在排序时只能通过 该值来确定项的位置所 以你应该比较明确的确 定该值的含义。
·我们什么时候需要排 序(消息映射)呢?
实现这点可以在父窗口 中对LVN_COLU MNCLICK消息进 行处理来实现。例子:
//排序回调函数实现
static int CALLBACK MyCompareP roc(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- >GetItemTe xt(lParam1 , 0);
CString strItem2 = pListCtrl- >GetItemTe xt(lParam2 , 0);
//比较两个数
LPCTSTR s1=(LPCTST R)strItem1 ;
LPCTSTR s2=(LPCTST R)strItem2 ;

int n1=atoi(s1 );
int n2=atoi(s2 );if (n1>n2)
return -1;
else
return 1;
}
void C***::OnCo lumnclickL ist(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIE W* pNMListVie w = (NM_LISTVI EW*)pNMHDR ;
// TODO: Add your control notificati on handler code here //调用排序函数
m_ShowData .SortItems ( MyCompareP roc, (DWORD)&m_ ShowData );
*pResult = 0;}

整个过程是这样的: 当你点击列表控件的表 头时,此时它会向父窗 口发送LVN_COL UMNCLICK消息 ,此时响应函数OnC olumnclick List(),在该函 数里面再调用列表控件 的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,所以刚才用了 SetItemData(i,i)的语句(至于能否将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("▼"))
{
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 -->


你可能感兴趣的:(MFC中使CListCTrl控件排序)