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. 改变index[name]并应用变化(VirtualImageList通过index[name]使用集合中的name[index]更新图像)。
2. 改变name[index]并应用变化(VirtualImageList使用集合中的index[name]按name[index]更新图像)。
用不同的名称保存图像(Save as...)。
提示:
你也可以点击并拖动一个图像到不同的位置来修改其索引值。
四、将现有的TImageList加载到TImageCollection中
为了协助将旧式图像列表转换为新系统,您可以从旧的TImageList-s加载图像到TImageCollection。当您在不同的TImageList-s中拥有同一图像的多种尺寸时,您可以一次加载这两种图像;图像被合并,以便图像集合包含同一图像的多种分辨率。
为了能够将图像从TImageList加载到TImageCollection中,你需要将这两个组件放在同一Form中。
按照下面的步骤,从表单上现有的TImageList加载图像到TImageCollection。
右击表格中的TImageCollection组件,从上下文菜单中选择从现有的TImageList中加载... 选项。
选择你想加载的TImageList并为图像指定一个类别。你可以选择一个以上的TImageList。这对加载同一图像的多个分辨率特别有用,这些图像以前存储在多个图像列表中。

单击 "Load in order",以便按照图像列表的相同顺序加载图像。
单击 "Load & merge "以合并来自不同图像列表的不同图像源。合并加载时,图像列表必须有相同数量的图像文件和不同的图像尺寸。

单击 "View Collection... "以验证图像在TImageCollection中是如何被导入的,而不必关闭对话框。
单击 "OK "以应用设置并关闭对话框。
单击 "Apply "以应用一组特定的更改并继续配置设置。
单击 "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: 允许你创建和添加你选择的图像的低不透明度或灰度版本。禁用图像的外观由图像列表的DisabledGrayscale和DisabledOpacity属性控制。
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而缩放。这使得表单上的控件与图像列表一起绘制时,总是以正确的比例分辨率绘制。然而,这意味着两件事。
控件应该总是引用同一表单上的图像列表。如果一个控件引用了不同窗体上的图像列表,那么当两个窗体有不同的DPI时,例如在不同的屏幕上,图像可能会画得不正确。
一个TVirtualImageList应该总是放在表单上,而不是数据模块上。表单有一个相关的显示器和DPI;数据模块没有。TImageCollection可以放在任何地方,因为它们只是源,并且不受DPI变化的影响:它们是源,而TVirtualImageList虚拟图像列表是呈现。
因此,如果表单上的控件使用了一个图像列表,总是在该表单上放置一个或多个TVirtualImageLists,并让控件只引用这些本地的、同表单的图像列表。这些TVirtualImageLists可以全部引用同一个TImageCollection。
虚拟图像集合是一个非常有用的控件,它将图像集合(TImageCollection)的概念与特定尺寸的图像集(TVirtualImageList)区分开来,尽管该尺寸会随DPI的变化而变化。一个图像集合不会受到DPI变化的影响,因为它只是一个容器。虚拟图像列表可以从另一个表单或数据模块的集合中引用图像。好的设计是在你的应用程序的主窗体或甚至更好的共享数据模块上为相关的图像--例如,所有的工具栏和菜单图像--有一个单一的图像集合。其他窗体将有他们自己的虚拟图像列表,具体到每个窗体,这些图像列表使用中央图像集合。
多个尺寸
如果你需要同一图像的多种尺寸,例如TListView的SmallImages和LargeImages属性,请使用两个TVirtualImageLists,就像你使用传统的TImageLists那样。这两个虚拟图像列表都引用了同一个图像集合。
在你的应用程序中支持高DPI:转换旧的TImageLists
将VCL应用程序从使用TImageLists转换为TVirtualImageLists是很常见的,这样可以升级视觉质量,也可以帮助支持高DPI。
TVirtualImageList继承自TCustomImageList的,所以在代码层面上可以直接替换,同时还提供了一个HIMAGELIST Handle属性来直接调用Windows API方法。
有两种建议的方法来转换你的应用程序以使用新的高DPI图像列表。
首先,你可能同时也在升级你的图标,从旧的风格到更现代的风格,或者从彩色透明到带有alpha通道的32位图像。如果你这样做,你可能会发现最简单的做法是把这些添加到一个新的图像集合中,创建新的图像列表,并改变你的组件以指向新的图像列表。
第二,你可能想一步一步地升级,逐步替换旧的图像,甚至根本不替换(尽管我们确实建议利用新系统中的32bpp alpha通道支持)。要这样做,放置一个TImageCollection,然后右击并选择从现有的TImageList(s)加载。选择图像列表,并选择添加图像,或合并图像,如果它们包含多个分辨率的相同图像。请看四、将现有的TImageList加载到TImageCollection,将现有的TImageList加载到TImageCollection中,以获得完整的信息。
这将导致您的图像集合包含您的旧图像。尽管使用旧的图像,你不会看到图形质量或透明度的提高,就像你使用新设计的图像一样,但这确实允许你让图像随每个表格的DPI缩放。在每个表单上创建新的TVirtualImageList组件,并从集合中添加图像:它们将保持相同的相对顺序,所以相同的索引,除非集合中已经有图像。然后,改变你的组件以使用新的TVirtualImageLists。
在TCanvas上绘图时,可平滑缩放
TCanvas.StretchDraw允许将TGraphic绘制到一个任意的矩形中。虽然TGraphic子类的实现决定了如何做到这一点,但在实践中,VCL绘图(如TBitmap)通常通过GDI使用近邻重采样,通常不会产生理想的缩放或拉伸的图像质量。
你可以使用TImageCollection来保存图像(内部存储为并使用WIC绘制),并将其绘制到一个任意的矩形。这样做将使用高质量的重采样。
将TImageCollection中图像导入到TImage中
假定TImageCollection1 中存在索引号为3的一个图像,需要将其导入到TImage图片中。
varT : TMemoryStream;
beginT := 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;
相关文章:

