CListView常用用法

转自: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, LPARAMlParamSort);//按字串排序
2. static int CALLBACK ListViewCompareIntFunc(LPARAM lParam1, LPARAM lParam2, LPARAMlParamSort);//按自然数排序

在InfoView.cpp中实现两个静态的回调函数:

01. int CALLBACK CInfoView::ListViewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAMlParamSort)
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, LPARAMlParamSort)
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, LPARAMlParamSort);//按字串排序
2. static int CALLBACK ListViewCompareIntFunc(LPARAM lParam1, LPARAM lParam2, LPARAMlParamSort);//按自然数排序

在InfoView.cpp中实现两个静态的回调函数:

01. int CALLBACK CInfoView::ListViewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAMlParamSort)
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, LPARAMlParamSort)
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的常规用法,希望对大家有参考作用!

你可能感兴趣的:(VC)