Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CListCtrl - one of the Blonde classes in MFC

8 Dec 2002 1  
Some dialogbox code to give the Blonde a clue

Introduction

I hate the CListCtrl class. Along with the CTreeCtrl, it's one of the most insanely unfinished classes in the entire MFC library. Don't bother arguing this point, my mind is made up, so you'll just end up being wrong anyway.

The problem

When I use a list control, I use it in report mode. Many of you probably also only use the CListCtrl in report mode. Lately, I've had cause to actually do something about some of the CListCtrl's shortcomings. I haven't had a reason yet to actually derive a new class, but I really should. This article discusses ways to take care of these things in your dialog box class itself. Deriving a new class and adding this behavior is left as an exercise for the reader.

What!? No function similar to GetCurSel()?

The CListBox control and the CComboBox control both have a function for retrieving the index number of the currently selected item. CListCtrl does NOT, so here's what I use.

int CMyDialog::GetSelectedItem()
{
    int nItem = -1;
    POSITION nPos = m_ctrlMyList.GetFirstSelectedItemPosition();
    if (nPos)
    {
        nItem = m_ctrlMyList.GetNextSelectedItem(nPos);
    return nItem;
}

Item highlight quirks

Okay, so you have your list control, and you click an item and as expected, a highlight bar appears. Cool. Now, if you click the a blank area under the last item in the list control, what happens? I'll tell you what happens - the highlight bar goes away. That's all well and good, but if you call the function I gave you above, guess what index number it returns. Wrong, it's NOT -1 (as you might expect), it's the index of the last item that was highlighted (or selected). How do you fix it? Handle the OnClick... and OnRclick... functions

void CMyDlg::OnClickList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_LISTVIEW* pNM = (NM_LISTVIEW*)pNMHDR;
    int nCount = m_ctrlList.GetItemCount();
    LVHITTESTINFO ht;
    ht.pt = pNM->ptAction;
    m_ctrlList.SubItemHitTest(&ht);
    if (ht.iItem < 0 || ht.iItem > nCount)
    {
        int nItem = GetSelectedItem();
        // re-establish the highlight bar on the last selected item 

        // (taking advantage of the control's bug)

        m_ctrlList.SetItemState(nItem, 
            LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
    }
    else
    {
        // highlight the item selected

        m_ctrlHostList.SetItemState(ht.iItem, 
            LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
    }
    *pResult = 0;
}

void CMyDlg::OnRclickList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_LISTVIEW* pNM = (NM_LISTVIEW*)pNMHDR;
    int nCount = m_ctrlList.GetItemCount();
    if (nCount > 0)
    {
        LVHITTESTINFO ht;
        ht.pt = pNM->ptAction;
        m_ctrlList.SubItemHitTest(&ht);
        if (ht.iItem < 0 || ht.iItem > nCount)
        {
            int nItem = GetSelectedItem();
            m_ctrlList.SetItemState(nItem, 
                LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
        }
        else
        {
            m_ctrlList.SetItemState(ht.iItem, 
                LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
        }
    }
    *pResult = 0;
}

Have a ball, and remember, I've only used this in report mode.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here