老规矩,先上MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/bb774737(v=vs.85).aspx
其实还是子窗口,static那节说的很明白了,就不重复了 ,这个控件的类名是SysListView32
还是以我的博客“窗口详解”(地址:http://blog.csdn.net/zuishikonghuan/article/details/46378475)中的代码为基础,继续编写
需要包含CommCtrl.h头文件和链接comctl32.lib
listview是非常实用的控件,先看几张来自MSDN的图,饱饱眼福:
分类:listview分好几类,今天说说Report (details) View报表列表控件
报表列表控件的风格是:LVS_REPORT
一。listview常用风格(其实很多,这里只说最常用的,其他的看MSDN)
1。LVS_SINGLESEL
只能同时选择一项。默认情况下,可以选择多个项。
2。LVS_NOSORTHEADER
列标题按钮不工作。即如果单击在报表头中的列标题不进行操作。
3。LVS_SHOWSELALWAYS
如果有的话,总是显示所选内容,即使该控件没有焦点。
二。listview常用扩展风格(其实很多,这里只说最常用的,其他的看MSDN)
1。LVS_EX_FULLROWSELECT
当选定一项,则该项目及其所有子项全部突出显示(就是说选中时高亮一行)。这种风格是仅在 LVS_REPORT 样式中可用。
2。LVS_EX_SUBITEMIMAGES
允许子项显示图像。这种风格是仅在 LVS_REPORT 样式中可用。
3。LVS_EX_GRIDLINES
显示网格线。这种风格是仅在 LVS_REPORT 样式中可用。
使用扩展风格,必须用LVM_SETEXTENDEDLISTVIEWSTYLE 消息添加扩展风格,直接在CreateWindowEx里面添加是无效的。
或者用ListView_SetExtendedListViewStyle函数
参数1:句柄
参数2:扩展风格
三。控制消息:
1。LVM_INSERTCOLUMN 插入新列
wParam:新列的索引
lParam:指向包含新列的属性的 LVCOLUMN 结构的指针。
返回值:成功返回新列的索引,失败返回-1
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 #if (_WIN32_WINNT >= 0x0600) int cxMin; int cxDefault; int cxIdeal; #endif } LVCOLUMN, *LPLVCOLUMN;
mask:
LVCF_FMT:Fmt 成员是有效的。
LVCF_WIDTH:Cx 成员是有效的。
LVCF_TEXT:PszText 成员是有效的。
LVCF_SUBITEM:ISubItem 成员是有效的。
LVCF_IMAGE:4.70 版本。iImage成员是有效的。
LVCF_ORDER:4.70 版本。iOrder的成员是有效的。
LVCF_MINWIDTH:版本 6.00 和 Windows Vista.The cxMin 成员是有效。
LVCF_DEFAULTWIDTH:版本 6.00 和 Windows Vista.The cxDefault 成员是有效。
LVCF_IDEALWIDTH:版本 6.00 和 Windows Vista.The cxIdeal 成员是有效。
fmt:列标题和列中的子项文本的对齐方式。
此成员可以是下列值的组合。请注意,并非所有组合都都有效。
LVCFMT_LEFT:文本是左对齐的。
LVCFMT_RIGHT:文本为右对齐。
LVCFMT_CENTER:文本居中。
LVCFMT_JUSTIFYMASK:用于选择控制领域的理由的那些 fmt 的位掩码。若要检查某一列的格式,请使用逻辑","LCFMT_JUSTIFYMASK 结合裂变材料条约。然后可以使用 switch 语句来确定是否已设置 LVCFMT_LEFT,LVCFMT_RIGHT 或 LVCFMT_CENTER 位。
LVCFMT_IMAGE:4.70 版本。该项显示的图像列表中的图像。
LVCFMT_BITMAP_ON_RIGHT:4.70 版本。该位图显示在右侧的文本。这并不影响图像列表中的图像分配到的标头项。
LVCFMT_COL_HAS_IMAGES:4.70 版本。标头项包含图像列表中的图像。
LVCFMT_FIXED_WIDTH:版本 6.00 和 Windows Vista。不能调整大小的列;就像 HDF_FIXEDWIDTH 一样。
LVCFMT_NO_DPI_SCALE:版本 6.00 和 Windows Vista。如果不设置,CCM_DPISCALE 将治理加大固定宽度。
LVCFMT_FIXED_RATIO:版本 6.00 和 Windows Vista。与行的高度,宽度会增加。
LVCFMT_SPLITBUTTON:版本 6.00 和 Windows Vista。列是一个拆分按钮 (与 HDF_SPLITBUTTON 相同)。列的标题显示拆分按钮 (与 HDF_SPLITBUTTON 相同)。
cx:列的宽度,以像素为单位。
pszText:如果设置的列信息,则此成员是字符串的一个 null 终止的字符串指针。如果结构接收有关列的信息,该成员指定的接收列标头文本的缓冲区的地址。
cchTextMax:在 TCHARs 的 pszText 成员所指向的缓冲区的大小。如果结构不接收有关列的信息,此成员将被忽略。
iSubItem:与该列关联的子项的索引。iImage:4.70 版本。图像在图像列表内的从零开始的索引。指定的图像将出现在列。
iOrder:4.70 版本。零开始的列偏移量。列偏移是左到右的顺序。例如,0 表示最左边的列。cxMin:Windows Vista。以像素为单位的列的最小宽度。
cxDefault:Windows Vista。应用程序定义的值,通常用来存储列的默认宽度。通过该列表视图控件,此成员将被忽略。
cxIdeal:Windows Vista。只读。以像素为单位,作为列的列的理想宽度目前可能指示到较小的宽度。
2。LVM_INSERTITEM 在列表视图控件中插入一个新的项目
wParam:必须为0
lParam:指针,指向 LVITEM 结构,它指定列表视图项的属性。使用代理权成员指定的从零开始的索引,应在其中插入新的项目。如果此值大于 listview 中当前包含的项数,新项目将追加到列表的末尾,并分配正确的索引。检查消息的返回值来确定分配给物料的实际索引。
返回值:成功返回新项目的索引,失败返回-1
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; PUINT puColumns; #endif #if (_WIN32_WINNT >= 0x0600) int *piColFmt; int iGroup; #endif } LVITEM, *LPLVITEM;
mask:
LVIF_COLFMT:Windows Vista 及更高版本。PiColFmt 成员是有效的或者必须设置。如果使用此标志,则分栏成员是有效的或必须设置。
LVIF_COLUMNS:分栏成员是有效的或者必须设置。
LVIF_DI_SETITEM:操作系统应该存储请求的列表项目信息并没有再问了。此标志仅用于 LVN_GETDISPINFO 通知代码。
LVIF_GROUPID:IGroupId 成员是有效的或者必须设置。如果未设置此标志,当发送 LVM_INSERTITEM 消息,iGroupId 的值被假定为 I_GROUPIDCALLBACK。
LVIF_IMAGE:iImage成员是有效的或者必须设置。
LVIF_INDENT:IIndent 成员是有效的或者必须设置。
LVIF_NORECOMPUTE:该控件将不生成 LVN_GETDISPINFO 来检索文本信息,如果它收到一条 LVM_GETITEM 消息。相反,pszText 成员将包含 LPSTR_TEXTCALLBACK。
LVIF_PARAM:LParam 成员是有效的或者必须设置。
LVIF_STATE:state成员是有效的或必须设置。
LVIF_TEXT:PszText 成员是有效的或者必须设置。
iItem:此结构引用的项的从零开始的索引。
iSubItem:一开始的索引,这种结构所指,该子项或零如果这种结构是指一个项目,而不是一个子项。
state:指示项的状态、 状态图像和覆盖图像。StateMask 成员指示此成员的有效位。位 0 到 7 的此成员包含项目状态标志。这可以是一个或多个项目状态的值。通过此成员 11 8 位指定一个基于叠加图像索引。全尺寸的图标图像列表和小图标图像列表可以有覆盖图像。覆盖图像叠加到此项的图标图像。如果这些位均为零,该项目已经没有覆盖图像。若要隔离这些位,请使用 LVIS_OVERLAYMASK 掩码。若要在此成员设置覆盖图像索引,您应该使用 INDEXTOOVERLAYMASK 宏。用 ImageList_SetOverlayImage 函数设置图像列表覆盖图像。
通过此成员 15 12 位指定状态图像索引。状态图像显示在项目的图标来指示应用程序定义的状态旁边。如果这些位均为零,该项目已经没有国家形象。若要隔离这些位,请使用 LVIS_STATEIMAGEMASK 掩码。若要设置状态图像索引,请使用 INDEXTOSTATEIMAGEMASK 宏。状态图像索引应绘制状态图像列表中指定的图像的索引。与 LVM_SETIMAGELIST 消息指定状态图像列表。
stateMask:该值指定哪些位国家成员将检索或修改。例如,将此成员设置为 LVIS_SELECTED 将导致只状态的项目的选择要检索。
此成员允许您修改一个或多个项状态而无需首先检索所有项的状态。例如,将此成员设置为 LVIS_SELECTED 和状态为零将导致项目的选择状态被清除,但没有一个其他国家会受影响。
若要检索或修改的所有国家,请设置此成员到 (UINT)-1。
您可以使用宏 ListView_SetItemState 来设置,清除位。
pszText:如果结构指定项目属性,pszText 是一个指向以 null 结尾的字符串的指针。当响应 LVN_GETDISPINFO 通知,是确保此指针保持有效直到后下通知已收到。
如果结构接收物料属性,pszText 是指向接收项目的文本缓冲区的指针。请注意,虽然该列表视图控件允许任何长度字符串存储为项目文本,只有首先 260 TCHARs 显示。
如果 pszText 的值为 LPSTR_TEXTCALLBACK,该项目是一个回调项。如果回调文本发生更改,您必须显式将 pszText 设置为 LPSTR_TEXTCALLBACK 并通过发送 LVM_SETITEM 或 LVM_SETITEMTEXT 的消息通知列表视图控件的更改。
不要设置 pszText LPSTR_TEXTCALLBACK 如果列表视图控件具有的 LVS_SORTASCENDING 或 LVS_SORTDESCENDING 的风格。
cchTextMax:TCHARs 中 pszText,包括终止 NULL 所指向的缓冲区数。
当结构接收项目属性时,只使用此成员。当结构指定项目属性时,它将被忽略。例如,cchTextMax 在 LVM_SETITEM 和 LVM_INSERTITEM 的过程中将被忽略。它在只读 LVN_GETDISPINFO 和其他 LVN_ 通知。永远不会注意复制超过 cchTextMax TCHARs — — 凡 cchTextMax 包括终止 NULL — — 成 pszText LVN_ 通知期间,否则您的程序可能会失败。
iImage:该项目的图标控件的图像列表中的索引。这适用于大型和小型的图像列表中。如果此成员是 I_IMAGECALLBACK 值,父窗口是负责存储索引。在这种情况下,列表视图控件发送父 LVN_GETDISPINFO 通知代码,需要时,它显示的图像检索的索引。
lParam:特定于项目的价值。如果你使用 LVM_SORTITEMS 消息,列表视图控件将此值传递到应用程序定义的比较函数。您还可以使用 LVM_FINDITEM 消息来搜索具有指定需要 lParam 的值的项的列表视图控件。
iIndent:4.70 版本。以图像宽度计算,要缩进的项目数。一个单一的压痕等于项目图像的宽度。因此,值 1 通过一个图像,由两个图像,等等值 2 缩进的宽度缩进的项目。请注意,此字段仅为项目支持。尝试设置子项缩进会导致调用函数失败。
iGroupId:版本 6.0 标识符的组,该项目属于,或为下列值之一。
I_GROUPIDCALLBACK:Listview 控件发送父 LVN_GETDISPINFO 通知代码以检索组的索引。
I_GROUPIDNONE:该项目不属于组。
cColumns:版本 6.0 的数据列 (子项) 为此项平铺视图中显示的数目。最大值为 20。如果此值为 I_COLUMNSCALLBACK,列阵列和阵列本身 (puColumns) 的大小被通过发送一个 LVN_GETDISPINFO 通知。
puColumns:版本 6.0 为这一项目和这些列的顺序显示指定的列的列索引数组的指针。
piColFmt:Windows Vista: 不执行。Windows 7 和以后: 指向数组的以下标志 (单独或组合),指定在每个子项的格式扩展平铺视图。
LVCFMT_LINE_BREAK:部队要换到顶部的下一列的列表中的列。
LVCFMT_FILL:填充图块区域的其余部分。可能有一个标题。
LVCFMT_WRAP:允许在其列表中的列的剩余空间内换行的列。
LVCFMT_NO_TITLE:从子项中删除标题。
LVCFMT_TILE_PLACEMENTMASK:相当于 LVCFMT_LINE_BREAK 和 LVCFMT_FILL 的组合。
iGroup:Windows Vista: 组的项的索引。仅对所有者数据/回调 (多个组中的单个项) 有效。
3.LVM_SETITEM 设置设置子项的文本。
wParam:必须为0
lParam:指向包含新的项目属性的 LVITEM 结构的指针。如果掩码成员指定的 LVIF_TEXT 值,pszText 成员是以 null 结尾的字符串的地址,cchTextMax 成员将被忽略。
返回值:成功TRUE,失败FALSE
4。LVM_DELETEITEM 移除一项
wParam:要删除项的序号
lParam:必须为0
返回值:成功TRUE,失败FALSE
5。LVM_DELETECOLUMN 移除列
wParam:要删除列的序号
lParam:必须为0
返回值:成功TRUE,失败FALSE
6。LVM_GETITEMCOUNT 获取项目数
wParam:必须为0
lParam:必须为0
返回值:返回项目的数量
7。LVM_GETITEM 获取指定项
wParam:必须为0
lParam:指向 LVITEM 结构的指针
返回值:成功返回TRUE,失败返回FALSE
注:关于获取指定项文本:
在 LVITEM 结构中的掩码成员设置 LVIF_TEXT 标志,iItem和iSubItem指定项目序号和子项。pszText 成员必须指向一个有效的缓冲区;cchTextMax 成员必须设置为该缓冲区中的字符数。应用程序不应假设文本一定将放置在指定的缓冲区。结果是可能改变结构中的 pszText 成员,以指向新的文本,而不是将它放在缓冲区中。
8。LVM_GETCOLUMN 获取指定列
wParam:列的序号
lParam:指向 LVCOLUMN 结构的指针
返回值:成功返回TRUE,失败返回FALSE
9。LVM_GETHOTITEM 获取当前选中项
wParam:必须为0
lParam:必须为0
返回值:返回选中项的序号
10。颜色:
文字颜色:获取:LVM_GETTEXTCOLOR 设置:LVM_SETTEXTCOLOR
文字背景色:获取:LVM_GETTEXTBKCOLOR 设置:LVM_SETTEXTBKCOLOR
背景色:获取:LVM_GETBKCOLOR 设置:LVM_SETBKCOLOR
获取颜色的三个消息 wParam和 lParam 都必须为0,返回值都是颜色
设置颜色的三个消息 wParam 都必须为0,为颜色(RGB颜色),其中设置背景颜色的那两个消息颜色可以为 CLR_NONE,表示没有颜色。
四。通知消息:
1。NM_CLICK 项目被单击
通过 WM_NOTIFY 发送给父窗口
wParam:控件标识符
lParam:指向 NMHDR 结构的指针,从4.71版本开始,是指向NMITEMACTIVATE 结构的指针
返回值:不使用
typedef struct tagNMITEMACTIVATE { NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; UINT uKeyFlags; } NMITEMACTIVATE, *LPNMITEMACTIVATE;
hdr:指向 NMHDR 结构的指针
iItem:项目的序号,如果没有使用则为-1
typedef struct tagNMHDR { HWND hwndFrom; UINT_PTR idFrom; UINT code; } NMHDR;hwndFrom:控件句柄
2。NM_DBLCLK 项目被双击
同上
3。NM_RCLICK 项目被右击
wParam和 lParam同上
返回值:非0表示不允许默认处理,0表示允许.
五。图片列表:
ImageList_Create 创建一个图片列表
HIMAGELIST ImageList_Create(
int cx,
int cy,
UINT flags,
int cInitial,
int cGrow
);
cx:宽度
cy:高度
flags:置ILC_MASK
cInitial:图像列表最初包含的映像数目。
cGrow:图像的图像列表可以增长时,系统需要腾出新的图像数。此参数表示新的图像调整大小后的图像列表可以包含的数。
ImageList_Add添加位图
ImageList_AddIcon添加图标
ListView_SetImageList为listview设置图片列表
HWND listview1; LVCOLUMN list1; LVITEM item1; HIMAGELIST imglist1;代码:
LRESULT CALLBACK WndProc2(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg){ case WM_CREATE: //创建listview listview1 = CreateWindowEx(WS_EX_STATICEDGE, TEXT("SysListView32"), NULL, WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL, 10, 10, 400, 400, hwnd, (HMENU)1, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL); ListView_SetExtendedListViewStyle(listview1, LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES);//设置listview扩展风格 SendMessage(listview1, WM_SETFONT, (WPARAM)GetStockObject(17), 0); //SetWindowTheme(listview1, L"Explorer", NULL); //创建图片列表 imglist1 = ImageList_Create(20, 20, ILC_MASK, 1, 1); ImageList_AddIcon(imglist1, LoadIcon((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), TEXT("ICON_2"))); ImageList_AddIcon(imglist1, LoadIcon((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), TEXT("ICON_1"))); ListView_SetImageList(listview1, imglist1, LVSIL_SMALL); //内存清零 RtlZeroMemory(&list1, sizeof(LVCOLUMN)); RtlZeroMemory(&item1, sizeof(LVITEM)); //创建列 list1.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;//掩码 list1.fmt = LVCFMT_LEFT;//左对齐 list1.cx = 100;//列宽 list1.pszText = TEXT("醉时空欢"); SendMessage(listview1, LVM_INSERTCOLUMN, 0, (LPARAM)&list1);//创建列 list1.pszText = TEXT("Win32"); list1.cx = 200; SendMessage(listview1, LVM_INSERTCOLUMN, 1, (LPARAM)&list1); list1.pszText = TEXT("MSDN"); SendMessage(listview1, LVM_INSERTCOLUMN, 2, (LPARAM)&list1); list1.pszText = TEXT("happy"); SendMessage(listview1, LVM_INSERTCOLUMN, 3, (LPARAM)&list1); //创建项目 item1.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_INDENT; item1.pszText = TEXT("项目"); item1.iItem = 0;//项目号 item1.iImage = 0;//图片号 item1.iIndent = 0; SendMessage(listview1, LVM_INSERTITEM, 0, (LPARAM)&item1); item1.iItem = 1; item1.iImage = 0; SendMessage(listview1, LVM_INSERTITEM, 0, (LPARAM)&item1); item1.pszText = TEXT("3"); item1.iItem = 2; item1.iImage = 1; item1.iIndent = 1;//缩进一个图像单位 SendMessage(listview1, LVM_INSERTITEM, 0, (LPARAM)&item1); //创建子项 item1.mask = LVIF_TEXT | LVIF_IMAGE; item1.iItem = 1; item1.iSubItem = 1; item1.iImage = -1; item1.pszText = TEXT("子项"); SendMessage(listview1, LVM_SETITEM, 0, (LPARAM)&item1); item1.iItem = 1; item1.iSubItem = 2; item1.pszText = TEXT("子项"); SendMessage(listview1, LVM_SETITEM, 0, (LPARAM)&item1); item1.iItem = 1; item1.iSubItem = 3; item1.pszText = TEXT("子项"); SendMessage(listview1, LVM_SETITEM, 0, (LPARAM)&item1); break; case WM_NOTIFY: switch (wParam){ case 1://ID为listview的ID LPNMITEMACTIVATE now; now = (LPNMITEMACTIVATE)lParam;//得到NMITEMACTIVATE结构指针 char a[50]; _itoa(now->iItem, a, 10);//now->iItem项目序号 switch (now->hdr.code){//判断通知码 case NM_CLICK: //MessageBoxA(hwnd, a, "单击", 0); break; case NM_DBLCLK: //MessageBoxA(hwnd, a, "双击", 0); break; case NM_RCLICK: //MessageBoxA(hwnd, a, "右击", 0); break; } break; } break; case WM_DESTROY: ImageList_Destroy(imglist1);//销毁图片列表 PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
效果图:
选中一项时:
将上面代码中的SetWindowTheme(listview1, L"Explorer", NULL);取消注释之后再运行:
有个虚线碍眼,挺难看的,其实这个问题困扰了我好长时间,MSDN和百度上也没有找到解决方法,用ControlSpy和Spy++倒腾了半天也没有结果,但经过我的不懈努力,终于研究出来了两个方法:
方法1.使用对话框,在对话框里创建的listview就没有虚线框
方法2.在NM_CLICK通知里面使listview失去焦点,在NM_CLICK里面加入:
SendMessage(now->hdr.hwndFrom, WM_KILLFOCUS, 0, 0);
不过这种方法可能会有一些隐患,目前尚不明确,不能加上LVS_SHOWSELALWAYS风格。
效果: