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