关于图像列表

图像列表是大小相同的图像集合,其中的每个图像都可以通过其索引进行引用。 图像列表用于有效地管理大的图标或位图集。 图像列表中的所有图像包含在一个采用屏幕设备格式的宽位图中。 图像列表还可以包含单色位图,其中包含了用于透明绘制图像(图标样式)的掩模。

Microsoft Win32 API 提供图像列表函数和宏,可用于创建和销毁图像列表、添加和删除图像、替换和合并图像、绘制图像以及拖动图像。 要使用图像列表功能,请在源代码文件中包含通用控件头文件,并链接到通用控件导出库。 此外,在调用任何图像列表函数之前,请使用 InitCommonControlsInitCommonControlsEx 函数来确保已加载常用控件 DLL。

以下是本节中要讨论的主题:

类型

图像列表有两种类型:无掩模和掩模。 无掩模图像列表由包含一个或多个图像的颜色位图组成。 掩模图像列表由两个大小相等的位图组成。 第一个是包含图像的颜色位图,第二个是包含一系列掩模的单色位图,第一个位图中的每个图像对应第二个位图的一个掩模。

绘制非掩模图像时,只需将其复制到目标设备上下文中;也就是说,在设备上下文的现有背景色上绘制非掩模图像。 绘制掩模图像时,图像的位与掩模的位组合,通常会在位图中产生透明区域,目标设备上下文的背景颜色可以透过这些区域显示出来。 在绘制掩模图像时,可以指定几种绘制样式。 例如,可以指定抖动图像以指示选定对象。

创建和销毁图像列表

通过调用 ImageList_Create 函数创建图像列表。 参数包括要创建的图像列表的类型、每个图像的尺寸以及要添加到列表中的图像数量。 对于无掩模图像列表,该函数会创建足够大的单个位图,可以容纳指定数量、指定尺寸的图像。 然后,它会创建屏幕兼容的设备上下文,并选择要加入其中的位图。 对于掩模图像列表,该函数会创建两个位图和两个屏幕兼容的设备上下文。 它会选择要加入设备上下文中的图像位图,以及要加入另一个设备上下文中的掩模位图。 通用控制 DLL 包含图像列表功能的可执行代码。

ImageList_Create 中,可以指定图像列表中的初始图像数以及列表可增长的图像数。 因此,如果尝试添加的图像超过最初指定的数量,则图像列表会自动增长以容纳新的图像。

如果 ImageList_Create 成功,它将返回 HIMAGELIST 类型的句柄。 可以在其他图像列表功能中使用此句柄来访问图像列表和管理图像。 可以添加和删除图像,将图像从一个图像列表复制到另一个图像列表,以及合并两个不同图像列表中的图像。 如果不再需要图像列表,可以通过在调用 ImageList_Destroy 函数时指定其句柄来将其销毁。

添加和删除图像

可以在图像列表中添加位图图像、图标或光标。 可以通过调用 ImageList_Add 函数来指定两个位图的句柄,从而添加位图图像。 第一个位图包含一个或多个要添加到图像位图中的图像,而第二个位图包含要添加到掩模位图中的掩模。 对于无掩模图像列表,第二个位图句柄会被忽略;可以将其设置为 NULL

ImageList_AddMasked 函数还可将位图图像添加到掩模图像列表中。 此函数与 ImageList_Add 类似,只是未指定掩模位图。 反,可以指定一种颜色,由系统结合图像位图自动生成掩模。 图像位图中指定颜色的每个像素都会变为黑色,而掩模中的相应位也会被设置为 1。 因此,在绘制图像时,图像中任何与指定颜色匹配的像素都是透明的。

ImageList_AddIcon 宏会向图像列表添加图标或光标。 如果是掩模图像列表,ImageList_AddIcon 会将图标或光标提供的掩模添加到掩模位图中。 如果是非掩模图像列表,则绘制图像时不会使用图标或光标的掩模。

可以使用 ImageList_GetIcon 函数,根据图像列表中的图像和掩模来创建图标。 函数将句柄返回至新图标。

