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.
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.
My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.