Click here to Skip to main content
14,269,309 members

SubItem Selection in List Control

Rate this:
4.56 (14 votes)
Please Sign up or sign in to vote.
4.56 (14 votes)
26 Dec 2004
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

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 Pauli24-Jul-07 17:09
memberMichael Pauli24-Jul-07 17:09 
QuestionIssues? Pin
Maverick23-Feb-05 3:51
memberMaverick23-Feb-05 3:51 
This list control code is great..But i have some issues though..

I put the list control in a CFormView.. but that view activation is not standard so maybe i missed some codes thats why the listctrl is acting strange..

First: When there are many items when i press the down-arrow key, the ctrl behaves as expected,the highlight changes from 1st itemto the 2nd item.. But when the next item needs to be scrolled, the highlight (red color) disappers and the listctrl just scrolls,meaning the down-arrow key behavior is to scroll, and the selection is lost until u click on any item again..

Second: A question about DoDateExchange in CFormView.. When does the DoDataExchange get called? because i manually made and attached CFormView from document (not by the framework), i may have missed some codes.. so i just need to know when DoDataExchanged gets called so i can adjust my program.. What i want is at program startup, i want the DoDataExchange() function called.. Right now its not... To cut is short, i just need to know when does it get called..


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    Praise Praise    Rant Rant    Admin Admin   

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

Article
Posted 26 Dec 2004

Stats

113.5K views
3K downloads
41 bookmarked