与CTreeCtrl类似,MFC中以两种形式封装列表控件,一种是CListCtrl;另一种是CListView。 对于CListView,调用成员函数GetListCtrl返回一个CListCtrl的引用,就可以像CListCtrl一样进行各种操作。
CListCtrl有很多种显示方式,其中最常用的四种是(大图标)LVS_ICON 、(小图标)LVS_SMALLICON、(列表)LVS_LIST、(报告/详细信息)LVS_REPORT。可以通过调用GetWindowLong和SetWindowLong来设置其属性,从而改变其显示方式。需要注意的是,LVS_TYPEMASK属性决定了当前列表控件的风格,如果需要调用SetWindowLong函数来更改其显示方式,就必须在更改操作前清除LVS_TYPEMASK属性。否则更改将无效。
与列表控件相关的两个数据结构是LV_ITEM和LV_COLUMN。其中LV_ITEM用于定义列表控件的一个表项;而LV_COLUMN则用于定义列表控件的一个表列。它们的定义及含义如下所示:
typedef struct tagLVITEMA
{
UINT mask;//结构成员有效屏蔽位
int iItem;//列表项索引号
int iSubItem;//子列表项索引号
UINT state;//列表状态
UINT stateMask;//状态有效性屏蔽位
LPSTR pszText;//列表项名称
int cchTextMax;//列表项名称最大长度
int iImage;//列表项图标索引号
LPARAM lParam;//自定义数据
#if (_WIN32_IE >= 0x0300)
int iIndent;
#endif
#if (_WIN32_WINNT >= 0x0501)
int iGroupId;
UINT cColumns; // tile view columns
PUINT puColumns;
#endif
#if _WIN32_WINNT >= 0x0600 // Will be unused downlevel, but sizeof(LVITEMA) must be equal to sizeof(LVITEMW)
int* piColFmt;
int iGroup; // readonly. only valid for owner data.
#endif
} LVITEMA, *LPLVITEMA;
typedef struct tagLVCOLUMNA
{
UINT mask;//结构成员有效性屏蔽位
int fmt;//对齐方式
int cx;//表列宽度
LPSTR pszText;//表列名称
int cchTextMax;//表列名称长度
int iSubItem;//与表列关联的子表项索引号
#if (_WIN32_IE >= 0x0300)
int iImage;
int iOrder;
#endif
#if _WIN32_WINNT >= 0x0600
int cxMin; // min snap point
int cxDefault; // default snap point
int cxIdeal; // read only. ideal may not eqaul current width if auto sized (LVS_EX_AUTOSIZECOLUMNS) to a lesser width.
#endif
} LVCOLUMNA, *LPLVCOLUMNA;
插入一个表项使用CListCtrl::InsertItem,插入一个子表项使用CListCtrl::InsertItem;插入一个表列使用CListCtrl::InsertColumn。
1、首先创建用于表项的CImageList:
m_LargeImage.Create(32,32,ILC_COLOR8 | ILC_MASK,8,1);
m_SmallImage.Create(16,16,ILC_COLOR8 | ILC_MASK,8,1);
CImageList::Create函数初始化一个图像列表并将其附加到该CImageList对象。
ILC_COLOR8使用8位的DIB段。这与半色调色板所使用的颜色表一致。ILC_MASK使用掩码。图像列表包含两个位图,其中一个是单色位图作为掩码。如果不包含这个值,图像列表只包含一个位图。8表明图像列表最初时包含8个图像。1表示当系统重新调整列表的大小时需要为新图像腾出空间的增量。
2、为图像列表装载位图:
CBitmap cBmp;
cBmp.LoadBitmap(IDB_IMAGES_NORMAL);
LargeImage.Add(&cBmp, RGB(255,0, 255));
cBmp.DeleteObject();
cBmp.LoadBitmap(IDB_IMAGES_SMALL);
SmallImage.Add(&cBmp, RGB(255,0, 255));
cBmp.DeleteObject();
IDB_IMAGES_NORMAL和IDB_IMAGES_SMALL均是位图资源ID。CImageList::Add函数添加一个或者多个图像或图标到图像列表中。当这个函数返回时,必须
3、为列表控件分派图像列表:
m_ListCtrl.SetImageList(&LargeImage, LVSIL_NORMAL);
m_ListCtrl.SetImageList(&SmallImage, LVSIL_SMALL);
LVSIL_NORMAL标志指示使用大图标,LVSIL_SMALL使用小图标。
4、插入表列
LVCOLUMN Lvcol;
Lvcol.mask=LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH;//标识哪些字段可用
Lvcol.fmt=LVCFMT_CENTER;//对齐方式
Lvcol.pszText="文件名";//列表头标题
Lvcol.iSubItem=3;//子表项索引
Lvcol.cx=70;//表项宽度,以像素为单位
m_ListCtrl.InsertColumn(0,&Lvcol);
Lvcol.pszText="文件大小";
m_ListCtrl.InsertColumn(1,&Lvcol);
Lvcol.pszText="开始时间";
m_ListCtrl.InsertColumn(2,&Lvcol);
Lvcol.pszText="上传进度";
……
5、插入表项
LVITEM Lvitem;
CString strItem;
for(int i=0;i<8;i++)
{
Lvitem.mask=LVIF_IMAGE | LVIF_TEXT;
strItem.Format("VC界面编程技术第%d章",i+1);
Lvitem.pszText=(LPTSTR)(LPCTSTR)(strItem);
Lvitem.iItem=i;
Lvitem.iSubItem=0;
Lvitem.iImage=i;
m_ListCtrl.InsertItem(&Lvitem);
strItem.Format("%dMB",(rand()%500)+10);
Lvitem.iSubItem=1;
m_ListCtrl.SetItem(&Lvitem);
strItem.Format("%d:%d:%d",rand()%24,rand()%60,rand()%60);
Lvitem.iSubItem=2;
m_ListCtrl.SetItem(&Lvitem);
……
}
列表控件在默认情况下只能选中表项的第一个项,其他项不能被选中。如果需要设置第一项被选中时整行高亮显示,可以使用CListCtrl::SetExtendedStyle函数并传递LVS_EX_FULLROWSELECT参数;或传递LVS_EX_GRIDLINES显示网格;或传递LVS_EX_HEADERDRAGDROP允许表列被拖拽自由排序(三种情况均只对具有LVS_REPORT风格的列表控件起作用)。
示例代码如下所示:
m_ListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP);
m_LargeImage.Create(32,32,ILC_COLOR8 | ILC_MASK,8,1);
m_SmallImage.Create(16,16,ILC_COLOR8 | ILC_MASK,8,1);
CBitmap Bitmap;
Bitmap.LoadBitmapA(IDB_IMAGES_NORMAL);
m_LargeImage.Add(&Bitmap,RGB(255,0,255));
Bitmap.DeleteObject();
Bitmap.LoadBitmapA(IDB_IMAGES_SMALL);
m_SmallImage.Add(&Bitmap,RGB(255,0,255));
Bitmap.DeleteObject();
m_ListCtrl.SetImageList(&m_LargeImage,LVSIL_NORMAL);
m_ListCtrl.SetImageList(&m_SmallImage,LVSIL_SMALL);
LVCOLUMN Lvcol;
Lvcol.mask=LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH;//标识哪些字段可用
Lvcol.fmt=LVCFMT_CENTER;//对齐方式
Lvcol.pszText="文件名";//列表头标题
Lvcol.iSubItem=3;//子表项索引
Lvcol.cx=70;//表项宽度,以像素为单位
m_ListCtrl.InsertColumn(0,&Lvcol);
Lvcol.pszText="文件大小";
m_ListCtrl.InsertColumn(1,&Lvcol);
Lvcol.pszText="开始时间";
m_ListCtrl.InsertColumn(2,&Lvcol);
Lvcol.pszText="上传进度";
m_ListCtrl.InsertColumn(3,&Lvcol);
Lvcol.pszText="完成时间";
m_ListCtrl.InsertColumn(4,&Lvcol);
Lvcol.pszText="上传耗时";
m_ListCtrl.InsertColumn(5,&Lvcol);
LVITEM Lvitem;
CString strItem;
for(int i=0;i<8;i++)
{
Lvitem.mask=LVIF_IMAGE | LVIF_TEXT;
strItem.Format("VC界面编程技术第%d章",i+1);
Lvitem.pszText=(LPTSTR)(LPCTSTR)(strItem);
Lvitem.iItem=i;
Lvitem.iSubItem=0;
Lvitem.iImage=i;
m_ListCtrl.InsertItem(&Lvitem);
strItem.Format("%dMB",(rand()%500)+10);
Lvitem.iSubItem=1;
m_ListCtrl.SetItem(&Lvitem);
strItem.Format("%d:%d:%d",rand()%24,rand()%60,rand()%60);
Lvitem.iSubItem=2;
m_ListCtrl.SetItem(&Lvitem);
strItem.Format("%d%%",rand()%100);
Lvitem.iSubItem=3;
m_ListCtrl.SetItem(&Lvitem);
strItem.Format("- -");
Lvitem.iSubItem=4;
m_ListCtrl.SetItem(&Lvitem);
strItem.Format("%d分%d秒",rand()%360,rand()%60);
Lvitem.iSubItem=5;
m_ListCtrl.SetItem(&Lvitem);
6、删除表项
ClistCtrl::DeleteItem函数根据给定的索引值从列表控件中删除表项。结合GetItemState函数可以删除被选中的表项。
CListCtrl::GetItemState函数可以返回当前表项的状态。可能的取值为LVIS_CUT、LVIS_DROPHILITED、LVIS_FOCUSED、LVIS_SELECTED。当需要删除被选中的表项时,删除操作必须从后向前依次进行(如果有多项被选中的话),因为当一个表项在列表控件中被删除之后,在它后面的表项的索引号会自动减一。如果不按从后向前进行删除操作,那么就不能正常删除被选中的多个表项。下面是删除表项的示例代码:
int nItemCount=m_list.GetItemCount();
for(int i=nItemCount-1;i>=0;i--)//从后向前删除
{
int iState=m_list.GetItemState(i,LVIS_SELECTED);
if(iState!=0)
m_list.DeleteItem(i);
}
删除表项之后的重新排序并不是必须的。