65.9K
CodeProject is changing. Read more.
Home

SubItem Selection in List Control

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.10/5 (11 votes)

Sep 6, 2004

1 min read

viewsIcon

86045

downloadIcon

1849

Explains how to select Sub Items in Report style List Control.

Sample screenshot

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));
   //GetSysColor(COLOR_HIGHLIGHT)) ; 
  }
  else
  {
   pDC->FillSolidRect(&lpDrawItemStruct->rcItem, 
                         GetSysColor(COLOR_WINDOW)) ;
   pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) ; 
  }
 } 
 for ( nCol=0; GetColumn(nCol, &lvc); nCol++)
 {
  if ( nCol > 0 ) 
  {
   // Get Previous Column Width in order to move the next display item   
   GetColumn(nCol-1, &lvcprev) ;
   lpDrawItemStruct->rcItem.left += lvcprev.cx ;
   lpDrawItemStruct->rcItem.right += lpDrawItemStruct->rcItem.left ; 
  }
  // Get the text 
  ::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:

  1. Using MFC AppWizard, create a Dialog Based application. Give the application name as you like.
  2. Now, add a List-Control and in Properties, change the style to Report. This style is necessary if we want multiple columns.
  3. 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.
  4. 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.
  5. 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.