ImageList_AddImageList_AddMaskedImageList_AddIcon 将为添加到图像列表的每个图像分配一个索引。 索引从 0 开始,即列表中第一个图像的索引为 0,下一个图像的索引为 1,以此类推。 添加单个图像后,函数将返回图像的索引。 如果一次添加多个图像,函数会返回第一个图像的索引。

ImageList_Remove 函数可从图像列表中删除图像。

替换和合并图像

ImageList_ReplaceImageList_ReplaceIcon 函数会用新图像替换图像列表中的图像。 ImageList_Replace 会用位图图像和掩模来替换图像,而 ImageList_ReplaceIcon 会用图标或光标来替换图像。

ImageList_Merge 函数会合并两个图像,并将新图像存储在新的图像列表中。 通过在第一个图像上透明地绘制第二个图像来创建新图像。 新图像的掩模是对两个现有图像的掩模的位执行逻辑 OR 运算的结果。

绘制图像

要绘制图像,请使用 ImageList_DrawImageList_DrawEx 函数。 可以指定图像列表的句柄、要绘制的图像的索引、目标设备上下文的句柄、设备上下文中的位置以及一个或多个绘制样式。

在指定 ILD_TRANSPARENT 样式时,ImageList_DrawImageList_DrawEx 会使用两个步骤来绘制掩模图像。 首先,它对图像的位和掩模的位执行逻辑 AND 操作。 然后对第一次操作的结果和目标设备上下文的背景的位执行逻辑 XOR 操作。 此过程会在结果图像中创建透明区域;即蒙板中的每个白色位会使结果图像中相应的位变为透明。

在纯色背景上绘制掩模图像之前,应使用 ImageList_SetBkColor 函数将图像列表的背景颜色设置为与目标相同的颜色。 在设置颜色后,无需在图像中创建透明区域,ImageList_DrawImageList_DrawEx 就能直接将图像复制到目标设备上下文,从而显著提高性能。 要绘制图像,请在调用 ImageList_DrawImageList_DrawEx 时指定 ILD_NORMAL 样式。

可以随时设置掩模图像列表的背景颜色,以便在任何纯色背景上正确绘制。 默认情况下,将背景色设置为 CLR_NONE 会将图像绘制成透明的。 要检索图像列表的背景颜色,请使用 ImageList_GetBkColor 函数。

ILD_BLEND25 和 ILD_BLEND50 样式使用系统高亮色为图像递色。 如果您使用一个添加了蒙板的图像来表示一个用户可以选择的对象,那么这些样式会非常有用。 例如,当用户选择某个图像时,可使用 ILD_BLEND50 样式来绘制它。

使用 SRCCOPY 光栅操作可将非掩模图像复制到目标设备上下文。 不论设备上下文的背景色是什么,图像中的颜色都相同。 ImageList_DrawImageList_DrawEx 中指定的绘制样式对非掩模图像的外观也没有影响。

拖动图像

Win32 API 包含用于在屏幕上拖动图像的函数。 拖动函数可以流畅地拖动图像,光标没有任何闪烁。 添加了蒙板的图像和未添加蒙板的图像均可拖动。

ImageList_BeginDrag 函数可开始拖动操作。 这些参数包括图像列表的句柄、要拖动图像的索引以及图像中热点的位置。 作用点是拖动函数识别为图像的确切屏幕位置的单一像素。 通常,应用程序将设置作用点,以便它与鼠标光标的作用点一致。 ImageList_DragMove 函数将图像移动到新位置。

ImageList_DragEnter 函数可设置拖动图像在窗口中的初始位置,并在该位置绘制图像。 这些参数包括要在其中绘制图像的窗口的句柄,以及窗口中的初始位置的标。 坐标相对于窗口的左上角,而不是工作区。 上述情况同样适用于将坐标作为参数使用的所有图像拖动函数。 这意味着您在指定坐标时必须补偿窗口元素的宽度,如边框、标题栏和菜单栏。 如果在调用 ImageList_DragEnter 时指定了 NULL 窗口句柄,则拖动函数将在与桌面窗口关联的设备上下文中绘制图像,并且坐标相对于屏幕左上角。

