The List Control is defined as Single Selection on the resources.
Question 1
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 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);
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.
Question 2
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
.
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;
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;
}
Is there a better way to distinguish a real user check/uncheck action from a InsertItem
side effect?
Question 3
Is there a better symbolic convention for getting the check/uncheck state? Magic numbers 0x1000
and 0x2000
are pretty meaningless!
Thanks in advance.
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);
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\n", pNMListView->iItem);
}
}