Delphi 中TImageCollection和TVirtualImageList 控件实现high-DPI

一、概述

RAD Studio允许你通过使用TImageCollection组件和TVirtualImageList组件,在你的Windows VCL应用程序中包含缩放、高DPI、多分辨率的图像。

这两个组件位于Windows 10面板中:

注意:
如果你使用FireMonkey进行跨平台应用,请看TImageList组件和FireMonkey指南,将TImageLists作为中央图像库使用。

这些成对的组件将图像集合的概念(每个逻辑图像可以有多个分辨率)与用于控件的单一特定尺寸的图像列表分开。简而言之,将多个分辨率的图像加载到一个图像集合中。图像列表持有一组来自图像集合的图像,并以特定的尺寸(例如,16x16)展示它们。图像被平滑地调整大小和缩放,图像列表的实际展示分辨率可以根据DPI改变。它与传统的图像列表完全兼容,并且可以直接替换,包括提供一个HIMAGELIST句柄,并且可以被VCL控件和任何使用Windows API图像列表调用的代码所使用。

图像支持alpha通道,你可以将PNG加载到图像集合中。你也可以加载旧式的彩色键控透明位图

二、使用图像收集组件(TImageCollection

TImageCollection允许你使用TWICImage类来存储、缩放和绘制本地格式的图像。TImageCollection集合中的每个图像可以有许多不同尺寸的版本。该组件选择最佳尺寸进行缩放,或者在可用尺寸等于所需尺寸的情况下使用一个图像。它还可以创建一个带有alpha通道的32位TBitmap缩放版本,可以直接添加到TCustomImageList中。

TImageCollection继承自TCustomImageCollection类(Vcl.BaseImageCollection单元),它定义了一个集合的基本方法。

三、图像收集组件编辑器

要打开图像集合编辑器,在你的窗体或数据模块上放置一个TImageCollection,然后双击窗体中的组件或右击它并从上下文菜单中选择Show collection editor...选项。你也可以在对象检查器中双击TImageCollection.Images属性。

图像集合编辑器窗口允许你将图像添加到组件中,并将它们组织成不同目录

注意:
图像收集编辑器要求在文件名的数字中使用分隔符,以便能够识别同一图像的不同尺寸。

单击 "Add...",显示 "打开 "对话框,并浏览到存储图像的文件夹。你可以一次添加一张图片,也可以从一个文件夹中选择多张图片并同时添加。图像集合编辑器按字母顺序显示图像。

选择 "Size in file name"复选框,在添加图像时,在文件名中搜索图像尺寸信息(尺寸)。你也可以从下拉选项中选择一个图像尺寸分隔符。这将自动识别同一图像的多个分辨率,其文件名相似,但像素大小不同,并将它们作为一个图像的多个分辨率添加到集合中。

图像大小分隔符设置控制它如何解析图像大小,并包含常用图标和图像大小文件名惯例的选项。

提示:
使用右上方的 "Add... "按钮,为一个图像或集合添加多个来源。当为集合添加各种来源时,确保来源文件的名称与你添加到集合中的第一组图像相同。
要为一个特定的图像添加源,从集合中选择图像,然后点击窗口底部的"Add...",显示打开对话框并找到图像文件。

分类目前只用于组织。(在VCL控件中,图像仍然只能通过索引来参考)。

要在一个类别中组织图像,选择图像并点击 Set Category...。

使用顶部的删除按钮从集合中删除特定的图像,使用清除按钮删除集合中的所有图像

注意。
当你从集合中删除一个图像时,VirtualImageList会按索引查找图像。

在你添加图像到集合中后,你可以选择任何可用的图像并执行以下操作。

  1. 修改图像名称。

  1. 为图像指定一个自定义的描述。

  1. 指定一个索引值,以修改集合内图像的顺序。

  1. 为同一图像添加其他来源。

  1. 删除图像的一个来源。

  1. 替换一个现有的图像源。

注意。
当你重命名和替换一个图像时,请遵循这些步骤。
1. 改变index[name]并应用变化(VirtualImageList通过index[name]使用集合中的name[index]更新图像)。
2. 改变name[index]并应用变化(VirtualImageList使用集合中的index[name]按name[index]更新图像)。
  1. 用不同的名称保存图像(Save as...)。

提示:
你也可以点击并拖动一个图像到不同的位置来修改其索引值。
四、将现有的TImageList加载到TImageCollection

为了协助将旧式图像列表转换为新系统,您可以从旧的TImageList-s加载图像到TImageCollection。当您在不同的TImageList-s中拥有同一图像的多种尺寸时,您可以一次加载这两种图像;图像被合并,以便图像集合包含同一图像的多种分辨率。

为了能够将图像从TImageList加载到TImageCollection中,你需要将这两个组件放在同一Form中。

按照下面的步骤,从表单上现有的TImageList加载图像到TImageCollection

  1. 右击表格中的TImageCollection组件,从上下文菜单中选择从现有的TImageList中加载... 选项。

  1. 选择你想加载的TImageList并为图像指定一个类别。你可以选择一个以上的TImageList。这对加载同一图像的多个分辨率特别有用,这些图像以前存储在多个图像列表中。

  1. 单击 "Load in order",以便按照图像列表的相同顺序加载图像。

  1. 单击 "Load & merge "以合并来自不同图像列表的不同图像源。合并加载时,图像列表必须有相同数量的图像文件和不同的图像尺寸。

  1. 单击 "View Collection... "以验证图像在TImageCollection中是如何被导入的,而不必关闭对话框。

  1. 单击 "OK "以应用设置并关闭对话框。

  1. 单击 "Apply "以应用一组特定的更改并继续配置设置。

  1. 单击 "Cancel "关闭对话框,放弃对图像集的所有更改。

注意。
如果你看到从传统的TImageList导入到TImageCollection或TVirtualImageList后,图像不能正确呈现,比如有白边或其他伪影,请检查TImageList的ColorDepth属性。有时,FMX TImageList可能被设置为cd32Bit,而它所持有的图像实际上是24位或16位。如果ImageList持有的位图是真正的32位,包括一个alpha通道,请确保ImageList的颜色深度被设置为cd32Bit。
五、使用虚拟图像列表组件(TVirtualImageList

TVirtualImageList允许你生成一个图像列表并同时对所有的图像进行修改。

TVirtualImageList使用TCustomImageCollection(TImageCollection)来生成一个内部图像的动态列表。

通过TVirtualImageList,你可以设置自定义的宽度和高度属性,该组件会自动缩放所有的图像。当DPI发生变化时,它将缩放图像以在高DPI显示器上正确显示。

注意:
当它们被缩放时,TVirtualImageList自动继承其所有者(TCustomForm或TCustomFrame)的DPI。
VCL控件可以使用TVirtualImageList而无需修改,因为它是继承自TCustomImageList。
注意:
要在TVirtualImageList中添加、插入和/或替换位图,你必须使用方法来添加、插入和/或替换ImageCollection中的项目。
六、虚拟图像列表组件编辑

为了能够使用虚拟图像列表组件和组件编辑器,你需要先在对象检查器中设置ImageCollection属性。

要打开虚拟图像列表编辑器,你可以双击表单中的组件,或者右击它并从上下文菜单中选择 Show image list editor...选项。

如果你把 Autofill 属性设置为 "True",虚拟图像列表将自动填充集合中的所有图像。否则,你可以通过使用图像列表编辑器,从集合中手动添加图像到列表中。

虚拟图像列表编辑器窗口允许您将图像添加到组件中,包括图像的禁用版本,并将它们组织成类别。

点击 "Add...",打开相关的图像集,选择你想包括在虚拟图像列表中的图像。你可以从图像集合中选择特定的图像,或者从集合或现有类别中选择所有的图像。

此外,虚拟图像列表编辑器窗口有以下选项。

Add Disabled: 允许你创建和添加你选择的图像的低不透明度或灰度版本。禁用图像的外观由图像列表的DisabledGrayscaleDisabledOpacity属性控制。

Add Disabled Copy: 允许你从相关的图像集合中添加图像,并同时创建和添加你选择的图像的禁用版本。

Replace: 允许你替换一个选定的图像。

注意。
你只能用一个不在你以前添加的图像列表中的图像来替换虚拟图像列表组件中的图像。

Set Category: 允许你将图像归入类别。要创建一个类别,选择你想包括在一个类别中的图像,然后点击Set Category...,输入类别的名称,并点击 OK,在类别列表中显示。组件编辑器会将类别名称添加到图像名称中。

Disabled All : 将你之前添加的图片转换为禁用的图片。

在你添加图像到虚拟图像列表组件后,你可以执行以下操作。

Reload: 从ImageCollection中重新加载图像名称和描述。

Delete: 从虚拟图像列表组件中删除选定的图像或图像。

Clear: 移除集合中的所有图像。

Name: 修改图像名称。

Description: 为图像指定一个自定义的描述。

七、在多分辨率下使用图像组件

TVirtualImage组件支持多种分辨率的TImage-like组件。图像的来源来自一个ImageCollection,根据屏幕的DPI,可以有多种分辨率。该组件根据所显示的显示器使用适当的版本。

TVirtualImage组件的一些配置设置和关键属性是。ImageCollection, ImageHeight, ImageIndex, ImageName, and ImageWidth

当你使用位图缩放逻辑来实现任何VCL TGraphic在缩放时的平滑绘制(例如StretchDraw),有一个TScaledGraphicDrawer类来为不同的TGraphic类实现HQ缩放绘制,其调用方式如下。

MyBitmap.EnableScaler(TD2DGraphicScaler);
Image1.Picture.Graphic.EnableScaler(TWICGraphicScaler);

不同的解决方案提供了更好或更差的渲染以及更慢或更快的性能组合。你可以编写自定义的TScaledGraphicDrawer衍生类,定义额外的缩放算法。

八、最佳实践

TVirtualImageList组件会随着它们所处的表单的DPI而缩放。这使得表单上的控件与图像列表一起绘制时,总是以正确的比例分辨率绘制。然而,这意味着两件事。

  1. 控件应该总是引用同一表单上的图像列表。如果一个控件引用了不同窗体上的图像列表,那么当两个窗体有不同的DPI时,例如在不同的屏幕上,图像可能会画得不正确。

  1. 一个TVirtualImageList应该总是放在表单上,而不是数据模块上。表单有一个相关的显示器和DPI;数据模块没有。TImageCollection可以放在任何地方,因为它们只是源,并且不受DPI变化的影响:它们是源,而TVirtualImageList虚拟图像列表是呈现。

因此,如果表单上的控件使用了一个图像列表,总是在该表单上放置一个或多个TVirtualImageLists,并让控件只引用这些本地的、同表单的图像列表。这些TVirtualImageLists可以全部引用同一个TImageCollection

虚拟图像集合是一个非常有用的控件,它将图像集合(TImageCollection)的概念与特定尺寸的图像集(TVirtualImageList)区分开来,尽管该尺寸会随DPI的变化而变化。一个图像集合不会受到DPI变化的影响,因为它只是一个容器。虚拟图像列表可以从另一个表单或数据模块的集合中引用图像。好的设计是在你的应用程序的主窗体或甚至更好的共享数据模块上为相关的图像--例如,所有的工具栏和菜单图像--有一个单一的图像集合。其他窗体将有他们自己的虚拟图像列表,具体到每个窗体,这些图像列表使用中央图像集合。

  1. 多个尺寸

如果你需要同一图像的多种尺寸,例如TListViewSmallImagesLargeImages属性,请使用两个TVirtualImageLists,就像你使用传统的TImageLists那样。这两个虚拟图像列表都引用了同一个图像集合。

  1. 在你的应用程序中支持高DPI:转换旧的TImageLists

将VCL应用程序从使用TImageLists转换为TVirtualImageLists是很常见的,这样可以升级视觉质量,也可以帮助支持高DPI。

TVirtualImageList继承自TCustomImageList的,所以在代码层面上可以直接替换,同时还提供了一个HIMAGELIST Handle属性来直接调用Windows API方法。

有两种建议的方法来转换你的应用程序以使用新的高DPI图像列表。

  1. 首先,你可能同时也在升级你的图标,从旧的风格到更现代的风格,或者从彩色透明到带有alpha通道的32位图像。如果你这样做,你可能会发现最简单的做法是把这些添加到一个新的图像集合中,创建新的图像列表,并改变你的组件以指向新的图像列表。

  1. 第二,你可能想一步一步地升级,逐步替换旧的图像,甚至根本不替换(尽管我们确实建议利用新系统中的32bpp alpha通道支持)。要这样做,放置一个TImageCollection,然后右击并选择从现有的TImageList(s)加载。选择图像列表,并选择添加图像,或合并图像,如果它们包含多个分辨率的相同图像。请看四、将现有的TImageList加载到TImageCollection,将现有的TImageList加载到TImageCollection中,以获得完整的信息。

这将导致您的图像集合包含您的旧图像。尽管使用旧的图像,你不会看到图形质量或透明度的提高,就像你使用新设计的图像一样,但这确实允许你让图像随每个表格的DPI缩放。在每个表单上创建新的TVirtualImageList组件,并从集合中添加图像:它们将保持相同的相对顺序,所以相同的索引,除非集合中已经有图像。然后,改变你的组件以使用新的TVirtualImageLists

  1. 在TCanvas上绘图时,可平滑缩放

TCanvas.StretchDraw允许将TGraphic绘制到一个任意的矩形中。虽然TGraphic子类的实现决定了如何做到这一点,但在实践中,VCL绘图(如TBitmap)通常通过GDI使用近邻重采样,通常不会产生理想的缩放或拉伸的图像质量。

你可以使用TImageCollection来保存图像(内部存储为并使用WIC绘制),并将其绘制到一个任意的矩形。这样做将使用高质量的重采样。

  1. TImageCollection中图像导入到TImage

假定TImageCollection1 中存在索引号为3的一个图像,需要将其导入到TImage图片中。

var
  T : TMemoryStream;
begin
   T := TMemoryStream.Create;
   //将ImageCollection1中索引号为3的图片保存到Stream中
   ImageCollection1.Images.Items[3].SourceImages[0].Image.SaveToStream(TStream(T));

   T.Position := 0;
   //将保存的图片Stream显示到TImage1中
   Image1.Picture.WICImage.LoadFromStream(TStream(T));
   T.Free;

end;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海纳老吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值