ImageList_SetDragCursorImage 函数将给定图像(通常是鼠标指针图像)与当前拖动图像相结合,从而创建新的拖动图像。 由于拖动函数会在拖动操作期间使用新图像,因此在调用 ImageList_SetDragCursorImage 之后,应使用 ShowCursor 函数来隐藏实际的鼠标光标。 否则,系统在拖动操作期间可能看起来具有两个鼠标光标。

当应用程序调用 ImageList_BeginDrag 时,系统会创建一个临时的内部图像列表,然后将指定的拖动图像复制到内部列表中。 可以使用 ImageList_GetDragImage 函数来检索临时拖动图像列表的句柄。 此函数还将检索当前拖动位置和拖动图像相对于拖动位置的偏移量。

图像信息

有许多函数都可以从图像列表中检索信息。 ImageList_GetImageInfo 函数可为 IMAGEINFO 结构填充单个图像的信息,包括图像和掩模位图的句柄、每个像素的颜色平面和位数,以及图像位图中图像的边界矩形。 您可使用此信息直接操作图像的位图。 ImageList_GetImageCount 函数可检索图像列表中的图像数。

图像覆盖

每个图像列表都包含一个用作覆盖的索引列表。 覆盖是指在另一个图像上透明绘制的图像。 当前图像列表中的任何图像都可用作覆盖。 每个图像列表最多可指定四个覆盖。 在 4.71 版中,这一限制已增大为 15 个。

可以使用 ImageList_SetOverlayImage 函数来指定图像列表的句柄、现有图像的索引和所需的覆盖索引,从而将图像索引添加到覆盖列表中。 这实际上是告诉图像列表“索引 x 处的图像可用作覆盖,我希望把覆盖索引称为 y”。覆盖索引是从 1 而不是从 0 开始,因为覆盖索引为 0 意味着不使用覆盖。

使用 ImageList_DrawImageList_DrawEx 函数绘制图像时可以指定覆盖。 覆盖可通过在所需的绘图标志和 INDEXTOOVERLAYMASK 宏的结果之间执行逻辑 OR 操作来指定。 INDEXTOOVERLAYMASK 宏采用覆盖索引并将其格式化,以便包含这些函数的标志。 这样将以指定的覆盖来绘制图像。 以下示例演示了在绘制图像时如何添加和指定覆盖。

ImageList_SetOverlayImage(himl, 0, 3);
ImageList_Draw(himl, 1, hdc, 0, 0, ILD_MASK | INDEXTOOVERLAYMASK(3));

这样会绘制图像 1,然后用图像 0 覆盖图像 1。 由于 3 是在 ImageList_SetOverlayImage 调用中指定的覆盖索引,因此 3 被置于 INDEXTOOVERLAYMASK 宏中。

32 位抗锯齿图标

抗锯齿是一种柔化或模糊锐利边缘的技术。 这会让图像看起来更加自然。 Windows Vista 和 Windows 7 中的图像列表支持使用 32 位抗锯齿图标和位图。 颜色值使用 24 位,而 8 位用作图标的 Alpha 通道。 要创建可处理每像素 32 位 (bpp) 图像的图像列表,请调用 ImageList_Create 函数,并传入 ILC_COLOR32 标志。

要正确创作 32 位图标,必须为每个图标创建多个图像,如下图所示。

illustration showing three sizes of icons for each of three color depths

  • 前三个图像为 16 色模式,可在安全模式下使用。
  • 接下来的三个图标可在 256 色模式下使用。
  • 最后三个图标具有 alpha 通道,只能在运行 24 位或更高色彩的操作系统中使用。
  • 图标格式中图像的顺序很重要。 如果顺序不正确,旧版本的 Windows 在提取图标时就会出现问题。 错误提取图标可能会导致内存损坏和呈现问题。
  • 以前版本的 Windows 有 10 个图标的资源限制。

注意

可以使用第三方工具生成包含 alpha 通道的图标文件和位图。 如果使用 LoadImage 加载包含 alpha 的 32 bpp 位图,则需要指定 LR_CREATEDIBSECTION 标志。