【问题标题】:only single selection in CListCtrl Checkbox in MFCMFC中的CListCtrl复选框中只有一个选择
【发布时间】:2023-03-30 16:43:01
【问题描述】:

在 MFC 对话框中,我使用了带有复选框的 CListCtrl。我想禁用多复选框选择,以便用户一次只能选择一个复选框。实现这一目标的最佳方法是什么。我已经这样做了

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


        int nSelectedItemIndex = -1;
        nSelectedItemIndex = m_ListCtrl.GetNextItem(-1, LVNI_SELECTED);
        int nCount = m_ListCtrl.GetItemCount();    
        for(int nItem = 0; nItem < nCount; nItem++)
        {
            m_ListCtrl.SetCheck(nItem,false);
        }
        if(nSelectedItemIndex != -1)
            m_ListCtrl.SetCheck(nSelectedItemIndex,true);

        *pResult = 0;
    }

不知何故,我认为这种方法不太合适,可以通过其他方式变得更好。欢迎所有建议。

编辑:更新:编写代码后,一切正常,但我面临一个新问题。 在 OnItemChanged 消息处理函数中调用 SetCheck() 函数,它再次调用相同的函数,创建递归。因此选择更改有点慢。如何避免这种情况。请帮忙。 ????

【问题讨论】:

    标签: checkbox mfc clistctrl


    【解决方案1】:

    创建控件时,请确保使用此样式LVS_SINGLESEL

    它在 CreateEx/CreateEx 函数中传递。也可从资源编辑器获得(如果通过它添加控制)。

    【讨论】:

    • 我已经从资源视图中检查了 listctrl 属性。单选设置为真。但我仍然可以一次选择多个复选框。可能是我说的多选误导了您的问题,实际上这是多选复选框的问题。
    【解决方案2】:

    终于解决了。现在复选框和选择可以正常工作。选择复选框选择行,反之亦然,并且可以选择一个。代码:

        void SomeClass::ResetAllCheckBox()
        {
            int nCount = m_ListCtrl.GetItemCount();
            for(int nItem = 0; nItem < nCount; nItem++)
            {
                m_ListCtrl.SetCheck(nItem,false);
            }
    
        }
    
        //Handler for ON_NOTIFY(NM_CLICK,...)
        void SomeClass::OnClickList(NMHDR *pNMHDR, LRESULT *pResult)
        {
            LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
            NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
            LVHITTESTINFO hitinfo;
            int nPosCB=-1,nPos=-1;
            hitinfo.pt = pNMListView->ptAction;
    
            //Make the hit test...
            nPosCB = m_ListCtrl.HitTest(&hitinfo);
    
            if(hitinfo.flags != LVHT_ONITEMSTATEICON)
                return;
            ResetAllCheckBox();
    
            nPos = m_ListCtrl.GetNextItem(-1,LVNI_SELECTED);
            m_ListCtrl.SetItemState(nPos, ~LVIS_SELECTED, LVIS_SELECTED);
            m_ListCtrl.SetItemState(nPosCB, LVIS_SELECTED, LVIS_SELECTED);
            m_ListCtrl.SetSelectionMark(nPosCB);
            *pResult = 0;
        }
    
    
        //Handler for ON_NOTIFY(LVN_ITEMCHANGED,...)
        void SomeClass::OnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
        {
            LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
            int nPos = -1;
    
            ResetAllCheckBox();
    
            nPos = m_ListCtrl.GetNextItem(-1,LVNI_SELECTED);
            if(nPos != -1)
                m_ListCtrl.SetCheck(nPos);
    
            int nCount = m_ListCtrl.GetItemCount();
            int nSelectedItemIndex = -1;
            for(int nItem = 0; nItem < nCount; nItem++)
            {
                if(m_ListCtrl.GetCheck(nItem)== 1)
                    nSelectedItemIndex = nItem;
            }
    
            *pResult = 0;
        }
    

    【讨论】:

      【解决方案3】:

      我找到了一个更短的解决方案。这个想法是检测用户是否选中了一个复选框。如果是这种情况,请取消选中所有其他复选框,否则什么也不做。与@egur 的答案相反,此解决方案在选择行时不会选中复选框。

      static void DisableAllItemsExcept(CListCtrl& ctrl, int indexToKeepChecked)
      {
          for (int nItem = 0; nItem < ctrl.GetItemCount(); nItem++)
              if (nItem != indexToKeepChecked)
                  ctrl.SetCheck(nItem, FALSE);
      }
      
      //in begin message map
      //ON_NOTIFY(LVN_ITEMCHANGED, IDC_SC_LIST, &CMyDlg::OnLvnItemchangedScList)
      
      void CMyDlg::OnLvnItemchangedScList(NMHDR *pNMHDR, LRESULT *pResult)
      {
          LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
      
          //detect if we checked a new element
          if ( (pNMLV->uChanged & LVIF_STATE) && (pNMLV->uNewState & 0x2000) && (pNMLV->uOldState & 0x1000) )
              DisableAllItemsExcept(m_lcList, pNMLV->iItem);  
      
          *pResult = 0;
      }
      

      状态变化的检测基于以下文章:Get the notification code from Listview Control checkboxes。值 0x1000 和 0x2000 似乎没有在头文件中的任何地方定义,所以也许我正在使用未记录的功能。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 2015-06-06
        • 2017-08-10
        • 2019-06-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多