dcsimg
 

Determining row indices in Sorting Comparison function

Thursday Aug 6th 1998 by Kamalahasan Rajaram

Determining row indices in Sorting Comparison function

The Sorting mechanism ( SortItems() ) of CListCtrl, does not provide us with the row indices inside the Comparison function. Without the row indices, the easiest way to get to our data inside the function is to store the text data in memory and set it's pointer as the LPARAM for each row. If the requirement is to sort the ListCtrl based on the item text alone, we shouldn't have to waste this memory. In such cases the following code can be used. It uses the FindItem() to determine the row index by using the LPARAM passed to the comparison function. Once we have the row index, we can use the GetItemText() to get the text. The pre-requisite of using this method is to set the LPARAM of each row to a unique value - a simple serial number will do. Compared to the sorting routines based on QuickSort provided by many in this site, this method was faster upto 5000 rows. After this threshold the FindItem() becomes slower and the custom sorting routines were much more faster.


/////////////////////////////////////////////////////////////////////////////
// SortInfo structure definition
typedef struct tagSortInfo
{
	CListCtrl * pListControl;
	int	nColumnNo;
	bool nAscendingSortOrder;
}SortInfo;

/////////////////////////////////////////////////////////////////////////////
// CTestDialog dialog

class CTestDialog : public CDialog
{
public:
	CTestDialog(CWnd* pParent = NULL);   // standard constructor
//Dialog Data
	//{{AFX_DATA(CTestDialog)
	enum { IDD = IDD_DIALOG1 };
	CListCtrl	m_ListControl;
	//}}AFX_DATA
// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CTestDialog)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

	static int CALLBACK SortList(LPARAM lpOne, LPARAM lpTwo, LPARAM lpArg);
// Implementation
	SortInfo m_SortInfo;
protected:
	// Generated message map functions
	//{{AFX_MSG(CTestDialog)
	//}}AFX_MSG
	afx_msg void OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult);
	
	DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////
//
void CTestDialog::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
	HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
	if(phdn->iButton == 0)
	{
		if (phdn->iItem == m_SortInfo.nColumnNo)
			m_SortInfo.nAscendingSortOrder = !m_SortInfo.nAscendingSortOrder;
		else
			m_SortInfo.nAscendingSortOrder = TRUE;

		m_SortInfo.nColumnNo = phdn->iItem;
		m_SortInfo.pListControl = &m_ListControl;

		m_ListControl.SortItems( SortList,(DWORD)&m_SortInfo );
	}
	*pResult = 0;
}

int CALLBACK CTestDialog::SortList(LPARAM lpOne, LPARAM lpTwo, LPARAM lpArg)
{
	int nResult 			= 0;
	SortInfo * pSortInfo 		= (SortInfo *) lpArg;

	int nColumnNo 			= pSortInfo->nColumnNo;
	CListCtrl * pListControl 	= pSortInfo->pListControl;
	bool nAscendingSortOrder 	= pSortInfo->nAscendingSortOrder;

	int lFirstData = -1, lSecondData = -1;

	LV_FINDINFO FindInfo;
	// use LVFI_WRAP for cases where lpTwo represents a row before lpOne
	FindInfo.flags = LVFI_PARAM | LVFI_WRAP;
	FindInfo.lParam = lpOne;
	lFirstData = pListControl->FindItem(&FindInfo);

	FindInfo.lParam = lpTwo;
	// reduce searching time by setting the start row as lFirstData
	lSecondData = pListControl->FindItem(&FindInfo,lFirstData);
	// because we are searching for LPARAM sent to us, FindItem() on 
	// these values should always be successful
	ASSERT(lFirstData != -1); ASSERT(lSecondData != -1);

	CString FirstText = pListControl->GetItemText(lFirstData,nColumnNo);
	CString SecondText = pListControl->GetItemText(lSecondData,nColumnNo);
	
	int nCompareValue = FirstText.Compare(SecondText);
	nResult = nCompareValue * ((nAscendingSortOrder)?1:-1);
	// or
	// your own comparison code

	return nResult;
}

Last updated: 5 August 1998

Home
Mobile Site | Full Site
Copyright 2018 © QuinStreet Inc. All Rights Reserved