如何强制clistctrl总是选择一个项目

How to force a CListCtrl to always have one item selected?

本文关键字:一个 项目 选择 何强制 clistctrl      更新时间:2023-10-16

我希望一个clistctrl总是拥有选定的项目,例如收集按钮的集合。

我使用了样式:LVS_SHOWSELALWAYS|LVS_SINGLESEL

我一直在为此寻找一种样式,但找不到它。

处理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);
}

这将防止鼠标点击进入控制并食用消息。您仍然可以通过编程方式删除选择,但是用户将无法单击项目下方的空白区域中的任何地方以删除选择。

我认为对此没有内置支持。

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

// Populate the list
// ...
c_MyList.SetItemState(nItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);

另一部分是在用户单击所有项目外的所有项目时阻止所有项目的取消选择,这更棘手。您可以轻松地检测列表是否取消了项目,而不是为什么该项目丢失所选状态的原因。IE。您无法判断它是取消选择的选择,以选择另一个项目或将所有未选择的项目留下。原因是控件首先发送"项目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子类并拦截点击,检查它们是否要强制无效选择并防止它,但是您必须决定是否值得付出麻烦。

当您设计clistCtrl时,可以在对话框编辑器中完成此操作,在属性中设置"始终显示选择"answers"单个选择"选项。如果您想通过代码执行此操作,那么您有正确的方法,但可以使用错误的位置。首先将OnInitdialog覆盖,并在其中调用Cdialog :: Oninitdialog,然后在此之后设置新样式(使用modifyStyle)。问题是基类正在覆盖您的样式变化。除此之外,可能是一些事情,MFC并不以其直觉而闻名!

我解决了此问题,如下所示:

  1. 我添加对话框的新变量nate lastItem
  2. 处理lvn_itemchanging消息并添加此行:

    lastItem = pNMLV->iItem;
    
  3. 处理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);
    
相关文章: