我希望 CListCtrl 始终具有选定的项目,例如单选按钮的集合。
我使用了以下样式:LVS_SHOWSELALWAYS|LVS_SINGLESEL
我一直在寻找这种风格,但一直找不到。
我希望 CListCtrl 始终具有选定的项目,例如单选按钮的集合。
我使用了以下样式:LVS_SHOWSELALWAYS|LVS_SINGLESEL
我一直在寻找这种风格,但一直找不到。
处理 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);
}
这将防止鼠标点击进入控件并吃掉消息。您仍然可以通过编程方式删除选择,但用户将无法单击项目下方空白区域中的任何位置来删除选择。
我认为没有对此的内置支持。
从一开始就进行选择的部分很简单:只需在填充列表后选择一个项目:
// 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 子类并拦截点击,检查它们是否会强制进行空选择并阻止它,但您必须确定额外的工作是否值得麻烦。
这可以在您设计 clistctrl 时简单地在对话框编辑器中完成,将“属性”中的“始终显示选择”和“单一选择”选项设置为 true。如果您想通过代码执行此操作,那么您有正确的方法,但可能是错误的地方。覆盖 OnInitDialog 并在其中首先调用 CDialog::OnInitDialog,然后设置新样式(使用 ModifyStyle)。问题是基类覆盖了您的样式更改。除此之外,它可能是一些事情,MFC 并不以其直观性而闻名!
我解决了这个问题如下:
处理 LVN_ITEMCHANGING 消息并添加以下行:
lastItem = pNMLV->iItem;
处理 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);