转自:http://www.vckbase.com/index.php/wv/1590
CListView是界面中非常常用的视图类,前段时间给可视化平台换脸的时候,平台的输出不仅包括直观的图像显示,用户还希望直观地得到每帧图像的一些相关的参数信息、统计信息等,这时候我就选择在CListView中滚动地显示相关信息,并将窗口进行切分,将CListView的窗口放在整个主窗口的最底端,在需要的时候显示,不需要的时候隐藏。但是,我对CListView的用法不是很熟悉,在查MSDN和从网上查相关用法的时候,要不就是零星地介绍,要不就是只介绍CListCtrl的用法,这让我走了很多弯路,为此,我将从网上查到的用法,结合我的实际应用,简单介绍下CListView的使用,希望对像我一样对CListView不熟悉或刚接触MFC编程的人有所帮助,对一些编程老手、高手来说,这些自然不在话下。
CListView中内置了CListCtrl,所以对CListView的操作实际上就是对内置CListCtrl的操作。下面就从新建一个CListView的子类开始,我从工程中新建了一个叫做CInfoView的类,基类选择CListView。
1、初始化CListView,设置风格,背景和字体颜色,初始化行列。该项工作在OnInitialUpdate()中完成,如下所示。
01.
void
CInfoView::OnInitialUpdate()
02.
{
03.
CListView::OnInitialUpdate();
04.
05.
CListCtrl& m_list = GetListCtrl();
//得到内置的listctrl引用
06.
LONG
lStyle;
07.
lStyle = GetWindowLong(m_list.m_hWnd, GWL_STYLE);
//获取当前窗口风格
08.
lStyle &= ~LVS_TYPEMASK;
//清除显示方式位
09.
lStyle |= LVS_REPORT;
//设置报表风格
10.
SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);
//设置窗口风格
11.
DWORD
dwStyle = m_list.GetExtendedStyle();
12.
13.
//选中某行使整行高亮(只适用于报表风格的listctrl)
14.
dwStyle |= LVS_EX_FULLROWSELECT;
15.
dwStyle |= LVS_EX_GRIDLINES;
//网格线(只适用与报表风格的listctrl)
16.
m_list.SetExtendedStyle(dwStyle);
//设置扩展风格
17.
m_list.SetBkColor(RGB(200, 200, 200));
//设置背景颜色
18.
m_list.SetTextBkColor(RGB(200, 200, 200));
//设置文本背景颜色
19.
m_list.SetTextColor(RGB(10, 10, 80));
//设置文本颜色
20.
//插入列的标题,为了简单起见,我只插入三列
21.
m_list.InsertColumn( 0,
"图像帧号"
, LVCFMT_CENTER, 80 );
22.
m_list.InsertColumn( 1,
"可见性判断"
, LVCFMT_CENTER, 110 );
23.
m_list.InsertColumn( 2,
"置信度结果"
, LVCFMT_CENTER, 110 );
24.
}
2、插入一行数据。一般在实际应用中,都是在程序运行中,插入一行数据,这时候,需要在当前的程序语境中得到CInfoView的指针,然后进行插入数据的操作。在我的应用中,我把CinfoView作为拆分窗口的一个子窗口,所以具体操作如下:
01.
CListView*listview=(CListView*)(((CMainFrame*)theApp.GetMainWnd())->m_wndSplitter1.GetPane(1,0));
//得到ListView的指针
02.
CListCtrl& list = listview->GetListCtrl();
//得到listview内置listctrl的引用
03.
CString strId, strCo;
//图像帧号,置信度
04.
CString strVb =
"Y"
;
//可见性
05.
if
(fConfid[nIndex] <= 0)
06.
{
07.
strVb =
"N"
;
08.
}
09.
strId.Format(
"%d"
, nIndex+1);
10.
strCo.Format(
"% .4f"
, fConfid[nIndex]);
11.
//插入一行数据,始终在顶端插入新的数据
12.
int
nRow = list.InsertItem(0, strId);
13.
list.SetItemText(nRow, 1, strVb);
14.
list.SetItemText(nRow, 2, strCo);
3、右键单击弹出浮动菜单。在我的应用中,右键弹出的浮动菜单,只有一项:“删除所有内容”。要弹出浮动菜单,首先先要在“资源”的“Menu”中新建一个Menu,ID命名为IDR_POPMENU,然后在该Menu中添加一个主菜单“操作”,在“操作”下添加一个子菜单“删除所有内容”,ID命名为“ID_DELETE_ALL”,通过向导在CInfoView中给ID_DELETE_ALL添加消息响应函数OnDeleteAll(),如下:
1.
void
CInfoView::OnDeleteAll()
2.
{
3.
CListCtrl &m_list = GetListCtrl();
4.
m_list.DeleteAllItems();
5.
}
然后通过向导在CInfoView中添加右键单击响应函数=NM_RCLICK,如下:
01.
void
CInfoView::OnRclick(NMHDR* pNMHDR,
LRESULT
* pResult)
02.
{
03.
CListCtrl &m_list = GetListCtrl();
//获取当前列表控件的指针
04.
CMenu menu, *pSubMenu;
//定义下面要用到的cmenu对象
05.
menu.LoadMenu(IDR_POPMENU);
//装载自定义的右键菜单
06.
pSubMenu = menu.GetSubMenu(0);
//获取第一个弹出菜单
07.
CPoint oPoint;
//定义一个用于确定光标位置的位置
08.
GetCursorPos(&oPoint);
//获取当前光标的位置
09.
10.
//在指定位置显示弹出菜单
11.
pSubMenu->TrackPopupMenu(TPM_LEFTALIGN, oPoint.x, oPoint.y,
this
);
12.
}
4、添加消息响应函数OnCustomDraw(),为ClistCtrl的每个Item设置不同的颜色,在该应用中,为单数和偶数的Item项设置两种不同的颜色。具体步骤如下:
首先在InfoView.h的AFX_MSG之间添加消息函数声明:
1.
afx_msg
void
OnCustomDraw(NMHDR* pNMHDR,
LRESULT
* pResult);
然后在InfoView.cpp的BEGIN_MESSAGE_MAP之间添加消息映射:
1.
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
最后在InfoView.cpp中添加函数实现:
01.
void
CInfoView::OnCustomDraw(NMHDR* pNMHDR,
LRESULT
* pResult)
02.
{
03.
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR;
04.
switch
(lplvcd->nmcd.dwDrawStage)
05.
{
06.
int
iRow;
07.
case
CDDS_PREPAINT:
08.
*pResult = CDRF_NOTIFYITEMDRAW;
09.
break
;
10.
case
CDDS_ITEMPREPAINT:
11.
*pResult = CDRF_DODEFAULT;
12.
iRow= lplvcd->nmcd.dwItemSpec;
13.
if
(iRow & 1)
14.
{
15.
lplvcd->clrTextBk = RGB(230, 230, 230);
16.
//lplvcd->clrText = RGB(255, 255, 0);
17.
*pResult = CDRF_NEWFONT;
18.
}
19.
break
;
20.
default
:
21.
*pResult = CDRF_DODEFAULT;
22.
}
23.
}
5、为CInfoView添加点击列的标题进行排序的消息响应函数,在添加该消息响应函数之前,先要定义实现排序的回调函数。在该应用中,第一列是图像帧号,按自然数排序,其他列都按字串进行排列,所以定义两个比较的回调函数。
在InfoView.h中声明两个静态的回调函数:
1.
static
int
CALLBACK ListViewCompareFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort);
//按字串排序
2.
static
int
CALLBACK ListViewCompareIntFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort);
//按自然数排序
在InfoView.cpp中实现两个静态的回调函数:
01.
int
CALLBACK CInfoView::ListViewCompareFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort)
02.
{
03.
// 得到排序方式
04.
int
*pisortorder = (
int
*)lParamSort;
05.
06.
// 得到两个列的排序信息
07.
TCHAR
*sz1 = (
TCHAR
*)lParam1;
08.
TCHAR
*sz2 = (
TCHAR
*)lParam2;
09.
10.
// 比较列的信息并返回比较结果。
11.
// 若为减序,则将比较结果乘上-1。
12.
if
(*pisortorder == LVS_SORTASCENDING)
13.
return
lstrcmp(sz1, sz2);
14.
else
15.
return
lstrcmp(sz1, sz2) * (-1);
16.
}
17.
18.
int
CALLBACK CInfoView::ListViewCompareIntFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort)
19.
{
20.
// 得到排序方式
21.
int
*pisortorder = (
int
*)lParamSort;
22.
23.
// 得到两个列的排序信息
24.
TCHAR
*sz1 = (
TCHAR
*)lParam1;
25.
TCHAR
*sz2 = (
TCHAR
*)lParam2;
26.
int
n1 = _ttoi(sz1);
27.
int
n2 = _ttoi(sz2);
28.
29.
// 比较列的信息并返回比较结果。
30.
// 若为减序,则将比较结果乘上-1。
31.
if
(*pisortorder == LVS_SORTASCENDING)
32.
{
33.
if
(n1 - n2 > 0)
return
1;
34.
else
if
(n1 -n2 == 0)
return
0;
35.
else
return
-1;
36.
}
37.
else
38.
{
39.
if
(n1 - n2 > 0)
return
-1;
40.
else
if
(n1 -n2 == 0)
return
0;
41.
else
return
1;
42.
}
43.
}
5、为CInfoView添加点击列的标题进行排序的消息响应函数,在添加该消息响应函数之前,先要定义实现排序的回调函数。在该应用中,第一列是图像帧号,按自然数排序,其他列都按字串进行排列,所以定义两个比较的回调函数。
在InfoView.h中声明两个静态的回调函数:
1.
static
int
CALLBACK ListViewCompareFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort);
//按字串排序
2.
static
int
CALLBACK ListViewCompareIntFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort);
//按自然数排序
在InfoView.cpp中实现两个静态的回调函数:
01.
int
CALLBACK CInfoView::ListViewCompareFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort)
02.
{
03.
// 得到排序方式
04.
int
*pisortorder = (
int
*)lParamSort;
05.
06.
// 得到两个列的排序信息
07.
TCHAR
*sz1 = (
TCHAR
*)lParam1;
08.
TCHAR
*sz2 = (
TCHAR
*)lParam2;
09.
10.
// 比较列的信息并返回比较结果。
11.
// 若为减序,则将比较结果乘上-1。
12.
if
(*pisortorder == LVS_SORTASCENDING)
13.
return
lstrcmp(sz1, sz2);
14.
else
15.
return
lstrcmp(sz1, sz2) * (-1);
16.
}
17.
18.
int
CALLBACK CInfoView::ListViewCompareIntFunc(
LPARAM
lParam1,
LPARAM
lParam2,
LPARAM
lParamSort)
19.
{
20.
// 得到排序方式
21.
int
*pisortorder = (
int
*)lParamSort;
22.
23.
// 得到两个列的排序信息
24.
TCHAR
*sz1 = (
TCHAR
*)lParam1;
25.
TCHAR
*sz2 = (
TCHAR
*)lParam2;
26.
int
n1 = _ttoi(sz1);
27.
int
n2 = _ttoi(sz2);
28.
29.
// 比较列的信息并返回比较结果。
30.
// 若为减序,则将比较结果乘上-1。
31.
if
(*pisortorder == LVS_SORTASCENDING)
32.
{
33.
if
(n1 - n2 > 0)
return
1;
34.
else
if
(n1 -n2 == 0)
return
0;
35.
else
return
-1;
36.
}
37.
else
38.
{
39.
if
(n1 - n2 > 0)
return
-1;
40.
else
if
(n1 -n2 == 0)
return
0;
41.
else
return
1;
42.
}
43.
}
然后通过向导为事件LVN_COLUMNCLICK添加消息响应函数OnColumnclick(),在该函数中调用上面的回调函数
01.
void
CInfoView::OnColumnclick(NMHDR* pNMHDR,
LRESULT
* pResult)
02.
{
03.
// TODO: Add your control notification handler code here
04.
static
int
ncurSortCol = -1;
// 保存当前的排序列。
05.
// 一开始表示为-1,表示尚未按任何列排序。
06.
07.
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
08.
09.
CListCtrl* lc = &GetListCtrl();
10.
LONG
ws = GetWindowLong(lc->m_hWnd, GWL_STYLE);
11.
int
nSortOrder;
// 排序的方式
12.
13.
// 若点击列与当前排序列不同的列,则改变排序序,并将排序方式改为增序。
14.
// 若当前排序列与点击列相同,则更改增、减序的排序方式
15.
if
(ncurSortCol == pNMListView->iSubItem)
16.
{
17.
if
(ws & LVS_SORTASCENDING)
18.
{
19.
ws ^= LVS_SORTASCENDING;
20.
nSortOrder = LVS_SORTDESCENDING;
21.
}
22.
else
23.
{
24.
ws ^= LVS_SORTDESCENDING;
25.
nSortOrder = LVS_SORTASCENDING;
26.
}
27.
}
28.
else
29.
{
30.
if
(ws & LVS_SORTASCENDING)
31.
{
32.
nSortOrder = LVS_SORTDESCENDING;
33.
ncurSortCol = pNMListView->iSubItem;
34.
}
35.
else
36.
{
37.
nSortOrder = LVS_SORTASCENDING;
38.
ncurSortCol = pNMListView->iSubItem;
39.
}
40.
}
41.
42.
// 将当前的排序信息保存在窗口Style中,供以后使用
43.
ws |= nSortOrder;
44.
SetWindowLong(lc->m_hWnd, GWL_STYLE, ws);
45.
46.
// 将各ITEM的LPARAM用新排序列的内容替换
47.
LVITEM li;
48.
li.mask = LVIF_PARAM|LVIF_TEXT;
49.
TCHAR
szItemText[1024];
50.
for
(
int
i = 0; i < lc->GetItemCount(); i++)
51.
{
52.
li.iItem = i;
53.
li.iSubItem = ncurSortCol;
54.
li.cchTextMax = 1024;
55.
li.pszText = szItemText;
56.
lc->GetItem(&li);
57.
TCHAR
* szlparam = (
TCHAR
*)li.lParam;
58.
// 删除以前的信息,释放空间
59.
// 添加List Item时应注意将lParam初始化NULL
60.
if
(szlparam != NULL)
61.
delete
szlparam;
62.
63.
// 复制当前列的szItemText到Item的lParam中
64.
szlparam =
new
TCHAR
[lstrlen(szItemText) + 1];
65.
lstrcpy(szlparam, szItemText);
66.
lc->SetItemData(i,
DWORD
(szlparam));
67.
}
68.
69.
// 开始排序
70.
if
(ncurSortCol == 0)
//第一列按整数排序
71.
{
72.
GetListCtrl().SortItems(ListViewCompareIntFunc,(
LPARAM
)(&nSortOrder));
73.
}
74.
else
75.
GetListCtrl().SortItems(ListViewCompareFunc,(
LPARAM
)(&nSortOrder));
76.
*pResult = 0;
77.
}
本文详细介绍了CListView的常规用法,希望对大家有参考作用!