声明:
1、本文为翻译文章,水平有限,错误之处,烦请指正(chinajiezhang@gmail.com)。
2、使用VS2005,所以在某些细节上和原作者不太一样
3、工程中使用图片和作者略有不同
4、文章如有争议,以原作者文章为准
5、转载请标明出处
原文链接:http://www.functionx.com/visualc/controls/listcontrol.htm
一、ListControl概述
概述:
ListCtrl控件由四种列表的显示方式构成,它最典型的用法是使用icon来显示。ListCtrl通常显示下面四种项目(item):
Icons: 控件显示项的列表,使用32*32(像素)大小的icons,推荐使用这么大小的icon,如果你想用图标来概述你的观点。
Small Icons:和剩下的两项相似的想法,它使用16*16(像素)大小的图标来显示一个单一的列表项。再次,没有提供关于这个列表的详细说明。这种列表是用来组织和其他主题在不同的列,如果列表有序,序列编排为按字母顺序从左到右。
List:这种列表,使用small icons,也是组织列;这种情况下,在第二列填充之前必须填充第一列。如果列表有序,序列编排为自顶向下的顺序。
Report:安排项的目的是提供列表开发者的信息。
二、实践学习:List Control介绍
1. 用Visual C++或者Visual Studio 创建一个名为DeptStore2的MFC应用程序
2. 基于Dialog创建它
3. 删除“TODO: 在此放置对话框控件。”行和确定按钮。
4. 将“取消”按钮的标题改为“关闭”
(1) 创建List Control
ListCtrl控件在MFC类库用CListCtrl类来实现。在设计的时候,创建一个ListCtrl,在toolbox中点击按钮 后单击对话框中想要放置的区域。通常来说,需要拉伸默认ListCtrl的默认大小,因为它通常需要一个更大的区域。
为了编程创建一个ListCtrl,声明CListCtrl变量或者CListCtrl指针。初始化控件调用它的Create方法,示例如下:
BOOL CDeptStore2Dlg::OnInitDialog() { CDialog::OnInitDialog(); // ... // TODO: 在此添加额外的初始化代码 CListCtrl * lstCtrl = new CListCtrl; lstCtrl -> Create(WS_CHILD | WS_VISIBLE, CRect( 10 , 10 , 320 , 280 ), this , 0x285 ); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
译者提示:这是内存泄露的做法,也许作者意图只是为了说明应在OnInitDialog添加代码,正确的做法在CDeptStore2Dlg中添加变量m_lstCtrl,之后在OnInitDialog中new,最后在析构函数中delete。
在之前提到,ListCtrl可以显示四种情况之一,在设计的时候应该在窗口属性中指定想要的风格,在属性中选择combo box,默认值是Icon,他可能是情况是:
Icon:当编程创建控件的时候,增加LVS_ICON风格;
Small Icon:类似的可以动态添加LVS_SMALLICON风格:
List:当创建的时候可以类似的添加LVS_REPORT风格;
Report:这种情况清楚的显示了列,同样应添加LVS_REPORT风格。
除了常规的几种风格外,Win32类库为ListCtrl提供了扩展风格,提供了一个扩展风格,调用CListCtrl::SetExtendStyle()方法,它的语法为:
DWORD SetExtendedStyle(DWORD dwNewStyle);
当调用这个函数的时候,把指定的扩展风格或者他们的组合风格作为参数来传递。其中的一些值是:
LVS_EX_CHECKBOXES:在左侧显示选择框(check box)
LVS_EX_FULLROWSELECT:这种风格允许Report View的整行来被选择而不是仅仅一项;
LVS_EX_GRIDLINES:相对上一种风格来说增加了水平和垂直分割线。
LVS_EX_TRACKSELECT:当设置这种风格的时候,用户可以隔项选取。
列表控件仅仅能在控件内显示,如果这儿他们太多或者各项的总宽度比控件可以显示的区域大,应该给它配备水平滚动条和垂直滚动条,或者两个都有。如果你想阻止滚动条的显示,设置无滚动条的属性为true或者创建属性为LVS_NOSCROLL风格。
一旦list控件创建,使用者可以选择一个选项通过点击它,然后选择更多的项,使用者也可以辅助ctrl来随机选择或者辅助shift连续选取,下面是一个随机选取的一个样例:
如果你不想用户每次选择多项的话,你可以设置通过增加LVS_SINGLESEL单选属性为true。
任何项被选中的时候都是高亮的,当用户点击另一个控件或者另一个应用程序的时候,你是否可以确定你想那些被选项仍旧被选中呢?典型的情况是在设计的时候通过选择“Always”属性来实现。默认情况下,设置为false,意味着当控件失去焦点或者它的父窗口无效的情况下,被选项将不会显示(高亮)。否则,你可以把这个属性设置为true,这样即使它失去焦点也也可以是选中状态。这个属性也可以通过设置LVS_SHOWSELALWAYS风格来实现。
三、实践学习:创建一个ListCtrl
1.在ToolBox上,单击ListCtrl控件然后点击对话框,将ID改为IDC_STORE_ITEMS
2.右击控件,添加变量
3.设置变量为:m_StoreItems
4.点击完成
ListCtrl的项
通过添加(使用toolboax)或者动态创建一个ListCtrl之后,下一个环节你应该让它来显示项。这个可以通过调用CListCtrl::InsertItem()方法,它的一种声明如下:
int InsertItem(const LVITEM* pItem);
这个版本需要一个LVITEM的指针作为参数,LVITEM定义如下:
typedef struct { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPTSTR pszText; int cchTextMax; int iImage; LPARAM lParam; #if (_WIN32_IE >= 0x0300) int iIndent; #endif #if (_WIN32_WINNT >= 0x0501) int iGroupId; UINT cColumns; UINT puColumns; #endif #if (_WIN32_WINNT >= 0x0600) int piColFmt; int iGroup; #endif } LVITEM, * LPLVITEM;
mask:用来指定你想给当前项设置的类型。
iItem:指定改变项的索引,第一个item应该为0,第二个item为1等等。
iSumItem:当前值的的子项,如果当前项是主导项,iSumItem应该存储从0开始的数组。
pszText:要显示项的字符串,你可以通过cchTextMask指定文本的长度。
初始化LVITEM之后,调用InsertItem()方法来为list添加一个项。以下是范例:
BOOL CDeptStore2Dlg::OnInitDialog() { CDialog::OnInitDialog(); // ... // TODO: 在此添加额外的初始化代码 LVITEM lvItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = 0 ; lvItem.iSubItem = 0 ; lvItem.pszText = _T( " Sandra C. Anschwitz " ); m_StoreItems.InsertItem( & lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = 1 ; lvItem.iSubItem = 0 ; lvItem.pszText = _T( " Roger A. Miller " ); m_StoreItems.InsertItem( & lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = 2 ; lvItem.iSubItem = 0 ; lvItem.pszText = _T( " Marie-Julie W. Gross " ); m_StoreItems.InsertItem( & lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = 3 ; lvItem.iSubItem = 0 ; lvItem.pszText = _T( " Ella Pius Roger " ); m_StoreItems.InsertItem( & lvItem); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
LVITEM结构体的值将决定新项的功能。例如,一旦增加了一个项,你可能想要准备删除前面的项、剪切和粘贴操作,在这种情况下,你应该将设置为LVIS_CUT;如果你想实现拖放操作,你可以设置LVIS_DROPHILIGHTED;如果想让项获得焦点,设置LVIS_FOCUSED;包含LVIS_SELECTED属性的情况下可以被选中。
除了上面的CListCtrl::InsertItem()版本,CListCtrl类还提供了如下版本:
int InsertItem(int nItem, LPCTSTR lpszItem);
这是一个早期最简洁的版本。nItem表示新增项的索引。和LVITEM::iItem成员类似,如果参数为0,新增项是首项。lpszItem参数值是当前项内容的字符串。
四、实战学习:构建(Populating)ListCtrl
1. 新建一个dialog box,选择主菜单项->右击工程->增加资源
2. 在增加资源对话框中选择dialog
3. 修改对话框的ID为:IDD_STOREITEMS_DLG
4. 设计对话框如下:
Control | ID | Caption |
Static Text |
| Item #: |
Edit Control | IDC_ITEMNUMBER |
|
5. 右击对话框,选择添加类
6. 设置类的名字为CNewStoreItemDlg基类为CDialog
7. 点击完成
8. 为edit control增加一个CString变量,命名为m_ItemNumber
9. 切换到第一个对话框,在ListCtrl下面,增加一个按钮,设置它的属性如下:
标题:新建项
ID:IDC_NEWITEM
10. 双击新建项按钮,生成它的OnBnClicked事件。
11. 在文件的前面,键入:#include "NewStoreItemDlg.h"
#include " stdafx.h " #include " DeptStore2.h " #include " DeptStore2Dlg.h " #include " NewStoreItemDlg.h " #ifdef _DEBUG #define new DEBUG_NEW #endif
12. 如下实现事件内容:
void CDeptStore2Dlg::OnBnClickedNewitem() { // TODO: Add your control notification handler code here CNewStoreItemDlg dlg; srand( (unsigned)time(NULL) ); char strNumber[ 20 ]; int number1 = rand() % 999 ; int number2 = rand() % 999 ; sprintf(strNumber, " %d-%d " , number1, number2); dlg.m_ItemNumber = strNumber; if ( dlg.DoModal() ) { LVITEM lvItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = 0 ; lvItem.iSubItem = 0 ; lvItem.pszText = strNumber; this -> m_StoreItems.InsertItem( & lvItem); } }
13. 运行应用程序,测试新建项
报告方式显示(The Report View)
无论你是用第一还是第二个版本,InsertItem只允许你去创建你要显示的图标,小图标,或者控件的List Views的项。如果你计划去显示在Report View(或者允许用户在几种显示方式中转换)或者你想要提供更多的信息为每一个项,你必须要创建一个关于每一个项信息的报告。
在ListCtrl可能的显示方式中,其中有一种可以显示列。这种使用报告的方式。这种方式不需要一个列表,而是提供一个列表的项的详细信息。如果你打算在你的ListCtrl控件中显示,那么你应该去创建列。(要么,你可以省略创建列而是每个分离的列的首项,可以使用CHeaderCtrl类来实现。否则,ListCtrl提供创建列为它的报告显示)
To create the column(s) of a list control, you can use the CListCtrl::InsertColumn() method. One of its syntaxes is:
创建一个ListCtrl的列,你可以使用CListCtrl::InsertColumn()方法,它的一种声明为:
int InsertColumn(int nCol, const LVCOLUMN* pColumn);
nCol:将要创建列的索引
pColumn:指向LVCOLUMN结构体指针,结构体定义如下:
typedef struct _LVCOLUMN { UINT mask; int fmt; int cx; LPTSTR pszText; int cchTextMax; int iSubItem; #if (_WIN32_IE >= 0x0300) int iImage; int iOrder; #endif } LVCOLUMN, FAR * LPLVCOLUMN;
mask: 用来指定你想要的列的属性
Fmt: 格式化列的文本。例如,它可以使列左对齐(默认值LVCFMT_LEFT),居中(LVCFMT_CENTER),或者右对齐(LVCFMT_RIGHT)。如果你想为这个值设置一个值,那么在初始化mask变量的时候增加LVCF_FMT属性。
cx 用来指定列文本的宽度。如果你初始化,它的长度将被初始化为刚好能显示文本的长度。因此,除非你有一个好的理由去省略它,你应该总是指定它的值。如果你打算去初始化这个值,那么在初始化mask变量的时候增加LVCF_WIDTH属性。
pszText 是将要显示的列的字符串。和其他成员一样,此变量不是必须要初始化的,除了每一个列的第一个元素。这个成员可能是最重要的列的特征,因为它告诉用户这一列的作用。它的值是一个"\0"结尾的字符串。和其他MFC应用程序中的字符串一样,该字符串可以是一个字符串表项。它也可以从一个字符串数组中获取。为此变量初始化值,在初始化mask时应增加LVCF_TEXT变量,它的长度可以通过cchTextMax成员来设置。
初始化LVCOLUMN之后,把它作为InsertColumn的第二个参数进行传递。下面是示例:
BOOL CDeptStore2Dlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化代码 LVCOLUMN lvColumn; int nCol; lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 120 ; lvColumn.pszText = TEXT( " Full Name " ); nCol = m_StoreItems.InsertColumn( 0 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 100 ; lvColumn.pszText = TEXT( " Profession " ); m_StoreItems.InsertColumn( 1 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 80 ; lvColumn.pszText = TEXT( " Fav Sport " ); m_StoreItems.InsertColumn( 2 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 75 ; lvColumn.pszText = TEXT( " Hobby " ); m_StoreItems.InsertColumn( 3 , & lvColumn); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
(译者注:需要修改ListCtrl为Report型)
iOrder:用来标识列的地址(列的索引)
你也可以用CListCtrl::InsertColumn()方法的另一个版本,你可以用下面的版本,来为控件创建列:
int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = - 1 , int nSubItem = - 1 );
这个版本是上个版本的简化版。
nCol: 列的索引,必须要指定的;
lpszColumnHeading:在列的开始要显示的字符串,和LVCOLUMN::pszText成员相似;
nFormat:用来指定lpszColumnHeading的水平对齐方式。默认为左对齐(LVCFMT_LEFT),居中为LVCFMT_CENTER,右对齐为LVCFMT_RIGHT;
nWidth:以像素为单位来设定列的宽度,如果你不想指定它的大小,可设置为-1;
nSubItem:用来设定当前列子项的索引。
列配置好之后,你必须要提供在特定列下显示的字符串项。为了实现这一功能,你必须先设定你要增加项的信息。InsertColumn()方法将会返回一个整形值来标识你增加列的信息。接着为每一列指定将要显示的项的字符串,调用CListCtrl::SetItemText()方法。它的声明为:
BOOL SetItemText(int nItem, int nSubItem, LPTSTR lpszText);
nItem:你要增加行的索引,它可以通过InsertColumn()的返回值获得。每一项的信息存储在一个以"\0"结尾的数组。
nSubItem:当前项所在的位置。(译者注:通过nItem和nSumItem确定项的位置,在平面中第nItem行,第nSumItem列)
lpszText:当前项的信息
示例:
BOOL CDeptStore2Dlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化代码 LVCOLUMN lvColumn; lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 120 ; lvColumn.pszText = TEXT( " Full Name " ); m_StoreItems.InsertColumn( 0 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 100 ; lvColumn.pszText = TEXT( " Profession " ); m_StoreItems.InsertColumn( 1 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 80 ; lvColumn.pszText = TEXT( " Fav Sport " ); m_StoreItems.InsertColumn( 2 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 75 ; lvColumn.pszText = TEXT( " Hobby " ); m_StoreItems.InsertColumn( 3 , & lvColumn); LVITEM lvItem; int nItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = 0 ; lvItem.iSubItem = 0 ; lvItem.pszText = TEXT( " Sandra C. Anschwitz " ); nItem = m_StoreItems.InsertItem( & lvItem); m_StoreItems.SetItemText(nItem, 1 , TEXT( " Singer " )); m_StoreItems.SetItemText(nItem, 2 , TEXT( " HandBall " )); m_StoreItems.SetItemText(nItem, 3 , TEXT( " Beach " )); lvItem.mask = LVIF_TEXT; lvItem.iItem = 1 ; lvItem.iSubItem = 0 ; lvItem.pszText = TEXT( " Roger A. Miller " ); nItem = m_StoreItems.InsertItem( & lvItem); m_StoreItems.SetItemText(nItem, 0 , TEXT( " Footballer " )); m_StoreItems.SetItemText(nItem, 1 , TEXT( " Tennis " )); m_StoreItems.SetItemText(nItem, 2 , TEXT( " Teaching " )); lvItem.mask = LVIF_TEXT; lvItem.iItem = 2 ; lvItem.iSubItem = 0 ; lvItem.pszText = TEXT( " Marie-Julie W. Gross " ); nItem = m_StoreItems.InsertItem( & lvItem); m_StoreItems.SetItemText(nItem, 1 , TEXT( " Student " )); m_StoreItems.SetItemText(nItem, 2 , TEXT( " Boxing " )); m_StoreItems.SetItemText(nItem, 3 , TEXT( " Programming " )); lvItem.mask = LVIF_TEXT; lvItem.iItem = 3 ; lvItem.iSubItem = 0 ; lvItem.pszText = TEXT( " Ella Pius Roger " ); nItem = m_StoreItems.InsertItem( & lvItem); m_StoreItems.SetItemText(nItem, 1 , TEXT( " Architect " )); m_StoreItems.SetItemText(nItem, 2 , TEXT( " Ping-Pong " )); m_StoreItems.SetItemText(nItem, 3 , TEXT( " Songo " )); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
四、实践学习:一个ListCtrl的详细实现
1.切换到第一个对话框点击ListCtrl控件
2.在属性窗口,改变View属性为Report
3.创建ListCtrl的列,在OnInitDialog()中添加代码如下:
BOOL CDeptStore2Dlg::OnInitDialog() { CDialog::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here LVCOLUMN lvColumn; lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_CENTER; lvColumn.cx = 60 ; lvColumn.pszText = " Item # " ; this -> m_StoreItems.InsertColumn( 0 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 100 ; lvColumn.pszText = " Category " ; this -> m_StoreItems.InsertColumn( 1 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 160 ; lvColumn.pszText = " Item Name " ; this -> m_StoreItems.InsertColumn( 2 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 80 ; lvColumn.pszText = " Size " ; this -> m_StoreItems.InsertColumn( 3 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_RIGHT; lvColumn.cx = 60 ; lvColumn.pszText = " Unit Price " ; this -> m_StoreItems.InsertColumn( 4 , & lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_RIGHT; lvColumn.cx = 30 ; lvColumn.pszText = " Qty " ; this -> m_StoreItems.InsertColumn( 5 , & lvColumn); this -> m_StoreItems.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); return TRUE; // return TRUE unless you set the focus to a control }
4.准备创建一个完全的项,设计一个第一个对话框如下:
Control | Caption | ID | Other Properties |
Static Text | Category: |
|
|
Combo Box |
| IDC_CATEGORIES | Data: Babies;Teens;Women;Men;Miscellaneous |
Static Text | Item Name: |
|
|
Edit Control |
| IDC_ITEMNAME |
|
Static Text | Item Size: |
|
|
Edit Control |
| IDC_ITEMSIZE |
|
Static Text | Qty: |
|
|
Edit Control |
| IDC_QUANTITY |
|
Static Text | Unit Price: |
|
|
Edit Control |
| IDC_UNITPRICE |
|
Static Text | Item #: |
|
|
Edit Control |
| IDC_ITEMNUMBER |
|
Button | OK | IDOK |
|
Button | Cancel | IDCANCEL |
|
5.如下创建CString变量
ID | Value Variable |
IDC_CATEGORIES | m_Categories |
IDC_ITEMNAME | m_ItemName |
IDC_ITEMSIZE | m_ItemSize |
IDC_QUANTITY | m_Quantity |
IDC_UNITPRICE | m_UnitPrice |
6.在主窗口中,双击新建项改变它的实现为:
void CDeptStore2Dlg::OnBnClickedNewitem() { // TODO: 在此添加控件通知处理程序代码 CNewStoreItemDlg1 dlg; srand( (unsigned)time(NULL) ); wchar_t strNumber[ 20 ]; int number1 = rand() % 999 ; int number2 = rand() % 999 ; swprintf(strNumber, TEXT( " %d-%d " ), number1, number2); dlg.m_ItemNumber = strNumber; if ( dlg.DoModal() ) { LVITEM lvItem; int nItem; lvItem.mask = LVIF_TEXT; lvItem.iItem = 0 ; lvItem.iSubItem = 0 ; lvItem.pszText = strNumber; nItem = this -> m_StoreItems.InsertItem( & lvItem); this -> m_StoreItems.SetItemText(nItem, 1 , dlg.m_Categories); this -> m_StoreItems.SetItemText(nItem, 2 , dlg.m_ItemName); this -> m_StoreItems.SetItemText(nItem, 3 , dlg.m_ItemSize); this -> m_StoreItems.SetItemText(nItem, 4 , dlg.m_UnitPrice); this -> m_StoreItems.SetItemText(nItem, 5 , dlg.m_Quantity); } }
7.运行应用程序,用下面的数据创建数据项(让计算机随机生成itemNumber)
Category | Item Name | Size | Qty | Unit Price |
Women | Cashmere Lined Glove | 8 | 12 | 115.95 |
Miscellaneous | Chocolate Gift Box | Medium | 5 | 45.00 |
Men | Trendy Jacket | Medium | 8 | 45.85 |
Women | Stretch Flare Jeans | Petite | 6 | 27.75 |
Women | Belted Sweater | Large | 10 | 15.95 |
Teens | Girls Classy Handbag | One Size | 4 | 95.95 |
Women | Casual Dress Shoes | 9.5M | 16 | 45.95 |
Babies | Infant Girls Ballerina Dress | 2M | 14 | 22.85 |
Teens | Girls Velour Dress | 10 | 8 | 12.55 |
Women | Lace Desire Panty | M | 22 | 7.15 |
Teens | Boys Hooded Sweatshirt | M (7/8) | 16 | 42.75 |
Men | Classic Pinstripe Suit | 38 | 8 | 145.90 |
8.关闭窗口,返回应用程序
Views转换
你可以创建一个ListCtrl显示一个单独的View,你也可以允许用户区改变从一个View到另外一个。和刚才所说的一样,在设计的时候或者程序动态创建一个ListCtrl,你可以设置一个初始化View用ComboBox去选择一个View。如果你想在初始化的时候显示,你可以停到那里,否则你可以提供改变的一种。
因为在一个ListCtrl显示的View是它风格的一部分。为了动态改变它的View模型,你可以用GetWindowLong()返回控件的风格。GetWindowLong()函数只返回当前控件的风格。你可能需要在改变它之前选择它。通过为GetWindowLong()函数增加LVS_TYPEMASK常量,在选择控件的View之后,你接着可以用SetWindowLong()函数来改变它的风格。示例如下:
void COthersDlg::OnIconBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~ LVS_TYPEMASK; mListStyle |= LVS_ICON; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); } void COthersDlg::OnSmallIconBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~ LVS_TYPEMASK; mListStyle |= LVS_SMALLICON; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); } void COthersDlg::OnListBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~ LVS_TYPEMASK; mListStyle |= LVS_LIST; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); } void COthersDlg::OnReportBtn() { // TODO: Add your control notification handler code here LONG mListStyle = GetWindowLong(m_List.m_hWnd, GWL_STYLE); mListStyle &= ~ LVS_TYPEMASK; mListStyle |= LVS_REPORT; SetWindowLong(m_List.m_hWnd, GWL_STYLE, mListStyle); }
五、实践学习:改变ListCtrl的View
1.在类视图中,扩展DeptStore2,右击CDeptStoreDlg2->Add->Add Function
2.设置返回值为DWORD类型,函数名为GetViewType
3.点击完成,函数实现如下:
DWORD CDeptStore2Dlg::GetViewType( void ) { return (GetStyle() & LVS_TYPEMASK); }
4.在类视图中,右击CDeptStore2Dlg->Add->Add Function
5.设置返回值为void,函数名称为SetViewType,参数类型为DWORD,参数名为dwViewType,点击Add。
6.点击完成,函数实现如下:
void CDeptStore2Dlg::SetViewType(DWORD dwViewType) { DWORD dwCurType; HWND hWnd; hWnd = this -> m_StoreItems; GetSafeHwnd(); dwCurType = ::GetWindowLong(hWnd, GWL_STYLE); dwCurType &= ~ LVS_TYPEMASK; dwViewType |= dwCurType; ::SetWindowLong(hWnd, GWL_STYLE, dwViewType); }
7.切换到第一个对话框,如下增加四个按钮:
Button ID | Caption |
IDC_LARGE | Large |
IDC_SMALL | Small |
IDC_LIST | List |
IDC_DETAILS | Details |
8.双击Large按钮,如下实现OnBnClicked事件:
void CDeptStore2Dlg::OnBnClickedLarge() { // TODO: Add your control notification handler code here SetViewType(LVS_ICON); }
9.类似添加其他按钮的事件响应函数,如下:
void CDeptStore2Dlg::OnBnClickedSmall() { // TODO: Add your control notification handler code here if ( GetViewType() != LVS_SMALLICON) SetViewType(LVS_SMALLICON); } void CDeptStore2Dlg::OnBnClickedList() { // TODO: Add your control notification handler code here if ( GetViewType() != LVS_LIST) SetViewType(LVS_LIST); } void CDeptStore2Dlg::OnBnClickedDetails() { // TODO: Add your control notification handler code here if ( GetViewType() != LVS_REPORT) SetViewType(LVS_REPORT); }
10.保存
ListCtrl和Icon
ListCtrl可以将实现图片,显示记录或者将两者组合显示。如果你想在列上显示一幅位图,你应该声明一个CImageList变量并初始化。然后调用CListCtrl::SetImageList()方法,并为之传参。如果你想这么做,并且你用的是第一个版本传递LVCOLUMN指针参数CListCtrl::InsertColumn()方法,需要给mask参数添加LVCF_IMAGE值,并且为fmt添加LVCFMT_IMAGE值。指定的图像会显示在列的首项上,把列的索引赋给iImage变量。示例如下:
BOOL COthersDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//
TODO: Add extra initialization here
LVCOLUMN lvColumn;
CImageList *ImgHeaders =
new CImageList;
ImgHeaders->Create(
16,
16, ILC_MASK,
1,
1);
ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_UP));
ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_LOSANGE));
m_List.SetImageList(ImgHeaders, LVSIL_SMALL);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE;
lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE;
lvColumn.cx =
120;
lvColumn.pszText =
"
Full Name
";
lvColumn.iImage =
0;
m_List.InsertColumn(
0, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx =
100;
lvColumn.pszText =
"
Profession
";
m_List.InsertColumn(
1, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE;
lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE;
lvColumn.iImage =
1;
lvColumn.cx =
80;
lvColumn.pszText =
"
Fav Sport
";
m_List.InsertColumn(
2, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx =
75;
lvColumn.pszText =
"
Hobby
";
m_List.InsertColumn(
3, &lvColumn);
return TRUE;
//
return TRUE unless you set the focus to a control
//
EXCEPTION: OCX Property Pages should return FALSE
}
BOOL COthersDlg::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here LVCOLUMN lvColumn; CImageList *ImgHeaders = new CImageList; ImgHeaders->Create( 16, 16, ILC_MASK, 1, 1); ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_UP)); ImgHeaders->Add(AfxGetApp()->LoadIcon(IDI_LOSANGE)); m_List.SetImageList(ImgHeaders, LVSIL_SMALL); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE; lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE; lvColumn.cx = 120; lvColumn.pszText = " Full Name "; lvColumn.iImage = 0; m_List.InsertColumn( 0, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 100; lvColumn.pszText = " Profession "; m_List.InsertColumn( 1, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_IMAGE; lvColumn.fmt = LVCFMT_LEFT | LVCFMT_IMAGE; lvColumn.iImage = 1; lvColumn.cx = 80; lvColumn.pszText = " Fav Sport "; m_List.InsertColumn( 2, &lvColumn); lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 75; lvColumn.pszText = " Hobby "; m_List.InsertColumn( 3, &lvColumn); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE }
在控件上使用位图或图标,你应该首先创建位图或图。如果你不打算使用Report View并且你想使用位图,你可以创建一个很长的位图(由一些小的大小相似的位图组成)。每一幅图像供每一个项使用。正常情况下,每个图片应该大小为16*16或者更小。下面是示例:
位图是由6幅相同大小的图片组成的。如果你不打算使用Report View并且你打算使用icons,那么就应该单独的创建16*16大小的icon。
如果你想使用ReportView和其他Views显示控件项,如果你想使用位图,你用该创建两个长位图。一个应该是16*16大小的。这样的图片用来做小图标(small icon),List,和ReportViews。你应该创建第二个位图,大小为32*32。这些图片用来为ListView服务。
在你创建完位图或者图标之后,紧接着声明一个指向CImageList类的指针并且用CImageList::Create方法来初始化。调用CListCtrl::SetImageList()方法来确定有效。语法如下:
CImageList* SetImageList(CImageList* pImageList, int nImageList);
pImageList:CImageList变量或者已被初始化的指针。
nImageList:使用ImageList的类型标识,它可以是如下几个值:
Value | Description |
LVSIL_NORMAL | The image list is made of large bitmap or icons, typically 32x32 |
LVSIL_SMALL | The image list is made of small bitmap or icons, typically 16x16 |
LVSIL_STATE | The image list is made of pictures that will be used as mask |
你可以使用CListCtrl::InsertItem()的几个版本来实现,向列表项关联图片:
int InsertItem( int nItem, LPCTSTR lpszItem, int nImage ); int InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam );
nImage:使用图片的索引。
nMask:和LVITEM::mask成员类似,它简单的指定你需要在项上显示的信息。
nState:和LVITEM::state成员变量相似,指定项的行为。是否能被选中,失去焦点时,以及有没有剪切粘贴操作,高亮和拖拽功能。
nStateMask:用来结合nState参数。指定精确的类型信息。
lParam:和TVITEM的lParam成员一样,用来执行指定项的操作,例如牵涉到项的排序和查找。
六、实践学习:为ListCtrl控件项关联位图
1.创建位图,在主菜单,右击工程->添加资源,在添加资源对话框内选择位图->单击新建
2.在设置属性窗口中,改变ID为IDB_SMALLIMG,设置高度为16,宽度为144.设计如下位图:
3.在增加位图,设置ID为IDB_LARGING,设置宽度为32,高度为288。设计位图如下:
4.在主对话框的头文件中声明两个CImageList变量,如下:
private:
CImageList m_SmallImg;
CImageList m_LargeImg;
};
5. 在OnInitDialog()方法中添加如下初始化代码:
m_SmallImg.Create(IDB_SMALLING, 16 , 1 , RGB( 255 , 255 , 255 )); m_LargeImg.Create(IDB_LARGING, 32 , 1 , RGB( 255 , 255 , 245 )); m_StoreItems.SetImageList( & m_SmallImg, LVSIL_SMALL); m_StoreItems.SetImageList( & m_LargeImg, LVSIL_NORMAL);
6.使用图像,改变新建的事件响应函数:
void CDeptStore2Dlg::OnBnClickedNewitem() { // TODO: 在此添加控件通知处理程序代码 CNewStoreItemDlg1 dlg; srand( (unsigned)time(NULL) ); wchar_t strNumber[ 20 ]; int number1 = rand() % 999 ; int number2 = rand() % 999 ; swprintf(strNumber, TEXT( " %d-%d " ), number1, number2); dlg.m_ItemNumber = strNumber; if ( dlg.DoModal() ) { LVITEM lvItem; int nItem; int imgNbr; if ( dlg.m_Categories == TEXT( " Babies " ) ) imgNbr = 0 ; else if ( dlg.m_Categories == TEXT( " Teens " ) ) imgNbr = 1 ; else if ( dlg.m_Categories == TEXT( " Women " ) ) imgNbr = 2 ; else if ( dlg.m_Categories == TEXT( " Men " ) ) imgNbr = 3 ; else // if( dlg.m_Category == "Miscellaneous" ) imgNbr = 4 ; lvItem.mask = LVIF_TEXT; lvItem.iItem = 0 ; lvItem.iSubItem = 0 ; lvItem.iImage = imgNbr; lvItem.pszText = strNumber; nItem = this -> m_StoreItems.InsertItem( & lvItem); this -> m_StoreItems.SetItemText(nItem, 1 , dlg.m_Categories); this -> m_StoreItems.SetItemText(nItem, 2 , dlg.m_ItemName); this -> m_StoreItems.SetItemText(nItem, 3 , dlg.m_ItemSize); this -> m_StoreItems.SetItemText(nItem, 4 , dlg.m_UnitPrice); this -> m_StoreItems.SetItemText(nItem, 5 , dlg.m_Quantity); } }
7.运行程序
<完>