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 rowint m_sel_col;
to keep track of selected columnBOOL m_bCustomDraw;
e.g., to switch off custom drawint m_nNumberOfRows;
number of rows inListCtrl
int m_nNumberOfCols;
number of columns inListCtrl
XListCtrl.h
Collapse
|
Copy Code
//{{AFX_MSG(CXListCtrl) afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnKeydown(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void custom_draw_funtion(NMHDR *pNMHDR, LRESULT *pResult);
XListCtrl.cpp
Collapse
|
Copy Code
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()
Collapse
|
Copy Code
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; } } }
Collapse
|
Copy Code
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); }
Collapse
|
Copy Code
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; }
Collapse
|
Copy Code
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; }