CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    May 1999
    Posts
    17

    how to sort owner-drawn list control

    I want to use a column to sort a own-draw list control. Could somebody give me some clues? Thanks.


  2. #2

    Re: how to sort owner-drawn list control

    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>

  3. #3
    Join Date
    May 1999
    Posts
    17

    Re: how to sort owner-drawn list control

    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.


  4. #4

    Re: how to sort owner-drawn list control

    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>

  5. #5
    Join Date
    May 1999
    Posts
    17

    Re: how to sort owner-drawn list control

    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.


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured