Click here to Skip to main content
11,578,739 members (62,858 online)
Click here to Skip to main content

SubItem Selection in List Control

, 26 Dec 2004 95K 2.4K 40
Rate this:
Please Sign up or sign in to vote.
SubItem selection in List Control.

Introduction

Muhammad Azam in his article 'SubItem Selection in List Control' showed how you can select subitem in CListCtrl by setting style LVS_OWNERDRAWFIXED and implementing DrawItem function. I'd like to show that a similar thing can be done using custom draw which is considered to be simpler.

The code

In CXListCtrl class derived from CListCtrl, I implemented NM_CUSTOMDRAW message because I wanted selected subitems to be drawn, NM_CLICK message to select subitem by mouse, and LVN_KEYDOWN to select subitem by keyboard.

  • int m_sel_row; to keep track of selected row
  • int m_sel_col; to keep track of selected column
  • BOOL m_bCustomDraw; e.g., to switch off custom draw
  • int m_nNumberOfRows; number of rows in ListCtrl
  • int m_nNumberOfCols; number of columns in ListCtrl

XListCtrl.h

//{{AFX_MSG(CXListCtrl)
  afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);
  afx_msg void OnKeydown(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
afx_msg void custom_draw_funtion(NMHDR *pNMHDR, LRESULT *pResult);

XListCtrl.cpp

BEGIN_MESSAGE_MAP(CXListCtrl, CListCtrl)
    //{{AFX_MSG_MAP(CXListCtrl)
    ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
    ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
    //}}AFX_MSG_MAP
    ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,custom_draw_funtion)
END_MESSAGE_MAP()
void CXListCtrl::custom_draw_funtion(NMHDR *pNMHDR, LRESULT *pResult)
{
    NMLVCUSTOMDRAW* nmcd=(NMLVCUSTOMDRAW*)pNMHDR;
    *pResult=CDRF_DODEFAULT;

    int row; 
    int col;
    switch(nmcd->nmcd.dwDrawStage)
    {
        case CDDS_PREPAINT:
            if(m_bCustomDraw) 
                *pResult=CDRF_NOTIFYITEMDRAW; 
            // else CDRF_DODEFAULT which tell windows to paint itself
            return;

        case CDDS_ITEMPREPAINT:
            *pResult=CDRF_NOTIFYSUBITEMDRAW;
            return;

        case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
        {
            *pResult=0;
            row=nmcd->nmcd.dwItemSpec;
            col=nmcd->iSubItem;

            CString str=GetItemText(row,col);

            CRect rect;
            CDC*pDC=CDC::FromHandle(nmcd->nmcd.hdc);

            if(col>0)
                GetSubItemRect(row,col,LVIR_BOUNDS,rect);
            else
                GetItemRect(row,&rect,LVIR_LABEL);

            UINT uCode=DT_LEFT;

            if(row==m_sel_row && col==m_sel_col)
            {
                COLORREF kolor=0xaa00aa;

                if(GetFocus()==this)
                    kolor=0x0000ff;

                CBrushbrush(kolor);
                pDC->FillRect(&rect,&brush);
            }
            rect.OffsetRect(5,0);
            pDC->DrawText(str,&rect,uCode);

            *pResult=CDRF_SKIPDEFAULT;

            break;
        }
    }
}
void CXListCtrl::invalidate_grid(int row, int col)
{   //I add this function to reduce flickering
    CRect r;

    if(col==0)
        GetItemRect(row,&r,LVIR_LABEL);
    else
        GetSubItemRect(row,col,LVIR_BOUNDS,r);

    InvalidateRect(&r);
}
void CXListCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NMITEMACTIVATE* nm=(NMITEMACTIVATE*)pNMHDR;

    invalidate_grid(m_sel_row,m_sel_col);//to clear old selection
    m_sel_row=nm->iItem;
    m_sel_col=nm->iSubItem;
    invalidate_grid(m_sel_row,m_sel_col);

    *pResult = 0;
}
void CXListCtrl::OnKeydown(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NMLVKEYDOWN* nmkd = (NMLVKEYDOWN*)pNMHDR;

    switch(nmkd->wVKey)
    {
        case VK_LEFT:
            m_sel_col--;
            if(m_sel_col<0)
                m_sel_col=0;
            invalidate_grid(m_sel_row,m_sel_col+1);
            break;
        case VK_RIGHT:
            m_sel_col++;
            if(m_sel_col>m_nNumberOfCols-1)
                m_sel_col=m_nNumberOfCols-1;
            invalidate_grid(m_sel_row,m_sel_col-1);
            break;

        case VK_UP:
            m_sel_row--;
            if(m_sel_row<0)
                m_sel_row=0;
            invalidate_grid(m_sel_row+1,m_sel_col);
            break;

        case VK_DOWN: 
            m_sel_row++;
            if(m_sel_row>m_nNumberOfRows-1)
                m_sel_row=m_nNumberOfRows-1;
            invalidate_grid(m_sel_row-1,m_sel_col);
            break;
        case VK_PRIOR:
            invalidate_grid(m_sel_row,m_sel_col);
            m_sel_row=0;
            break;
        case VK_NEXT:
            invalidate_grid(m_sel_row,m_sel_col);
            m_sel_row=m_nNumberOfRows-1;
            break;
        case VK_HOME:
            invalidate_grid(m_sel_row,m_sel_col);
            m_sel_col=0;

            if(GetKeyState(VK_CONTROL)<0)
                m_sel_row=0;

            SetItemState(m_sel_row,LVIS_FOCUSED,LVIS_FOCUSED);
            *pResult = CDRF_SKIPDEFAULT;
            invalidate_grid(m_sel_row,m_sel_col);
            return;
            break;
        case VK_END:
            invalidate_grid(m_sel_row,m_sel_col);
            m_sel_col=m_nNumberOfCols-1;
            if(GetKeyState(VK_CONTROL)<0)
                m_sel_row=m_nNumberOfRows-1;

            SetItemState(m_sel_row,LVIS_FOCUSED,LVIS_FOCUSED);

            *pResult=CDRF_SKIPDEFAULT;
            invalidate_grid(m_sel_row,m_sel_col);
            return;
    }
    *pResult = 0;
}