Delphi 中TImageCollection和TVirtualImageList 控件实现high-DPI
一、概述RAD Studio允许你通过使用TImageCollection组件和TVirtualImageList组件,在你的Windows VCL应用程序中包含缩放、高DPI、多分辨率的图像。这两个组件位于Windows 10面板中:注意:如果你使用FireMonkey进行跨平台应用,请看T…...

Ros中如何给UR5配置自定义工具 | 在Rviz中给UR5机器人装载定义工具 | UR5配置自定义末端执行器
前言 在学习和项目研究的过程中,我需要在Ur5e上装上工具,以对现实场景进行仿真。网上会有一些装载/配置现成的夹爪,例如Robotiq等。但和我们装载自定义工具的场景还有些差异,因此写一篇博客记录,可能有偏差。如果有问…...

数据库 delete 表数据后,磁盘空间为什么还是被一直占用?
插: 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 坚持不懈,越努力越幸运,大家一起学习鸭~~~ 最近有个上位机获取下位机上报数据的项目,…...

docker-微服务篇
docker学习笔记1.docker简介1.1为什么会出现docker?1.2docker理念1.3虚拟机(virtual machine)1.4容器虚拟化技术1.5一次构建到处运行2.docker安装2.1前提条件2.2docker基本构成2.3docker安装步骤*2.4测试镜像3.docker常用命令3.1 启动docker3…...

图像优化篇
目录(1)矢量图(2)位图 2.1 分辨率2,图像格式格式选择建议:(1)矢量图 被定义为一个对象,包括颜色,大小,形状,以及屏幕位置等属性&…...
在surface go 2上安装ubuntu 20.04
在surface go 2上安装ubuntu 20.04 1.制作安装盘 下载ubuntu系统的iso文件 使用Rufus软件将u盘制作为ubuntu系统的安装盘 2.在surface go 2上操作 禁用快速启动 在 Windows 中,禁用“电源选项”中的“快速启动”>选择电源按钮的功能 禁用 Bitlocker 在 Wi…...

Java:SpringMVC的使用(1)
目录第一章、SpringMVC基本了解1.1 概述1.2 SpringMVC处理请求原理简图第二章、SpringMVC搭建框架1、搭建SpringMVC框架1.1 创建工程【web工程】1.2 导入jar包1.3 编写配置文件(1) web.xml注册DispatcherServlet(2) springmvc.xml(3) index.html1.4 编写请求处理器【Controller…...

自动化测试岗位求职简历编写规范+注意事项,让你的简历脱颖而出
目录 前言 1.个人信息 2.教育背景(写最高学历) 3.个人技能(按精通/掌握/熟练/了解层次来写) 4.工作经历 5.工作经验/项目经历 6.自我评价 总结 前言 挑选一个阅读舒适度不错的模板 HR和面试官看的简历多,都是快速阅读,舒适度特别重要;…...

