CListCtrl Sort

来源:互联网 发布:java final是什么意思 编辑:程序博客网 时间:2024/05/21 10:21
 

If we look at the documentation of CListCtrl::SortItems(...) in MSDN we find the following example of how to sort the items in reverse alphabetical order:

// Sort the item in reverse alphabetical order.
static int CALLBACK
MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// lParamSort contains a pointer to the list view control.
CListCtrl* pListCtrl = (CListCtrl*) lParamSort;
CString strItem1 = pListCtrl->GetItemText(lParam1, 0);
CString strItem2 = pListCtrl->GetItemText(lParam2, 0);

return strcmp(strItem2, strItem1);
}

void snip_CListCtrl_SortItems()
{
// The pointer to my list view control.
extern CListCtrl* pmyListCtrl;

// Sort the list view items using my callback procedure.
pmyListCtrl->SortItems(MyCompareProc, (LPARAM) pmyListCtrl);
}
This approach obviously does not work and here is why: The parameters of MyCompareProc(...) - lParam1 and lParam2 are not the index of the items but their 32-bit associated value.

There is a second problem: even if we set the 32-bit associated value of each item to be the same as the item's index this example will still not work. This is because the items will shift positions after each call to MyCompareProc(...) and the 32-bit associated values will no longer represent the item's index.

The function CListCtrl::SortItems(...) is only usefull if we store a pointer in the 32-bit associated value and we want to sort the items by some value that comes from that pointer.

One easy way of implementing reverse alphabetical sort in CListCtrl derived class is using an STL set:

 Collapse
#pragma warning(disable : 4786)
#include <functional>
#include <set>

struct LVITEM_less : public std::binary_function<LVITEM*, LVITEM*, bool>
{
bool operator()(const LVITEM* pItem1, const LVITEM* pItem2) const
{
CString strItem1(pItem1->pszText);
CString strItem2(pItem2->pszText);

return (strItem1 < strItem2);
}
};

void CSortableListCtrl::SortItemsDescending()
{
// Sort all items in descending aphabetical order using an STL set
typedef std::set<LVITEM*, LVITEM_less> ItemSet;
ItemSet setItems;
int iCount = GetItemCount();
for (int i = 0; i < iCount; i++)
{
LVITEM* pLVI = new LVITEM();
::memset(pLVI, 0, sizeof(LVITEM));
pLVI->iItem = i;
pLVI->mask = LVIF_IMAGE | LVIF_INDENT | LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
pLVI->pszText = new TCHAR[1024];
pLVI->cchTextMax = 1024;
GetItem(pLVI);

setItems.insert(pLVI);
}

// Remove all items from the list control
DeleteAllItems();

// Put the items back in the list control in reverse order
int iIndex = 0;
for (ItemSet::reverse_iterator it = setItems.rbegin(); it != setItems.rend(); ++it)
{
(*it)->iItem = iIndex++;
InsertItem(*it);
delete [] (*it)->pszText;
delete *it;
}
}

The comparison function is something you name and write yourself. Here is an example, where m_listAccts is a CListCtrl.

Use an LVN_COLUMNCLICK event handler:


void COrderSheetPage::OnColumnclickListAccounts(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

m_listAccts.SortItems( AcctsCompare, pNMListView-&gt;iSubItem);
*pResult = 0;
}




The callback can look something like this (note that the callback is static, not a class member):


// ITEMINFO is used in filling the Accounts list control
typedef struct tagITEMINFO{
CString cFirm;
CString cAcctNum;
CString cFileNum;
CString cTradeSize;
CString cProgram;
} ITEMINFO;

// Sorting function for the list of accounts
static int CALLBACK AcctsCompare( LPARAM lParam1, LPARAM lParam2, LPARAM dwData)
{
int nReturn;
int nCompare;
int nNum1;
int nNum2;

ITEMINFO* p1 = (ITEMINFO*) lParam1;
ITEMINFO* p2 = (ITEMINFO*) lParam2;

switch(dwData)
{
case 0: // firm
// if the firm is the same between the two, sort by account #
nCompare = p1-&gt;cFirm.CompareNoCase(p2-&gt;cFirm);
if(nCompare != 0)
{
nReturn = nCompare;
break;
}
// fall through to do account # comparison
case 1: // account #
nReturn = p1-&gt;cAcctNum.CompareNoCase(p2-&gt;cAcctNum);
break;
case 2: // file #
nNum1 = atoi(p1-&gt;cFileNum.GetBuffer(1));
nNum2 = atoi(p2-&gt;cFileNum.GetBuffer(1));
if(nNum1 == nNum2)
nReturn = 0;
else if(nNum1 &lt; nNum2)
nReturn = -1;
else
nReturn = 1;
break;
case 3: // trade size
nNum1 = atoi(p1-&gt;cTradeSize.GetBuffer(1));
nNum2 = atoi(p2-&gt;cTradeSize.GetBuffer(1));
if(nNum1 == nNum2)
nReturn = 0;
else if(nNum1 &lt; nNum2)
nReturn = -1;
else
nReturn = 1;
break;
case 4: // program
nReturn = p1-&gt;cProgram.CompareNoCase(p2-&gt;cProgram);
break;
}
return nReturn;
}


原创粉丝点击