Sort list (numeric/text) using callback
Posted
by Iuri Apollonio
on August 6th, 1998
Step 1: implementing the class
The class will contain two subclasses to manage numeric and text column data. The numeric is provided to avoid the sorting of 11 before 2 as it would occur with string comparison; there are also 4 comparing routines (for ascending and descending text and integer columns).The header file of the class should be like this:
class CSortClass
{
public:
CSortClass(CListCtrl * _pWnd, const int _iCol, const bool _bIsNumeric);
virtual ~CSortClass();
int iCol;
CListCtrl * pWnd;
bool bIsNumeric;
void Sort(const bool bAsc);
static int CALLBACK CompareAsc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
static int CALLBACK CompareDes(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
static int CALLBACK CompareAscI(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
static int CALLBACK CompareDesI(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
public:
class CSortItem
{
public:
virtual ~CSortItem();
CSortItem(const DWORD _dw, const CString &_txt);
CString txt;
DWORD dw;
};
class CSortItemInt
{
public:
CSortItemInt(const DWORD _dw, const CString &_txt);
int iInt ;
DWORD dw;
};
};
The CPP file will implement all the above:
/////////////////////////////////////////////////////////////////////////////
// CSortClass
CSortClass::CSortClass(CListCtrl * _pWnd, const int _iCol, const bool _bIsNumeric)
{
iCol = _iCol;
pWnd = _pWnd;
bIsNumeric = _bIsNumeric;
ASSERT(pWnd);
int max = pWnd->GetItemCount();
DWORD dw;
CString txt;
if (bIsNumeric)
{
for (int t = 0; t < max; t++)
{
dw = pWnd->GetItemData(t);
txt = pWnd->GetItemText(t, iCol);
pWnd->SetItemData(t, (DWORD) new CSortItemInt(dw, txt));
}
}
else
{
for (int t = 0; t < max; t++)
{
dw = pWnd->GetItemData(t);
txt = pWnd->GetItemText(t, iCol);
pWnd->SetItemData(t, (DWORD) new CSortItem(dw, txt));
}
}
}
CSortClass::~CSortClass()
{
ASSERT(pWnd);
int max = pWnd->GetItemCount();
if (bIsNumeric)
{
CSortItemInt * pItem;
for (int t = 0; t < max; t++)
{
pItem = (CSortItemInt *) pWnd->GetItemData(t);
ASSERT(pItem);
pWnd->SetItemData(t, pItem->dw);
delete pItem;
}
}
else
{
CSortItem * pItem;
for (int t = 0; t < max; t++)
{
pItem = (CSortItem *) pWnd->GetItemData(t);
ASSERT(pItem);
pWnd->SetItemData(t, pItem->dw);
delete pItem;
}
}
}
void
CSortClass::Sort(const bool bAsc)
{
if (bIsNumeric)
{
if (bAsc)
pWnd->SortItems(CompareAscI, 0L);
else
pWnd->SortItems(CompareDesI, 0L);
}
else
{
if (bAsc)
pWnd->SortItems(CompareAsc, 0L);
else
pWnd->SortItems(CompareDes, 0L);
}
}
int CALLBACK CSortClass::CompareAsc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CSortItem * i1 = (CSortItem *) lParam1;
CSortItem * i2 = (CSortItem *) lParam2;
ASSERT(i1 && i2);
return i1->txt.CompareNoCase(i2->txt);
}
int CALLBACK CSortClass::CompareDes(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CSortItem * i1 = (CSortItem *) lParam1;
CSortItem * i2 = (CSortItem *) lParam2;
ASSERT(i1 && i2);
return i2->txt.CompareNoCase(i1->txt);
}
int CALLBACK CSortClass::CompareAscI(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CSortItemInt * i1 = (CSortItemInt *) lParam1;
CSortItemInt * i2 = (CSortItemInt *) lParam2;
ASSERT(i1 && i2);
if (i1->iInt == i2->iInt) return 0;
return i1->iInt > i2->iInt ? 1 : -1;
}
int CALLBACK CSortClass::CompareDesI(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CSortItemInt * i1 = (CSortItemInt *) lParam1;
CSortItemInt * i2 = (CSortItemInt *) lParam2;
ASSERT(i1 && i2);
if (i1->iInt == i2->iInt) return 0;
return i1->iInt < i2->iInt ? 1 : -1;
}
CSortClass::CSortItem::CSortItem(const DWORD _dw, const CString & _txt)
{
dw = _dw;
txt = _txt;
}
CSortClass::CSortItem::~CSortItem()
{
}
CSortClass::CSortItemInt::CSortItemInt(const DWORD _dw, const CString & _txt)
{
iInt = atoi(_txt);
dw = _dw;
}
Step 2: using it
The class is designed to be easy usable. In answer to a column click message in a list control, we can write something like this:
void CMyListCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
// bAscending will be use to order from lower to higher or higher to lower
bool bAscending = true;
CSortClass csc(this, pNMListView->iSubItem, bAscending);
csc.Sort(bAsc);
*pResult = 0;
}

Comments
Adding a double sort
Posted by Legacy on 03/31/2003 12:00amOriginally posted by: Bud Baker
ReplyExcellent! Great solid class!
Posted by Legacy on 03/20/2003 12:00amOriginally posted by: Patrick
This class provides everything I needed for evc++ applications, look above for needed modifications posted by another user!
ReplyThanks.
Great job but...
Posted by Legacy on 02/11/2003 12:00amOriginally posted by: Simon
Do you have any clue on how to mark the sorted column with an arrow to see which one is sorted and if the sort is ascendent or not.
ReplyThanx for this great piece of code.
It helps me very much, Thank you
Posted by Legacy on 12/06/2002 12:00amOriginally posted by: Bahman Ganji
:) :)
Reply
Excellent Work, I made slighty changes for eVC++
Posted by Legacy on 07/10/2002 12:00amOriginally posted by: devchand
This is excellent class,it makes a work very easy.
ReplyThank you very much
Dev
Good Job. I got working on Microsoft eMbedded VC++ (Pocket PC)
Posted by Legacy on 05/23/2002 12:00amOriginally posted by: Mike Dawn
Hi:
I want to thank you. I use this code, and modify a little bit for embedded Pocket PC. It work great.
Mike D.
ReplyGreat job!!!
Posted by Legacy on 05/08/2002 12:00amOriginally posted by: Morten Strand
Just what I was looking for. Works great. Thanks again.
Ragards,
ReplyMorten Strand
Thank you very much..
Posted by Legacy on 04/13/2002 12:00amOriginally posted by: Daniel
Thank you very much.. ^^;;
Reply
Thans! very useful! *^^*
Posted by Legacy on 12/26/2001 12:00amOriginally posted by: kyuchong
*^^*
ReplyNice Good! Useful SourceCode Thank You^^
Posted by Legacy on 09/04/2001 12:00amOriginally posted by: Lim Ji Soon
ReplyLoading, Please Wait ...