C 字符串
在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。空字符(Null character)又称结束符,缩写 NUL,是一个数值为 0 的控制字符,\0 是转义字符&#…...
【每日一题Day115】LC2335装满杯子需要的最短总时长 | 贪心
装满杯子需要的最短总时长【LC2335】 You have a water dispenser that can dispense cold, warm, and hot water. Every second, you can either fill up 2 cups with different types of water, or 1 cup of any type of water. You are given a 0-indexed integer array amo…...
Flink流计算处理-旁路输出
使用Flink做流数据处理时,除了主流数据输出,还自定义侧流输出即旁路输出,以实现灵活的数据拆分。 定义旁路输出标签 首先需要定义一个OutputTag,代码如下: // 这需要是一个匿名的内部类,以便我们分析类型…...

nginx正向代理的配置和使用
nginx正向代理的配置和使用 nginx正向代理的配置和使用nginx正向代理的配置和使用安装包准备下载nginx安装包下载正向代理模块的包版本与模块对照表部署nginx服务上传nginx包和正向模块包解压,改名安装nginx配置正向代理创建nginx用户检查nginx配置并启动nginx服务所在服务器验…...

Oracle Trace File Analyzer 介绍及简单使用
一、什么是Oracle Trace File Analyzer Oracle Autonomous Health Framework(AHF) 包含 Oracle ORAchk, Oracle EXAchk, and Oracle Trace File Analyzer(TFA). AHF工具包包含了Oracle常用的多种诊断工具,如 ORAchk, Oracle EXAchk, and Oracle Trace File Analyzer…...

面试实战篇 | 快手本地生活,结合项目谈Redis实战项目场景?MySQL InnoDB存储引擎如何工作的?策略模式?
本期是【你好,面试官】系列文章的第21期,持续更新中…。 《你好,面试官》系列目前已经连载20篇了,据说看了这个系列的朋友都拿到了大厂offer~ 你好,面试官 | 你真的理解面向 “对象”?你好,面…...

Hadoop之——WordCount案例与执行本地jar包
目录 一、WordCount代码 (一)WordCount简介 1.wordcount.txt (二)WordCount的java代码 1.WordCountMapper 2.WordCountReduce 3.WordCountDriver (三)IDEA运行结果 (四)Hadoop运行wordcount 1.在HDFS上新建一个文件目录 2.新建一个文件,并上传至该目录下…...

利用git reflog 命令来查看历史提交记录,并使用提交记录恢复已经被删除掉的分支
一.问题描述 当我们在操作中手误删除了某个分支,那该分支中提交的内容也没有了,我们可以利用git reflog这个命令来查看历史提交的记录从而恢复被删除的分支和提交的内容 二.模拟问题 1.创建git仓库,并提交一个文件 [rootcentos7-temp /da…...

【软件测试】大厂测试开发你真的了解吗?测试开发养成记......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 在一些大公司里&…...

Redis中的hash结构和扩容机制
1.rehash原理 hash包含两个数据结构为字典数组ht[0]和ht[1]。其中ht[0]用来存放数据,ht[1]在rehash时使用。 扩容时,ht[1]的大小为第一个大于等于ht[0].used*2的2的幂次方的数; 收缩时,ht[1]的大小为第一个大于等于ht[0].used的…...
【C++奇技淫巧】前置自增与后置自增的区别(++i,i++)【2023.02.08】
简介 先说i和i的区别,判断语句中if(i)是拿i的值先判断,而后自增;if(i)是先自增i再进行判断。涉及到左值与右值也有点区别,i返回的是右值,i返回的是左值。也就是下面的代码要解释的东西。 #include <iostream>i…...

实战打靶集锦-005-HL
**写在前面:**记录一次曲折的打靶经历。 目录1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 浏览器访问4.2 目录枚举4.3 探查admin4.4 探查index4.5 探查login5 公共EXP搜索6. 再次目录枚举6.1 探查superadmin.php6.2 查看页面源代码6.3 base64绕过6.4 构建反弹…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...

企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...
Java多线程实现之Runnable接口深度解析
Java多线程实现之Runnable接口深度解析 一、Runnable接口概述1.1 接口定义1.2 与Thread类的关系1.3 使用Runnable接口的优势 二、Runnable接口的基本实现方式2.1 传统方式实现Runnable接口2.2 使用匿名内部类实现Runnable接口2.3 使用Lambda表达式实现Runnable接口 三、Runnabl…...
Easy Excel
Easy Excel 一、依赖引入二、基本使用1. 定义实体类(导入/导出共用)2. 写 Excel3. 读 Excel 三、常用注解说明(完整列表)四、进阶:自定义转换器(Converter) 其它自定义转换器没生效 Easy Excel在…...