Points of Interest

In OnKeydown function:

  • SetItemState(m_sel_row,LVIS_FOCUSED,LVIS_FOCUSED);
  • *pResult=CDRF_SKIPDEFAULT;

change default responding CListCtrl on messages VK_HOME and VK_END.

Demo project

Demo project is a dialog based application with CListCtrl control and CXListCtrl class derived from CListCtrl.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

No Biography provided

You may also be interested in...

Comments and Discussions

 
SuggestionSimple way to accomplish subItem select Pin
mvadu18-Nov-11 15:39
membermvadu18-Nov-11 15:39 
GeneralI have made changes to enable multiple selection. However I am having problems that it will not redraw it correctly Pin
MeanKhoo29-Sep-08 11:43
memberMeanKhoo29-Sep-08 11:43 
QuestionLVN_ITEMCHANGED issue? Pin
Maverick24-Feb-05 1:17
memberMaverick24-Feb-05 1:17 
AnswerRe: LVN_ITEMCHANGED issue? Pin
Piotr Szewczyk24-Feb-05 11:49
memberPiotr Szewczyk24-Feb-05 11:49 
GeneralRe: LVN_ITEMCHANGED issue? Pin
Maverick11-Jul-05 6:03
memberMaverick11-Jul-05 6:03 
GeneralRe: LVN_ITEMCHANGED issue? Pin
Michael Mogensen24-Jul-07 17:09
memberMichael Mogensen24-Jul-07 17:09 
QuestionIssues? Pin
Maverick23-Feb-05 3:51
memberMaverick23-Feb-05 3:51 
Generalmarvelous Pin
Muhammad Azam16-Jan-05 22:10
memberMuhammad Azam16-Jan-05 22:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150603.1 | Last Updated 27 Dec 2004
Article Copyright 2004 by Piotr Szewczyk
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid