CListCtrl с вопросами о флажках

Элемент управления списком определяется как единичный выбор ресурсов.

Вопрос 1

Я хочу установить флажок в заголовке первого столбца моего CListCtrl. На OnInitDialog у меня есть

    m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);

    CString s;
    s.LoadString(IDS_COLUMN1);

    #ifndef HDS_CHECKBOXES
    // Copied from Microsoft SDKs\Windows\v7.0A\Include\CommCtrl.h
    #define HDS_CHECKBOXES  0x0400
    #endif 

    CHeaderCtrl& header = *m_list.GetHeaderCtrl();
    header.ModifyStyle(0, HDS_CHECKBOXES);


    #ifndef HDF_CHECKBOX
    // Copied from Microsoft SDKs\Windows\v7.0A\Include\CommCtrl.h    
    #define HDF_CHECKBOX  0x0040
    #endif 

    LVCOLUMN lc = { 0 };
    lc.mask = LVCF_FMT |LVCF_WIDTH |LVCF_TEXT | LVCF_SUBITEM;
    lc.fmt |= HDF_CHECKBOX;
    lc.cx = 96;
    lc.pszText = (TCHAR*) (LPCTSTR)s;

    m_list.InsertColumn(0, &lc);

Флажок в заголовке отображается только в том случае, если я добавляю расширенный |LVS_EX_AUTOCHECKSELECT, который мне определенно не нужен, потому что я хочу, чтобы действие проверки и действие выбора использовалось для разных целей.

Вопрос 2

Мне нужно установить логическое значение и пометить вещь как измененную, когда пользователь проверяет или снимает отметку с элемента. Но я не хочу, чтобы это действие происходило при вставке элементов, например, при заполнении списка при загрузке формы, но оно запускается без моего намерения, поскольку InsertItem запускает «действие снятия отметки» на OnItemChanged.

Это обязывало меня оформлять каждую вставку флагом m_is_inserting:

    m_is_inserting = true;
    m_list.InsertItem(i, m_array[i]->GetName());
    m_is_inserting = false;

и соответствующим образом отреагировать на обработчик LVN_ITEMCHANGED

void CMyDialog::OnItemChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
    NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    if (pNMListView->uChanged & LVIF_STATE)
    {
        if (pNMListView->uNewState & LVIS_SELECTED)
            OnSelect();
        else
        {
            if (pNMListView->iItem != -1)
            {
                if ((pNMListView->uNewState & LVIS_STATEIMAGEMASK) == 0x1000)
                {
                    if (!m_is_inserting)
                    {
                        m_array[pNMListView->iItem]->m_active = false;
                        SetModified();
                    }
                }
                else if ((pNMListView->uNewState & LVIS_STATEIMAGEMASK) == 0x2000)
                {
                    if (!m_is_inserting)
                    {
                        m_array[pNMListView->iItem]->m_active = true;
                        SetModified();
                    }
                }
            }
        }
    }

    *pResult = 0;
}

Есть ли лучший способ отличить реальное действие проверки / снятия флажка пользователя от InsertItem побочного эффекта?

Вопрос 3

Есть ли лучшее символическое соглашение для получения состояния проверки / снятия отметки? Магические числа 0x1000 и 0x2000 бессмысленны!

Заранее спасибо.


person sergiol    schedule 16.12.2016    source источник
comment
Связанные (Вопрос 2): stackoverflow.com/questions/28582698/   -  person sergiol    schedule 28.04.2017


Ответы (1)


Сначала вставьте заголовки столбцов. Затем измените HDF_CHECKBOX. Например:

m_list.SetExtendedStyle(LVS_EX_CHECKBOXES| LVS_EX_FULLROWSELECT);

CHeaderCtrl &header = *m_list.GetHeaderCtrl();
header.ModifyStyle(0, HDS_CHECKBOXES);

m_list.InsertColumn(0, L"Column0", 0, 120, 0);
m_list.InsertColumn(1, L"Column1", 0, 80, 1);
m_list.InsertColumn(2, L"Column2", 0, 80, 2);

HDITEM hdi = { 0 };
hdi.mask = HDI_FORMAT;
header.GetItem(0, &hdi);
hdi.fmt |= HDF_CHECKBOX;
header.SetItem(0, &hdi);

m_list.InsertItem(m_list.GetItemCount(), L"C0", 0);
m_list.InsertItem(m_list.GetItemCount(), L"C1", 0);

m_list.SetCheck(0, 1);
m_list.SetCheck(1, 1);

При обработке уведомления вы можете использовать метод GetCheck, чтобы узнать, отмечен ли элемент или нет. Пример:

if(pNMListView->uChanged & LVIF_STATE)
{
    if(pNMListView->uNewState & LVIS_SELECTED)
    {
        ...
    }
    else if(pNMListView->uNewState & LVIS_STATEIMAGEMASK && pNMListView->iItem >= 0)
    {
        if(m_list.GetCheck(pNMListView->iItem))
            TRACE("%d checked\n", pNMListView->iItem);
    }
}
person Barmak Shemirani    schedule 18.12.2016
comment
Спасибо. Вы получили ответ на вопрос "Как установить флажок" в части заголовка (Вопрос 1). Еще не пробовал обрабатывать уведомление. Боковое примечание: очень вероятно, что функция наличия флажка в заголовке для _1 _ / _ 2_ даже не реализована, так как я не нахожу случаев появления HDS_CHECKBOXES, HDF_CHECKBOX и HDF_CHECKED в файлах afxheaderctrl.cpp|h и afxlistctrl.cpp|h! - person sergiol; 18.12.2016
comment
Какая цель header.SetItem(0, &hdi);? Первый столбец может быть списком флажков даже без этой части кода. - person Zhang; 09.06.2020
comment
@Zhang Да, header.SetItem(0, &hdi) не нужно. Он устанавливает флажок в элементе управления заголовком, необязательно. - person Barmak Shemirani; 10.06.2020