2

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

我使用了以下样式:LVS_SHOWSELALWAYS|LVS_SINGLESEL

我一直在寻找这种风格,但一直找不到。

4

4 回答 4

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

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

于 2013-09-13T20:15:50.790 回答
1

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

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

// Populate the list
// ...

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

另一部分,当用户在所有项目之外单击时防止取消选择所有项目,则比较棘手。您可以轻松检测列表是否取消选择项目,但不能检测项目为何失去选定状态。即,您无法判断它是取消选择它以选择另一个还是未选择所有项目。原因是控件先发送“item X has been deselected”通知,然后是“item Y has been selected”通知。如果未选择任何项目,您将获得第一个,但不会获得第二个。

我想到的一个小想法是捕获 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 子类并拦截点击,检查它们是否会强制进行空选择并阻止它,但您必须确定额外的工作是否值得麻烦。

于 2012-10-26T08:26:13.127 回答
0

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

于 2012-10-25T15:47:53.437 回答
0

我解决了这个问题如下:

  1. 我在对话框中添加名为 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);
    
于 2015-10-22T08:14:55.617 回答