CListCtrl 带复选框问题

2021-12-23 00:00:00 checkbox mfc clistctrl side-effects

列表控件被定义为资源的单一选择.

The List Control is defined as Single Selection on the resources.

问题 1

我想在我的 CListCtrl 的第一列的标题上有一个复选框.在 OnInitDialog 我有

I want to have a checkbox on the header of first column of my CListCtrl. On the OnInitDialog I have

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

    CString s;
    s.LoadString(IDS_COLUMN1);

    #ifndef HDS_CHECKBOXES
    // Copied from Microsoft SDKsWindowsv7.0AIncludeCommCtrl.h
    #define HDS_CHECKBOXES  0x0400
    #endif 

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


    #ifndef HDF_CHECKBOX
    // Copied from Microsoft SDKsWindowsv7.0AIncludeCommCtrl.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,它只显示标题的复选框,我绝对不想要,因为我希望检查动作和选择动作将用于不同的目的.

It only presents the header's checkbox if I add in the extended |LVS_EX_AUTOCHECKSELECT, which I definitely not want because I desire that checking action and selection action will be used for different purposes.

问题 2

我需要设置一个布尔值,并在用户选中或取消选中某个项目时将其标记为已修改.但是我不希望在插入项目时发生此操作,例如在加载表单时填写列表时,但它是无意触发的,因为 InsertItem 上触发取消选中操作">OnItemChanged.

I need to set a boolean and mark thing as modified when user checks or unchecks an item. But I don't want this action to occur when inserting items, for example when filling the list at form loading, but it is triggered without my intention, as InsertItem triggers "a uncheck action" on OnItemChanged.

它迫使我使用 m_is_inserting 成员标志来调节每个插入:

It obliged me to condition every insert with a m_is_inserting member flag:

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

并对 LVN_ITEMCHANGED 处理程序做出相应的反应

and react accordingly on the LVN_ITEMCHANGED handler

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 副作用区分开来?

Is there a better way to distinguish a real user check/uncheck action from a InsertItem side effect?

问题 3

是否有更好的符号约定来获取选中/取消选中状态?幻数 0x10000x2000 毫无意义!

Is there a better symbolic convention for getting the check/uncheck state? Magic numbers 0x1000 and 0x2000 are pretty meaningless!

提前致谢.

推荐答案

先插入列标题.然后更改HDF_CHECKBOX.例如:

Insert the column headers first. Then change the HDF_CHECKBOX. For example:

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 方法查看项目是否被选中.示例:

When handling the notification you can use the GetCheck method to see if item is checked or not. Example:

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
", pNMListView->iItem);
    }
}

相关文章