1
2
3
CListView中内置了CListCtrl,所以对CListView的操作实际上就是对内置CListCtrl的操作。下面就从新建一个CListView的子类开始,我从工程中新建了一个叫做CInfoView的类,基类选择CListView。
4
5
1
>----------
初始化CListView,设置风格,背景和字体颜色,初始化行列。该项工作在OnInitialUpdate()中完成,如下所示。
6
7
void
CInfoView::OnInitialUpdate()
8
{
9
CListView::OnInitialUpdate();
10
//
TODO: Add your specialized code here and/or call the base class
11
CListCtrl
&
m_list
=
GetListCtrl();
//
得到内置的listctrl引用
12
LONG lStyle;
13
lStyle
=
GetWindowLong(m_list.m_hWnd, GWL_STYLE);
//
获取当前窗口风格
14
lStyle
&=
~
LVS_TYPEMASK;
//
清除显示方式位
15
lStyle
|=
LVS_REPORT;
//
设置报表风格
16
SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);
//
设置窗口风格
17
18
DWORD dwStyle
=
m_list.GetExtendedStyle();
19
20
//
选中某行使整行高亮(只适用于报表风格的listctrl)
21
dwStyle
|=
LVS_EX_FULLROWSELECT;
22
dwStyle
|=
LVS_EX_GRIDLINES;
//
网格线(只适用与报表风格的listctrl)
23
24
m_list.SetExtendedStyle(dwStyle);
//
设置扩展风格
25
m_list.SetBkColor(RGB(
200
,
200
,
200
));
//
设置背景颜色
26
m_list.SetTextBkColor(RGB(
200
,
200
,
200
));
//
设置文本背景颜色
27
m_list.SetTextColor(RGB(
10
,
10
,
80
));
//
设置文本颜色
28
29
//
插入列的标题,为了简单起见,我只插入三列
30
m_list.InsertColumn(
0
,
"
图像帧号
"
, LVCFMT_CENTER,
80
);
31
m_list.InsertColumn(
1
,
"
可见性判断
"
, LVCFMT_CENTER,
110
);
32
m_list.InsertColumn(
2
,
"
置信度结果
"
, LVCFMT_CENTER,
110
);
33
}
34
35
36
2
>----------
插入一行数据。一般在实际应用中,都是在程序运行中,插入一行数据,这时候,需要在当前的程序语境中得到CInfoView的指针,然后进行插入数据的操作。在我的应用中,我把CinfoView作为拆分窗口的一个子窗口,所以具体操作如下:
37
38
CListView
*
listview
=
(CListView
*
)(((CMainFrame
*
)theApp.GetMainWnd())
->
m_wndSplitter1.GetPane(
1
,
0
));
//
得到ListView的指针
39
CListCtrl
&
list
=
listview
->
GetListCtrl();
//
得到listview内置listctrl的引用
40
CString strId, strCo;
//
图像帧号,置信度
41
CString strVb
=
"
Y
"
;
//
可见性
42
if
(fConfid[nIndex]
<=
0
)
43
{
44
strVb
=
"
N
"
;
45
}
46
strId.Format(
"
%d
"
, nIndex
+
1
);
47
strCo.Format(
"
%.4f
"
, fConfid[nIndex]);
48
49
//
插入一行数据,始终在顶端插入新的数据
50
int
nRow
=
list.InsertItem(
0
, strId);
51
list.SetItemText(nRow,
1
, strVb);
52
list.SetItemText(nRow,
2
, strCo);
53
54
3
>----------
右键单击弹出浮动菜单。在我的应用中,右键弹出的浮动菜单,只有一项:“删除所有内容”。要弹出浮动菜单,首先先要在“资源”的“Menu”中新建一个Menu,ID命名为IDR_POPMENU,然后在该Menu中添加一个主菜单“操作”,在“操作”下添加一个子菜单“删除所有内容”,ID命名为“ID_DELETE_ALL”,通过向导在CInfoView中给ID_DELETE_ALL添加消息响应函数OnDeleteAll(),如下:
55
56
void
CInfoView::OnDeleteAll()
57
{
58
CListCtrl
&
m_list
=
GetListCtrl();
59
m_list.DeleteAllItems();
60
}
61
62
然后通过向导在CInfoView中添加右键单击响应函数
=
NM_RCLICK,如下:
63
64
void
CInfoView::OnRclick(NMHDR
*
pNMHDR, LRESULT
*
pResult)
65
{
66
//
TODO: Add your control notification handler code here
67
CListCtrl
&
m_list
=
GetListCtrl();
//
获取当前列表控件的指针
68
CMenu menu,
*
pSubMenu;
//
定义下面要用到的cmenu对象
69
menu.LoadMenu(IDR_POPMENU);
//
装载自定义的右键菜单
70
pSubMenu
=
menu.GetSubMenu(
0
);
//
获取第一个弹出菜单
71
CPoint oPoint;
//
定义一个用于确定光标位置的位置
72
GetCursorPos(
&
oPoint);
//
获取当前光标的位置
73
74
//
在指定位置显示弹出菜单
75
pSubMenu
->
TrackPopupMenu(TPM_LEFTALIGN, oPoint.x, oPoint.y,
this
);
76
}
77
78
4
>----------
添加消息响应函数OnCustomDraw(),为ClistCtrl的每个Item设置不同的颜色,在该应用中,为单数和偶数的Item项设置两种不同的颜色。具体步骤如下:
79
首先在InfoView.h的AFX_MSG之间添加消息函数声明:
80
afx_msg
void
OnCustomDraw(NMHDR
*
pNMHDR, LRESULT
*
pResult);
81
然后在InfoView.cpp的BEGIN_MESSAGE_MAP之间添加消息映射:
82
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
83
最后在InfoView.cpp中添加函数实现:
84
85
void
CInfoView::OnCustomDraw(NMHDR
*
pNMHDR, LRESULT
*
pResult)
86
{
87
LPNMLVCUSTOMDRAW lplvcd
=
(LPNMLVCUSTOMDRAW)pNMHDR;
88
89
switch
(lplvcd
->
nmcd.dwDrawStage)
90
{
91
int
iRow;
92
case
CDDS_PREPAINT:
93
*
pResult
=
CDRF_NOTIFYITEMDRAW;
94
break
;
95
case
CDDS_ITEMPREPAINT:
96
*
pResult
=
CDRF_DODEFAULT;
97
iRow
=
lplvcd
->
nmcd.dwItemSpec;
98
if
(iRow
&
1
)
99
{
100
lplvcd
->
clrTextBk
=
RGB(
230
,
230
,
230
);
101
//
lplvcd->clrText = RGB(255, 255, 0);
102
*
pResult
=
CDRF_NEWFONT;
103
}
104
break
;
105
default
:
106
*
pResult
=
CDRF_DODEFAULT;
107
}
108
}
109
110
5
>----------
为CInfoView添加点击列的标题进行排序的消息响应函数,在添加该消息响应函数之前,先要定义实现排序的回调函数。在该应用中,第一列是图像帧号,按自然数排序,其他列都按字串进行排列,所以定义两个比较的回调函数。
111
在InfoView.h中声明两个静态的回调函数:
112
113
static
int
CALLBACK ListViewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
//
按字串排序
114
115
static
int
CALLBACK ListViewCompareIntFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
//
按自然数排序
116
117
在InfoView.cpp中实现两个静态的回调函数:
118
119
int
CALLBACK CInfoView::ListViewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
120
{
121
//
得到排序方式
122
int
*
pisortorder
=
(
int
*
)lParamSort;
123
124
//
得到两个列的排序信息
125
TCHAR
*
sz1
=
(TCHAR
*
)lParam1;
126
TCHAR
*
sz2
=
(TCHAR
*
)lParam2;
127
//
比较列的信息并返回比较结果。
128
//
若为减序,则将比较结果乘上-1。
129
if
(
*
pisortorder
==
LVS_SORTASCENDING)
130
return
lstrcmp(sz1, sz2);
131
else
132
return
lstrcmp(sz1, sz2)
*
(
-
1
);
133
}
134
135
int
CALLBACK CInfoView::ListViewCompareIntFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
136
{
137
//
得到排序方式
138
int
*
pisortorder
=
(
int
*
)lParamSort;
139
//
得到两个列的排序信息
140
TCHAR
*
sz1
=
(TCHAR
*
)lParam1;
141
TCHAR
*
sz2
=
(TCHAR
*
)lParam2;
142
int
n1
=
_ttoi(sz1);
143
int
n2
=
_ttoi(sz2);
144
//
比较列的信息并返回比较结果。
145
//
若为减序,则将比较结果乘上-1。
146
if
(
*
pisortorder
==
LVS_SORTASCENDING)
147
{
148
if
(n1
-
n2
>
0
)
return
1
;
149
else
if
(n1
-
n2
==
0
)
return
0
;
150
else
return
-
1
;
151
}
152
else
153
{
154
if
(n1
-
n2
>
0
)
return
-
1
;
155
else
if
(n1
-
n2
==
0
)
return
0
;
156
else
return
1
;
157
}
158
}
159
160
//
然后通过向导为事件LVN_COLUMNCLICK添加消息响应函数OnColumnclick(),在该函数中调用上面的回调函数
161
void
CInfoView::OnColumnclick(NMHDR
*
pNMHDR, LRESULT
*
pResult)
162
{
163
//
TODO: Add your control notification handler code here
164
static
int
ncurSortCol
=
-
1
;
//
保存当前的排序列。
165
//
一开始表示为-1,表示尚未按任何列排序。
166
NM_LISTVIEW
*
pNMListView
=
(NM_LISTVIEW
*
)pNMHDR;
167
CListCtrl
*
lc
=
&
GetListCtrl();
168
LONG ws
=
GetWindowLong(lc
->
m_hWnd, GWL_STYLE);
169
int
nSortOrder;
//
排序的方式
170
171
//
若点击列与当前排序列不同的列,则改变排序序,并将排序方式改为增序。
172
//
若当前排序列与点击列相同,则更改增、减序的排序方式
173
if
(ncurSortCol
==
pNMListView
->
iSubItem)
174
{
175
if
(ws
&
LVS_SORTASCENDING)
176
{
177
ws
^=
LVS_SORTASCENDING;
178
nSortOrder
=
LVS_SORTDESCENDING;
179
}
180
else
181
{
182
ws
^=
LVS_SORTDESCENDING;
183
nSortOrder
=
LVS_SORTASCENDING;
184
}
185
}
186
else
187
{
188
if
(ws
&
LVS_SORTASCENDING)
189
{
190
nSortOrder
=
LVS_SORTDESCENDING;
191
ncurSortCol
=
pNMListView
->
iSubItem;
192
}
193
else
194
{
195
nSortOrder
=
LVS_SORTASCENDING;
196
ncurSortCol
=
pNMListView
->
iSubItem;
197
}
198
}
199
200
//
将当前的排序信息保存在窗口Style中,供以后使用
201
ws
|=
nSortOrder;
202
SetWindowLong(lc
->
m_hWnd, GWL_STYLE, ws);
203
204
//
将各ITEM的LPARAM用新排序列的内容替换
205
LVITEM li;
206
li.mask
=
LVIF_PARAM
|
LVIF_TEXT;
207
TCHAR szItemText[
1024
];
208
for
(
int
i
=
0
; i
<
lc
->
GetItemCount(); i
++
)
209
{
210
li.iItem
=
i;
211
li.iSubItem
=
ncurSortCol;
212
li.cchTextMax
=
1024
;
213
li.pszText
=
szItemText;
214
lc
->
GetItem(
&
li);
215
TCHAR
*
szlparam
=
(TCHAR
*
)li.lParam;
216
//
删除以前的信息,释放空间
217
//
添加List Item时应注意将lParam初始化NULL
218
if
(szlparam
!=
NULL)
219
delete szlparam;
220
221
//
复制当前列的szItemText到Item的lParam中
222
szlparam
=
new
TCHAR[lstrlen(szItemText)
+
1
];
223
lstrcpy(szlparam, szItemText);
224
lc
->
SetItemData(i, DWORD(szlparam));
225
}
226
227
//
开始排序
228
if
(ncurSortCol
==
0
)
//
第一列按整数排序
229
{
230
GetListCtrl().SortItems(ListViewCompareIntFunc,(LPARAM)(
&
nSortOrder));
231
}
232
else
233
GetListCtrl().SortItems(ListViewCompareFunc,(LPARAM)(
&
nSortOrder));
234
*
pResult
=
0
;
235
236
}
237