CListCtrl中需要把选中的item高亮显示时只需要调用SetItemState传入LVIS_SELECTED就好。
但是这样需要把焦点设置到CListCtrl上,一旦CListCtrl失去焦点高亮就会消失。
---------------------
最近工作中遇到一个需求,需要让CListCtrl在失去焦点的情况下依然显示高亮的item。
总的来说有三种方法来实现这个功能。
继承CListCtrl然后重绘
太麻烦了不想用这个……
NM_CUSTOMDRAW事件
这个是一个类似于回调的处理过程,Windows在绘制List Ctrl的某个时间点上发送这个消息,可以选择忽略所有的通知,或者处理某部分的绘制,甚至绘制整个控件。用起来比较灵活方便,我只重绘被选中的那个item就好。 参考帖子
---------------------
void CMainFrame::OnNMCustomdrawRecQueryList(NMHDR *pNMHDR, LRESULT *pResult) { NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR ); *pResult = CDRF_DODEFAULT; if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage ) { *pResult = CDRF_NOTIFYITEMDRAW; } else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage ) { *pResult = CDRF_NOTIFYSUBITEMDRAW; } else if ( (CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage ) { COLORREF clrNewTextColor, clrNewBkColor; int nItem = static_cast<int>( pLVCD->nmcd.dwItemSpec ); POSITION pos = m_lstRecQueryRes.GetFirstSelectedItemPosition(); int index = m_lstRecQueryRes.GetNextSelectedItem(pos); if (index == nItem)//如果要刷新的项为当前选择的项,则将文字设为白色,背景色设为蓝色 { clrNewTextColor = RGB(255,255,255); //Set the text to white clrNewBkColor = RGB(49,106,197); //Set the background color to blue } else { clrNewTextColor = RGB(0,0,0); //set the text black clrNewBkColor = RGB(255,255,255); //leave the background color white } pLVCD->clrText = clrNewTextColor; pLVCD->clrTextBk = clrNewBkColor; *pResult = CDRF_DODEFAULT; } }
然而!我们代码里面用的BCG的list ctrl坑爹的自己把NM_CUSTOMDRAW处理了……用不了这个方法
---------------------
使用下面的方法肯定可以实现的,已经验证成功!
NM_KILLFOCUS
当控件失去焦点的时候就会发送这个消息,我们只要在这个消息的处理函数里面把需要高亮的item设置成LVIS_DROPHILITED,然后在NM_SETFOCUS的时候把状态取消就好了~
CTestDlg类的cpp文件主要代码如下:
//目的:小时列表与全览图切换后,恢复无模式对话框的选中项;事件映射方法如下
ON_NOTIFY(NM_KILLFOCUS, IDC_NOMODAL_LIST, OnNMKillfocusList) //目的:小时列表与全览图切换后,恢复无模式对话框的选中项 ON_NOTIFY(NM_SETFOCUS, IDC_NOMODAL_LIST, OnNMSetfocusList) void CTestDlg::OnNMKillfocusList(NMHDR *pNMHDR, LRESULT *pResult) { // TODO: 在此添加控件通知处理程序代码 m_nSelectedItemIndex = m_List.GetSelectionMark(); m_List.SetItemState(m_nSelectedItemIndex, LVIS_DROPHILITED, LVIS_DROPHILITED); *pResult = 0; } void CTestDlg::OnNMSetfocusList(NMHDR *pNMHDR, LRESULT *pResult) { // TODO: 在此添加控件通知处理程序代码 m_List.SetItemState(m_nSelectedItemIndex, FALSE, LVIF_STATE); *pResult = 0; }
CTestDlg类的h头文件主要代码如下:
class CTestDlg: public CDialog { public: // Construction CTestDlg(CWnd* pParent = NULL); // standard constructor virtual ~CTestDlg(); public: CListCtrl *m_pList; private: //目的:保存小时列表中的无模式对话框的选中项的索引值 int m_nSelectedItemIndex; // Implementation protected: // Generated message map functions //{{AFX_MSG(CUIRevNoModalDlg) //目的:小时列表与全览图切换后,恢复无模式对话框的选中项 afx_msg void OnNMKillfocusList(NMHDR *pNMHDR, LRESULT *pResult); //目的:小时列表与全览图切换后,恢复无模式对话框的选中项 afx_msg void OnNMSetfocusList(NMHDR *pNMHDR, LRESULT *pResult); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif
如下所示,图1与图2相互切换后选中项的焦点没有丢失。
图1
图2