如何强制CListCtrl始终选择一个项目?

时间:2012-10-25 15:26:22

标签: c++ visual-c++ mfc clistctrl

我希望CListCtrl始终具有所选项目,例如单选按钮的集合。

我使用了样式:LVS_SHOWSELALWAYS|LVS_SINGLESEL

我一直在为此寻找一种风格,但未能找到它。

4 个答案:

答案 0 :(得分:2)

处理WM_LBUTTONDOWN。在CListCtrl派生类中,添加

MyListCtrl.cpp:

BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
    ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
    UINT uHitFlags;
    int nItem = HitTest(point, &uHitFlags);

    if (uHitFlags & LVHT_NOWHERE)
    {
        // eat the message by just returning
        return;
    }

    CListCtrl::OnLButtonDown(nFlags, point);
}

这将阻止鼠标单击进入控件并吃掉该消息。您仍然可以通过编程方式删除选择,但用户将无法点击商品下方空白区域中的任意位置来删除选择。

答案 1 :(得分:1)

我认为没有内置的支持。

从一开始就选择的部分很简单:只需在填充列表后选择一个项目:

// Populate the list
// ...

c_MyList.SetItemState(nItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);

另一部分,当用户点击所有项目时,阻止取消选择所有项目,这是非常棘手的。您可以轻松检测列表是否取消选择某个项目,但不能检测该项目是否正在丢失所选状态。即您无法判断是否取消选择另一个或未选中所有项目。原因是控件首先发送“项目X已被取消选择”通知,然后“项目Y已被选中”通知。如果没有选择任何项目,则会获得第一个项目,但不会获得第二个项目。

我想到的一个小想法是捕获NM_CLICK通知并阻止控件取消选择该项目。 所有选择/取消选择通知后,问题是发送 NM_CLICK。

所以,这是我提出的一个小黑客:当一个项目失去所选状态时,存储其项目索引。然后在NM_CLICK通知中,如果激活的项目为-1,则再次选择最后一个未选择的项目:

void CMyDialog::OnLvnItemchangedListaEjesPane(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

    if (pNMLV->uChanged & LVIF_STATE)
    {
        UINT oldSelectionState = (pNMLV->uOldState & LVIS_SELECTED);
        UINT newSelectionState = (pNMLV->uNewState & LVIS_SELECTED);

        if ( oldSelectionState == LVIS_SELECTED && newSelectionState == 0 )
        {   // Deselect item
            m_LastDeselectedItem = pNMLV->iItem;
        }
        // ...
    }

    *pResult = 0;
}

void CMyDialog::OnNMClickListaEjesPane(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);

    if (pNMItemActivate->iItem == -1)
    {
        c_ListaEjes.SetItemState(m_LastDeselectedItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
    }
    *pResult = 0;
}

它可能无法完全满足您的需求,因为它实际上取消选择该项目然后再次选择它。

可能有更好的解决方案,包括创建自己的CListCtrl子类并拦截点击,检查它们是否会强制进行空选择并阻止它,但你必须确定额外的工作是否值得。

答案 2 :(得分:0)

在设计clistctrl时,只需在对话框编辑器中完成此操作,将属性中的“始终显示选择”和“单选”选项设置为true即可。如果你想通过代码这样做,那么你有正确的方法,但错误的地方。覆盖OnInitDialog并在其中首先调用CDialog :: OnInitDialog,然后设置新样式(使用ModifyStyle)。问题是基类覆盖了样式更改。除此之外,它可能是一些东西,MFC并不以其直观性而着称!

答案 3 :(得分:0)

我解决了这个问题如下:

  1. 我添加名为lastItem
  2. 的对话框新变量
  3. 处理LVN_ITEMCHANGING消息并添加以下行:

    lastItem = pNMLV->iItem;
    
  4. 处理NM_CLICK,NM_DBLCLK,NM_RCLICK和NM_RDBLCLK消息,并将这些行添加到所有消息中:

    CListCtrl * listCtrl = (CListCtrl *)FromHandle(pNMHDR->hwndFrom);
    if (pNMItemActivate->iItem == -1)
        listCtrl->SetItemState(m_lastItem, LVIS_SELECTED, LVIS_SELECTED);