Я хочу, чтобы CListCtrl всегда имел выделенный элемент, например, коллекцию переключателей.
Я использовал стили: LVS_SHOWSELALWAYS|LVS_SINGLESEL
Я искал стиль для этого, но не смог найти это.
Я не думаю, что есть встроенная поддержка для этого.
Часть выбора с самого начала проста: просто выберите элемент после заполнения списка:
// Populate the list
// ...
c_MyList.SetItemState(nItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
Другая часть, предотвращающая отмену выбора всех элементов, когда пользователь щелкает мышью за пределами всех элементов, является более сложной. Вы можете легко определить, отменяет ли выбор в списке элемент, но не выяснить, почему этот элемент теряет выбранное состояние. То есть Вы не можете сказать, отменяет ли он выбор, чтобы выбрать другой или оставить все элементы невыбранными. Причина в том, что элемент управления сначала отправляет уведомление «элемент X был отменен», а затем уведомление «элемент Y был выбран». Если ни один элемент не выбран, вы получите первый, но не второй.
Небольшая идея, о которой я подумал, — перехватывать уведомления 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 и перехват перехватов, проверка, не приведут ли они к принудительному выбору и предотвращению этого, но вы должны решить, стоит ли эта дополнительная работа проблем.
Обрабатывать 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);
}
Это предотвратит переход клика мыши к элементу управления и получит сообщение. Вы по-прежнему сможете удалить выбор программным способом, но пользователь не сможет щелкнуть где-либо в пустой области под вашими элементами, чтобы удалить выбор.
Это можно сделать просто в диалоговом редакторе, когда вы создаете свой 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);