Reputation: 33
I have extended CMFCListCtrl
class mainly to be able to easily sort by columns. From what I learned, it should be enough to implement Sort
and OnCompareItems
functions.
What happens is that sort works fine with 1st column which type is integer
but it gives strange ordering for 2nd column, which type is string
. There are no errors, ordering is changed but not alphabetically.
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);
}
Values I get in OnCompareItems
are ok for both columns. But the end result is valid only for the first one. Are there any other functions necessary for this to work?
Upvotes: 3
Views: 873
Reputation: 31609
CMFCListCtrl::Sort
will call CListCtrl::SortItems
. SortItems
will pass LPARAM
item data to the callback function. This LPARAM
is a value which can be set with SetItemData
.
That means the lParam1
and lParam2
in OnCompareItems
, refere to LPARAM
data only.
GetItemText(lParam1, iColumn)
is undefined behavior in this case because lParam1
does not refer to row number.
See also documentation for LVM_SORTITEMS
and LVM_SORTITEMSEX
Sort
and call SortItemsEx
instead. This way lParam1
and lParam2
will refer to row numbers, and GetItemText(lParam1, iColumn)
will be a valid call, as shown below. Note that (iColumn == 0)
condition is used only if SetItemData
was called earlier.
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);
}
Upvotes: 4