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();
m_ctrlList.SetItemState(nItem,
LVIS_SELECTED, LVIS_SELECTED | LVIS_FOCUSED);
}
else
{
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.