区分 CListCtrl 中的用户单击和 SetChecked()

Posted

技术标签:

【中文标题】区分 CListCtrl 中的用户单击和 SetChecked()【英文标题】:Differentiate between user click and SetChecked() in CListCtrl 【发布时间】:2015-02-18 11:37:33 【问题描述】:

我有一个带有复选框的 CListCtrl,我需要根据某些外部因素启用或禁用这些复选框。但是,当列表中有更多可以显示的项目时,我无法在控件上使用 EnableWindow(FALSE),因为它也会禁用滚动条。

所以,我在消息映射中搜索并想出了以下代码:

ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHECKBOX_LIST, OnCheckboxChanged)

回调函数实现为:

void CUserPropertiesDialog::OnCheckboxChanged(NMHDR* pNMHDR, LRESULT* pResult)

    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR;
    LVHITTESTINFO hitInfo;

    hitInfo.pt = pNMListView->ptAction;
    int nItem = m_checkBoxList.HitTest(&hitInfo);
    if (hitInfo.flags != LVHT_ONITEMSTATEICON) return;

    std::string groupName = static_cast<LPCTSTR>(m_checkBoxList.GetItemText(nItem, 0));

    if (!CCharmUserAdminGUIApp::getTheCharmUserAdminGUIApp().isAdministrator())
    
        if (pNMListView->uChanged & LVIF_STATE)
        
            if (((pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(2)) != 0) && ((pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(1)) != 0))
            
                CH_INFO1("CUserPropertiesDialog::OnCheckboxChanged - CheckBox Now Selected", groupName);
            
            else if (((pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(1)) != 0) && ((pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(2)) != 0))
            
                CH_INFO1("CUserPropertiesDialog::OnCheckboxChanged - CheckBox Now Unselected", groupName);
            
        
    

问题在于,当用户单击复选框(很好!)时会调用此函数,而且当从代码中调用 SetChecked() 函数时也会调用此函数。

我曾希望对 hitInfo.flags 的检查能让我区分点击和功能,但事实并非如此。

除了在函数调用之前/之后设置一些全局标志并在回调中使用之外,还有其他方式来判断是使用点击还是函数调用?

【问题讨论】:

如果您需要根据某些条件启用/禁用,为什么禁用滚动条(和整个控件)很重要?听起来您正在实现非标准 UI 行为。 为什么这是非标准的?我想查看列表中的所有复选框条目,但我不想切换这些条目。类似于显示编辑框但禁用编辑功能。 为什么使用INDEXTOSTATEIMAGEMASK?你应该使用LVIS_STATEIMAGEMASK 相关(问题 2):***.com/questions/41176599/… 【参考方案1】:

我在我的程序中使用相同的,我使用了一个标志。

但我使用的是 LVN_ITEMCHANGING。有了这条消息,我可以阻止任何更改。

我在更改列表框项的状态之前覆盖了 SetCheck(即使它不是虚拟的)并设置了一个标志。内部 OnItemChanging 例程看到标志集并允许更改。返回后直接清除flag。

因此,如果使用鼠标执行相同的操作,则未设置标志,您需要以不同的方式进行检查。

装箱时也是这样。我设置了flag,让所有的变化都能通过……

【讨论】:

我选择了一个类似的解决方案,其标志在SetCheck() 之前/之后切换,这可行,但感觉有点笨拙。 是的。但即使寻找最后收到的 Window 消息也无济于事。您需要“动作”的上下文。一种上下文是“程序动作”,一种上下文是“用户动作”。

以上是关于区分 CListCtrl 中的用户单击和 SetChecked()的主要内容,如果未能解决你的问题,请参考以下文章

MFC CListCtrl 右键单击​​标题

如何在 MFC CListCtrl 中实现“点击并按住”行为?

单击或选择 Clistctrl 子项(报告视图)

如何处理 CListCtrl 中的属性键?

CListCtrl

如何在 SDI 中使用 MFC CListCtrl