junpin Li
April 13th, 1999, 09:19 PM
I want to use a column to sort a own-draw list control. Could somebody give me some clues? Thanks.
|
Click to See Complete Forum and Search --> : how to sort owner-drawn list control junpin Li April 13th, 1999, 09:19 PM I want to use a column to sort a own-draw list control. Could somebody give me some clues? Thanks. LALeonard April 14th, 1999, 12:59 PM Do this in your CListCtrl-derived class. BEGIN_MESSAGE_MAP(MyListCtrl, CListCtrl) //{{AFX_MSG_MAP(MyListCtrl) ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick) END_MESSAGE_MAP() // This is a reflected message handler, which means that this control // handles this message instead of the parent window. Any handler // for this message in the parent window will override this handler // (unless it calls this handler first, of course). void MyListCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR; SortColumn(pNMListView->iSubItem); *pResult = 0; } // Split this code out so that it can be called from outside this class. void MyListCtrl::SortColumn(int nColumn, bool bToggle /* = true */ ) { // If a different column is being sorted from the last time we // sorted, we always start off ascending. if (nColumn != m_nColumnSort) { m_bSortAscending = ! TRUE; } else if (bToggle) { m_bSortAscending = ! m_bSortAscending; } m_nColumnSort = nColumn; _ASSERTE(IsColumn(m_nColumnSort)); // Now, the only way the CListCtrl can know how to sort is by each // item's LPARAM, so let's see if the first item has one. If so, // we assume they all do, and use them; otherwise, we use the item number! BOOL bHasLparams(IsItem(0) && GetItemData(0)); if (! bHasLparams) { for (int nItem = 0; IsItem(nItem); nItem++) { VERIFY(SetItemData(nItem, nItem)); } } // Call the sort routine the first time. (Make sure we do an alphabetic sort.) m_bNumericSort = false; VERIFY(SortItems(CompareFunc, reinterpret_cast <DWORD> (this))); // If the first and last item contain only numeric strings, it's a // safe bet that this is a numeric column. if (0 < GetItemCount()) { CString sChars("$.%, 0123456789"); CString sFirst(GetItemTextWorks(0, m_nColumnSort)); CString sLast(GetItemTextWorks(GetItemCount() - 1, m_nColumnSort)); m_bNumericSort = (NULL == _strspnp(sFirst, sChars) && NULL == _strspnp(sLast, sChars)); //TRACE1("Setting numeric sort flag to %s\n", m_bNumericSort ? "true" : "false"); // Call the sort routine the second time for a numeric sort. if (m_bNumericSort) { VERIFY(SortItems(CompareFunc, reinterpret_cast <DWORD> (this))); } } // I set the lParams back to zero so that stale data isn't hanging around // (because the sort has changed the item numbers). if (! bHasLparams) { for (int nItem = 0; IsItem(nItem); nItem++) { VERIFY(SetItemData(nItem, 0)); } } } // This is the function that the base CListCtrl code calls whenever it // needs to compare two items. /* static */ int CALLBACK MyListCtrl::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { // Retrieve the "this" we packaged in OnColumnclick(). MyListCtrl* pListCtrl = reinterpret_cast <MyListCtrl*> (lParamSort); ASSERT_VALID(pListCtrl); // Retrieve the two items to compare. LV_FINDINFO lvi; ::ZeroMemory(&lvi, sizeof(lvi)); lvi.flags = LVFI_PARAM; lvi.lParam = lParam1; int nItem1(pListCtrl->FindItem(&lvi)); _ASSERTE(-1 != nItem1); lvi.lParam = lParam2; int nItem2(pListCtrl->FindItem(&lvi)); _ASSERTE(-1 != nItem2); // Now get the two strings to compare. CString s1(pListCtrl->GetItemTextWorks(nItem1, pListCtrl->m_nColumnSort)); CString s2(pListCtrl->GetItemTextWorks(nItem2, pListCtrl->m_nColumnSort)); // Now compare them, remembering to take into account which direction // we are sorting in at the moment. "The comparison function must return // 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." int nReturn(0); // Numeric sort. if (pListCtrl->m_bNumericSort) { nReturn = atoi(s1) - atoi(s2); if (! pListCtrl->m_bSortAscending) { nReturn = -nReturn; } } else { // Alphabetic sort. nReturn = s1.CompareNoCase(s2); if (! pListCtrl->m_bSortAscending) { nReturn = -nReturn; } } return nReturn; } <HR>LA Leonard - <A HREF="http://www.DefinitiveSolutions.com/">Definitive Solutions, Inc.</A> junpin Li April 15th, 1999, 07:58 PM Thanks for help. I tried the codes but not very successful. There are two functions missing: IsItem(), IsColumn(). I programmed IsItem by checking if it is in the range (nItem < GetItemCount()). IsColumn() by returning GetColumn(nCol, &lv_column). The _strspnp() is undeclared though I included tchar.h (I forced false numericsorting). After these, I got sorted results only when I clicked column three times (first time, nothing, 2nd, a little bit sorting, 3rd, works fine) Can you tell me why? and how you i,plement IsColumn, and IsItem? Thanks a lot. LALeonard April 16th, 1999, 08:36 AM Oops, sorry... here they are: // Does the sent item exist? BOOL MyListCtrl::IsItem(int nItem) const { _ASSERTE(0 <= nItem); return -1 < nItem && GetItemCount() > nItem; } // Does the sent column exist? BOOL MyListCtrl::IsColumn(int nCol) const { _ASSERTE(0 <= nCol); LV_COLUMN lvc; ::ZeroMemory(&lvc, sizeof(lvc)); lvc.mask = LVCF_WIDTH; return -1 < nCol && GetColumn(nCol, &lvc); } HTH. <HR>LA Leonard - <A HREF="http://www.DefinitiveSolutions.com/">Definitive Solutions, Inc.</A> junpin Li April 16th, 1999, 09:41 PM Thanks again. I implemented IsItem, IsColumn almost the same you did. But you still didn't anwser the following questions: 1) _strspnp compile error (though I include tchar.h) 2) I didn't get sorted results until I click the column head the third time. After tha it works fine on any column. I appreciate if you can explain that. codeguru.com
Copyright Internet.com Inc., All Rights Reserved. |