Как заставить CListCtrl всегда выбирать один элемент?

Я хочу, чтобы CListCtrl всегда имел выделенный элемент, например, коллекцию переключателей.

Я использовал стили: LVS_SHOWSELALWAYS|LVS_SINGLESEL

Я искал стиль для этого, но не смог найти это.

2

Решение

Я не думаю, что есть встроенная поддержка для этого.

Часть выбора с самого начала проста: просто выберите элемент после заполнения списка:

// 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 и перехват перехватов, проверка, не приведут ли они к принудительному выбору и предотвращению этого, но вы должны решить, стоит ли эта дополнительная работа проблем.

1

Другие решения

Обрабатывать 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);
}

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

2

Это можно сделать просто в диалоговом редакторе, когда вы создаете свой clistctrl, установите для параметров «Всегда показывать выделенное» и «Отдельное выделение» в свойствах значение true. Если вы хотите сделать это с помощью кода, то у вас есть правильный путь, но вы ошибаетесь в неправильном месте. Переопределите OnInitDialog и сначала вызовите CDialog :: OnInitDialog, а затем установите новый стиль (используйте ModifyStyle). Проблема в том, что базовый класс переопределяет ваши изменения стиля. Помимо этого, это может быть несколько вещей, MFC не известен своей интуитивностью!

0

Я решил эту проблему следующим образом:

  1. Я добавляю в диалог новую переменную с именем lastItem
  2. обработайте сообщение LVN_ITEMCHANGING и добавьте следующие строки:

    lastItem = pNMLV->iItem;
    
  3. обрабатывать сообщения 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);
    
0
По вопросам рекламы [email protected]