|
If you have access to the MSDN library CD (which IMHO is
pretty much a requirement for Windows development) it
includes the text and source code for the book 'Programming
the Windows '95 UI', most of which is also applicable to
Windows NT. This book has a chapter on the CListCtrl/
CListView, which includes a code sample MFCLIST which
supports sorting of column data via. an application-defined
comparison function called from CListCtrl::SortItems()
when the user clicks a column heading.
The essential parts of the code are attached, but you
really need the MSDN CD article or the hardcopy book
for a full explanation.
The MFCList sample is bit more complex because it manages
its own data via. an application-defined HOUSEINFO
structure. This is done by setting
LV_ITEM.pszText = LPSTR_TEXTCALLBACK. The application
supplies the data for display in response to LVN_GETDISPINFO
BTW, I don't understand your comment that:
I am using the callback to automatically sort the column. However, I
cannot figure out from the documentation how I can select the item and
how to report it back to the app since everything is embedded in the
LV_ITEM structure.
As described in the documentation for CListCtrl, all your
application-defined comparison function has to return is a negative
value if the first item should precede the second, a positive value
if the first item should follow the second, or zero if the two items
are equivalent. You can pass an additional optional parameter to
your comparison function to tell it what column you want sorted
- in the MFCLIST example, this is determined by the sub-item
index of the column heading which the user has clicked.
LRESULT CMfclistView::NotifyHandler(UINT message, WPARAM wParam, LPARAM lParam)
{
LV_DISPINFO *pLvdi = (LV_DISPINFO *)lParam;
NM_LISTVIEW *pNm = (NM_LISTVIEW *)lParam;
HOUSEINFO *pHouse = (HOUSEINFO *)(pLvdi->item.lParam);
static char szText[64];
if (wParam != ID_LISTVIEW)
return 0L;
switch(pLvdi->hdr.code)
{
case LVN_GETDISPINFO:
switch (pLvdi->item.iSubItem)
{
case 0: // Address
pLvdi->item.pszText = pHouse->szAddress;
break;
case 1: // City
pLvdi->item.pszText = pHouse->szCity;
break;
case 2: // Price
sprintf(szText, "$%u", pHouse->iPrice);
pLvdi->item.pszText = szText;
break;
case 3: // Number of bedrooms
sprintf(szText, "%u", pHouse->iBeds);
pLvdi->item.pszText = szText;
break;
case 4: // Number of bathrooms
sprintf(szText, "%u", pHouse->iBaths);
pLvdi->item.pszText = szText;
break;
default:
break;
}
break;
case LVN_BEGINLABELEDIT:
{
CEdit *pEdit;
// Get the handle to the edit control.
pEdit = m_ListCtl.GetEditControl();
// Limit the amount of text that teh user can enter.
pEdit->LimitText(20);
}
break;
case LVN_ENDLABELEDIT:
// If label editing wasn't cancelled and the
// text buffer is non-NULL...
if ((pLvdi->item.iItem != -1) && (pLvdi->item.pszText != NULL))
// save the new label information.
lstrcpy(pHouse->szAddress, pLvdi->item.pszText);
break;
case LVN_COLUMNCLICK:
// The user clicked on one of the column headings - sort by
// this column.
m_ListCtl.SortItems( ListViewCompareProc,
(LPARAM)(pNm->iSubItem));
break;
default:
break;
}
return 0L;
}
// this is static
int CALLBACK CMfclistView::ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
HOUSEINFO *pHouse1 = (HOUSEINFO *)lParam1;
HOUSEINFO *pHouse2 = (HOUSEINFO *)lParam2;
LPSTR lpStr1, lpStr2;
int iResult;
if (pHouse1 && pHouse2)
{
switch( lParamSort)
{
case 0: // sort by Address
lpStr1 = pHouse1->szAddress;
lpStr2 = pHouse2->szAddress;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
case 1: // sort by City
lpStr1 = pHouse1->szCity;
lpStr2 = pHouse2->szCity;
iResult = lstrcmpi(lpStr1, lpStr2);
break;
case 2: // sort by Price
iResult = pHouse1->iPrice - pHouse2->iPrice;
break;
case 3: // sort by the number of bedrooms
iResult = pHouse1->iBeds - pHouse2->iBeds;
break;
case 4: // sort by the number of bathrooms
iResult = pHouse1->iBaths - pHouse2->iBaths;
break;
default:
iResult = 0;
break;
}
}
return(iResult);
}
LRESULT CMfclistView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_NOTIFY)
NotifyHandler(message, wParam, lParam);
return CView::WindowProc(message, wParam, lParam);
}
|
| I am able to sort the column following the example in the Window 95
book. However, I am not sure how 'selected' item(s) can be reported
to the applications. For example, I would like to know when the
user select the item using callback. I look at the NM_CLICK message
but I cannot figure out the 'state' of the item and the documentation
did not mention anything regarding the header pass with the message.
So, what I did was to loop through every single item in the list and
check the state using 'GetItemState()' to determine which item(s) is
being selected. I think there must be a better way to do this.
Mike
|
|
You can simplify your code a lot (depending on your application and
needs) by handling the OnItemChanged message. This will allow you to
ignore a plethora of messages, except those where some item's state
really changed.
Once inside this routine, you can use the GetNextItem call referenced
in the previous reply.
Brian
|