排序CMFCListCtrl时出现奇怪行为

Strange behaviour while sorting CMFCListCtrl

本文关键字:CMFCListCtrl 排序      更新时间:2023-10-16

我扩展了CMFCListCtrl类,主要是为了能够轻松地按列排序。根据我的经验,实现SortOnCompareItems功能就足够了。

发生的情况是,排序对第一列(类型为integer(很好,但对第二列(类型是string(给出了奇怪的排序。没有错误,排序是更改的,但不是按字母顺序排列的。


int MyCMFCListCtrl::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int iColumn)
{
if (iColumn == 0)
{
if (lParam1 > lParam2)
return -1;
else if (lParam1 < lParam2)
return 1;
else
return 0;
}
else if (iColumn == 1)
{
CString strCol1, strCol2;
strCol1 = GetItemText(lParam1, iColumn);
strCol2 = GetItemText(lParam2, iColumn);
return strCol1.Compare(strCol2);
}
return 0;
}
void MyCMFCListCtrl::Sort(int iColumn, BOOL bAscending, BOOL bAdd)
{
// Sort available for first and second column
if (iColumn > 1) return;
CMFCListCtrl::Sort(iColumn, bAscending, bAdd);
}

我在OnCompareItems中得到的值对这两列都可以。但最终结果只对第一个有效。是否有其他必要的功能使其发挥作用?

CMFCListCtrl::Sort将调用CListCtrl::SortItemsSortItems将向回调函数传递LPARAM项数据。该CCD_ 11是可以用CCD_ 12设置的值。

这意味着OnCompareItems中的lParam1lParam2仅参考LPARAM数据。

在这种情况下,GetItemText(lParam1, iColumn)是未定义的行为,因为lParam1不引用行号。

另请参阅LVM_SORTITEMSLVM_SORTITEMSEX的文档


您可以覆盖Sort并调用SortItemsEx。这样,lParam1lParam2将引用行号,而GetItemText(lParam1, iColumn)将是一个有效的调用,如下所示。注意,(iColumn == 0)条件仅在先前调用SetItemData的情况下使用。

int MyCMFCListCtrl::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int iColumn)
{
if(iColumn == 0)//assuming SetItemData was called earlier
return lParam1 - lParam2;
CString strCol1 = GetItemText(lParam1, iColumn);
CString strCol2 = GetItemText(lParam2, iColumn);
return strCol1.Compare(strCol2);
}
void MyCMFCListCtrl::Sort(int iColumn, BOOL bAscending, BOOL bAdd)
{
if(iColumn == 0)//assuming SetItemData was called earlier
{
//call SortItem and get LPARAM data in call back function
CMFCListCtrl::Sort(iColumn, bAscending, bAdd);
return;
}
//call SortItemEx instead, get row numbers in callback function
CWaitCursor wait;
GetHeaderCtrl().SetSortColumn(iColumn, bAscending, bAdd);
m_iSortedColumn = iColumn;
m_bAscending = bAscending;
SortItemsEx(CompareProc, (LPARAM)this);
}