Только один выбор в CListCtrl Флажок в MFC

В диалоге 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;
    }

Почему-то я думаю, что этот метод не очень правильный и может быть улучшен другим способом. Все предложения приветствуются.

РЕДАКТИРОВАТЬ: ОБНОВЛЕНИЕ: после написания кода все работает, но я столкнулся с новой проблемой. Вызывая функцию SetCheck() внутри функции-обработчика сообщений OnItemChanged, она снова вызывает ту же функцию, создавая рекурсию. Таким образом, изменение выбора происходит медленно. Как этого избежать. Пожалуйста, помогите.????

3 ответа

Наконец я решил это. Теперь флажок и выбор работает на пар. флажок выбора выбирает строку и наоборот, и возможен один выбор. код:

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

При создании элемента управления убедитесь, что этот стиль используется LVS_SINGLESEL,

Он передается в функцию CreateEx/CreateEx. Также доступно из редактора ресурсов (если контроль добавлен через него).

Я нашел более короткое решение. Идея состоит в том, чтобы обнаружить, если пользователь установил флажок. Если это так, снимите все остальные чекбоксы, иначе ничего не делайте. Вопреки ответу @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;
}

Обнаружение изменения состояния было основано на следующей статье: Получить код уведомления из флажков Listview Control. Значения 0x1000 и 0x2000, кажется, нигде не определены в заголовочном файле, поэтому, возможно, я использую недокументированную функцию.

Другие вопросы по тегам