在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()函数,它再次调用相同的函数,创建一个递归。因此选择更改有点慢。如何避免这种情况。请帮忙。 ????
答案 0 :(得分:2)
最后我解决了它。现在复选框和选择工作在par。选择复选框选择行,反之亦然,可以进行一次选择。代码:
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;
}
答案 1 :(得分:1)
创建控件时,请确保使用此样式LVS_SINGLESEL
。
它在CreateEx / CreateEx函数中传递。也可以从资源编辑器获得(如果通过它添加控件)。
答案 2 :(得分:0)
我找到了一个更短的解决方案。这个想法是要检测用户是否选中了一个复选框。如果是这种情况,请取消选中所有其他复选框,否则不执行任何操作。与@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,所以也许我正在使用未记录的功能。