Introduction
In one of my projects, I needed to add a single cell (SubItem) selection in Report style list control. By default, List control has full row selection style that can be set using "LVS_EX_FULLROWSELECT
" as a flag in SetExtendedStyle()
.
To select a subitem in Report style list control, you have to set LVS_OWNERDRAWFIXED
style and have to implement DrawItem()
function in your CListCtrl
derived class.
Following is the implementation of DrawItem
function that shows selection around a subitem in report style list control.
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
TCHAR lpBuffer[256];
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_PARAM ;
lvi.iItem = lpDrawItemStruct->itemID ;
lvi.iSubItem = 0;
lvi.pszText = lpBuffer ;
lvi.cchTextMax = sizeof(lpBuffer);
VERIFY(GetItem(&lvi));
LV_COLUMN lvc, lvcprev ;
::ZeroMemory(&lvc, sizeof(lvc));
::ZeroMemory(&lvcprev, sizeof(lvcprev));
lvc.mask = LVCF_WIDTH |LVCF_FMT;
lvcprev.mask = LVCF_WIDTH | LVCF_FMT;
CDC* pDC;
pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
int nCol;
if(!m_SelectionFlag)
{
for ( nCol=0; GetColumn(nCol, &lvc); nCol++)
{
if(nCol>0)
{
GetSubItemRect(lpDrawItemStruct->itemID,
nCol,LVIR_BOUNDS, m_SelectionRect);
else
{
GetItemRect(lpDrawItemStruct->itemID,
m_SelectionRect,LVIR_BOUNDS);
m_SelectionRect.right = GetColumnWidth(0);
m_SelectionRect.left = 0;
}
if(m_SelectionRect.PtInRect(m_Point))
{
m_SelectionFlag = TRUE;
break;
}
else
m_SelectionFlag = FALSE;
}
if ( (lpDrawItemStruct->itemState &
ODS_SELECTED) && m_SelectionFlag )
{
CRect rc=lpDrawItemStruct->rcItem;
rc.left=m_SelectionRect.left;
rc.right = m_SelectionRect.right;
pDC->FillSolidRect(&rc, RGB(255,0,0));
}
else
{
pDC->FillSolidRect(&lpDrawItemStruct->rcItem,
GetSysColor(COLOR_WINDOW)) ;
pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) ;
}
}
for ( nCol=0; GetColumn(nCol, &lvc); nCol++)
{
if ( nCol > 0 )
{
GetColumn(nCol-1, &lvcprev) ;
lpDrawItemStruct->rcItem.left += lvcprev.cx ;
lpDrawItemStruct->rcItem.right += lpDrawItemStruct->rcItem.left ;
}
::ZeroMemory(&lvi, sizeof(lvi));
lvi.iItem = lpDrawItemStruct->itemID;
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iSubItem = nCol;
lvi.pszText = lpBuffer;
lvi.cchTextMax = sizeof(lpBuffer);
VERIFY(GetItem(&lvi));
pDC->SelectObject(GetStockObject(DEFAULT_GUI_FONT));
UINT uFormat = DT_LEFT ;
::DrawText(lpDrawItemStruct->hDC, lpBuffer, strlen(lpBuffer),
&lpDrawItemStruct->rcItem, uFormat) ;
pDC->SelectStockObject(SYSTEM_FONT) ;
}
}
Demo Project:
- Using MFC AppWizard, create a Dialog Based application. Give the application name as you like.
- Now, add a List-Control and in Properties, change the style to Report. This style is necessary if we want multiple columns.
- Add CListCtrlEx.cpp and CListCtrlEx.h files in your project by selecting Project->Add To Project->Files... menu from the menu bar and selecting these files in "Insert files to project" dialog.
- Now, go to classwizard, then select 'Member variable Tag' and add a member variable for your list control of category="Control" and VariableType='CListCtrlEx'. Give any name you want to your member variable (let's say
m_ListCtrlEx
). Do not forget to include 'ListCtrlEx.h' in your Dialog class' header file.
- In the
OnInitDialog()
function of your Dialog class, add the following lines of code:
BOOL CCListCtrlExDemoDlg::OnInitDialog()
{
...
m_ListCtrlEx.SetStyles();
m_ListCtrlEx.SetNoOfRows(5);
m_ListCtrlEx.SetNoOfColumns(3);
m_ListCtrlEx.OnInitialUpdate();
}
That's it. Now, run the program and select subitems in the list control without having full row selection.
Conclusion
With this I will hope, you will get an idea how to show subitem selection in a List control.