因为以前都是在对话框里面使用CListCtrl控件,可以在VC6里面的ClassWizard里面直接就给该控件添加各种消息处理函数。但是到了Feature Pack里面,可以把CListCtrl放到一个CDockPane上面,这时就比较郁闷了,所以只能手工添加消息的处理。为此,我特意到VC6下新建了一个对话框,并加上一个CListCtrl控件,并添加了LVN_ITEMCHANGED消息,及其处理函数。 然后我就如法炮制,跑到VS2010的项目里面,到CListCtrl所属的CStlListWnd的消息映射里面手工加上
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, OnItemchangedList1)
这里的IDC_LIST就是在CStlListWnd里面创建CListCtrl时所用的ID
然后添加对应的处理函数
afx_msg void OnItemchangedList(NMHDR* pNMHDR, LRESULT* pResult);
这里就可以在这个函数里面加一个消息框的函数,然后在ListCtrl上点击时,就可以看到该消息已被处理了。
然后就要完善这个函数了,注意这个函数的第一个参数,它就是我们要考虑的重点。
NMHDR这个结构体是所有NOTIFY消息的用到的参数,但是对于不同控件的NOTIFY消息,它的含义也是不同的。
对于我们所使用的CListCtrl,我们就需要转换一下
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
NM_LISTVIEW结构体的定义如下
typedef struct tagNMLISTVIEW {
- NMHDR hdr;
- int iItem;
- int iSubItem;
- UINT uNewState;
- UINT uOldState;
- UINT uChanged;
- POINT ptAction;
- LPARAM lParam;
- } NMLISTVIEW, *LPNMLISTVIEW;
成员很多,但最有用的就是iItem, uNewState, uOldState;
iItem就是CListCtrl中,状态发生变化的Item的编号,从0开始
uNewState是变化之后的状态
uOldState是变化之前的状态
这两个state可用的值有
LVIS_ACTIVATING
Not currently supported.
LVIS_CUT
The item is marked for a cut-and-paste operation.
LVIS_DROPHILITED
The item is highlighted as a drag-and-drop target.
LVIS_FOCUSED
The item has the focus, so it is surrounded by a standard focus rectangle. Although more than one item may be selected, only one item can have the focus.
LVIS_OVERLAYMASK
The item's overlay image index is retrieved by a mask.
LVIS_SELECTED
The item is selected. The appearance of a selected item depends on whether it has the focus and also on the system colors used for selection.
LVIS_STATEIMAGEMASK
The item's state image index is retrieved by a mask.
各项可以进行或运算进行组合
重点关注 LVIS_SELECTED
因为我们要处理某一行被选中的消息,那么必然就是某item的状态转变为LVIS_SELECTED
但是要注意,不能用pNMListView->uNewState == LVIS_SELECTED 来进行判断,因为各个state是可以进行或运算的。
因此应该使用 pNMListView->uNewState & LVIS_SELECTED == LVIS_SELECTED 来判断是该notify消息不是某item被选中而触发的消息
代码大致如下:
void CStlListWnd::OnItemchangedList( NMHDR* pNMHDR, LRESULT* pResult )
- {
- NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
- *pResult = NULL;
- if(pNMListView->iItem == -1)
- return;
- if(pNMListView->uNewState & LVIS_SELECTED == LVIS_SELECTED)
- {
- //item is selected
- //......
- }
- }
如果有兴趣,可以在某次消息触发时,都把iItem, uNewState, uOldState打印出来看看
也许会有意想不到的收获,比如说如果列表框前面设置了复选框,
你会发现复选框是否被选中对应的两个状态是4096和8192即0x1000和0x2000
这点估计以后要用到