Sort list (numeric/text) using callback

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

This is a small class which permits to sort list controls. It works "substituting" every original item data with a small class (preserving the value), sort it using the standard (fast!) list control way, and then putting the things right back.

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:00am

    Originally posted by: Bud Baker

    Thanks, Iuri.  CSortClass is almost what I was looking for, and a small addition made it exactly what I wanted.  I'm adding a Windows Explorer type view to a program, and like Explorer, I wanted a CListView that showed folders first, alphabetically, then files, alphabetically.  I managed to do this in two steps; the second is a small addition to your code.
    
    

    First, I made column one of each item show the file size. If the item was a folder, I made column one a blank text string (easy to do by checking the dwFileAttributes member of the WIN32_FIND_DATA I use to fill the CListCtrl).

    Next, I modified your CSortClass constructor to the following code:

    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);
    // my added code
    CString txt2 = pWnd->GetItemText(t, 1);
    if(txt2.GetLength() == 0)
    {
    txt2 = txt;
    txt = "\n";
    txt += txt2;
    }
    // end of my added code
    pWnd->SetItemData(t, (DWORD) new CSortItem(dw, txt));
    }
    }
    }

    All my added code does is check for the blank text string in column one (denoting a folder), and if it is found, it adds a newline character to the beginning of the sort column string (only for the sorting function). Since a newline character is always lower than text, the folders are shown first, in alphabetical order, then the files, also in alphabetical order. Clicking any column still shows folders first, then files.

    Reply
  • Excellent! Great solid class!

    Posted by Legacy on 03/20/2003 12:00am

    Originally posted by: Patrick

    This class provides everything I needed for evc++ applications, look above for needed modifications posted by another user!
    Thanks.

    Reply
  • Great job but...

    Posted by Legacy on 02/11/2003 12:00am

    Originally 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.
    Thanx for this great piece of code.

    Reply
  • It helps me very much, Thank you

    Posted by Legacy on 12/06/2002 12:00am

    Originally posted by: Bahman Ganji

    :) :)

    Reply
  • Excellent Work, I made slighty changes for eVC++

    Posted by Legacy on 07/10/2002 12:00am

    Originally posted by: devchand

    This is excellent class,it makes a work very easy.
    Thank you very much
    Dev

    Reply
  • Good Job. I got working on Microsoft eMbedded VC++ (Pocket PC)

    Posted by Legacy on 05/23/2002 12:00am

    Originally 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.

    Reply
  • Great job!!!

    Posted by Legacy on 05/08/2002 12:00am

    Originally posted by: Morten Strand

    Just what I was looking for. Works great. Thanks again.

    Ragards,
    Morten Strand

    Reply
  • Thank you very much..

    Posted by Legacy on 04/13/2002 12:00am

    Originally posted by: Daniel

    Thank you very much.. ^^;;

    Reply
  • Thans! very useful! *^^*

    Posted by Legacy on 12/26/2001 12:00am

    Originally posted by: kyuchong

    *^^*

    Reply
  • Nice Good! Useful SourceCode Thank You^^

    Posted by Legacy on 09/04/2001 12:00am

    Originally posted by: Lim Ji Soon

    "CListCtrl" hasn't simple Sort-Method~~~~~
    
    

    so, i fall in hell~~....

    but your Source-Code save me~

    Onemore-time Thank you! Good Luck!

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The software-defined data center (SDDC) and new trends in cloud and virtualization bring increased agility, automation, and intelligent services and management to all areas of the data center. Businesses can now more easily manage the entire lifecycle of their applications and services via the SDDC. This Aberdeen analyst report examines how a strong foundation in both the cloud and internal data centers is empowering organizations to fully leverage their IT infrastructure and is also preparing them to be able …

  • You know that visibility is critical to security. You simply can't secure what you can't see. Read this Gartner research note to learn why visibility through a continuous adaptive risk and trust assessment (CARTA) approach is key to securing digital business. Download now to learn eight ways this approach can be deployed to optimize the visibility into your organization's cloud services, mobile endpoints, and digital ecosystems.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date