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

news2024/12/28 18:20:57

一、概述

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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/339664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用VSCode在共用服务器上使用连接自己的Docker容器进行开发

问题描述 我们实验室有一台很牛的Linux服务器,核多卡多硬盘大,它是大家共用的,组里给我们每个人都创建了一个普通用户,没有sudo权限,所以不能用apt。 但是每个人对开发环境的需求都是不一样的,比如我要用…

年前无情被裁,面试大厂的这几个月…

2月份了,金三银四也即将来临,在这个招聘季,大厂也开始招人,但还是有很多人吐槽说投了很多简历,却迟迟没有回复… 另一面企业招人真的变得容易了吗?有企业HR吐槽,简历确实比以前多了好几倍&…

【手写 Vuex 源码】第五篇 - Vuex 中 Mutations 和 Actions 的实现

一,前言 上一篇,主要介绍了 Vuex 中 getters 的实现,主要涉及以下几个点: 将选项中的 getters 方法,保存到 store 实例中的 getters 对象中;借助 Vue 原生 computed,实现 Vuex 中 getters 的数…

有趣的Hack-A-Sat黑掉卫星挑战赛——跟踪卫星

国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加,太空已经成为国家赖以生存与发展的命脉之一,凝聚着巨大的国家利益,太空安全的重要性日益凸显[1]。而在信息化时代,太空安…

TMC2660驱动及调试记录

TMC2660 一款优秀的电机驱动芯片,驱动简单。 理论就看这篇:TMC260/TMC2660/TMC262步进电机驱动 或者直接看手册,手册也不复杂。 使用SPI通信,通过SPI配置参数。支持直接使用SPI和Step/Dir方式控制两种控制步进电机的方式。 TMC…

【C语言】数据结构-二叉树

主页:114514的代码大冒险 qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ ) Gitee:庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 引入 我们之前已经学过线性数据结构,今天我们将介绍非线性数据结构----树 树是一种非线性的…

面试官问我:说说你对Spring MVC的理解

文章目录什么是MVC模式MVC的原理图2.1 分析工作原理3.1 组件说明:3.1.1 组件:核心架构的具体流程步骤什么是MVC模式 MVC:MVC是一种设计模式 MVC的原理图 2.1 分析 M-Model 模型(完成业务逻辑:有javaBean构成&#x…

C++11的异步操作让多线程开发变得简单

C11的异步操作简介一、std::future1.1、future的类型1.2、future的使用1.3、使用示例二、std::packaged_task三、std::promise总结简介 C提供如下的异步操作接口: std::future :异步指向某个任务,然后通过future特性去获取任务函数的返回结…

1. RNN神经网络初探

目录1. 神经网络与未来智能2. 回顾数据维度和神经网络3. 文本转变为词向量1. 神经网络与未来智能 2. 回顾数据维度和神经网络 循环神经网络,主要用来处理时序的数据,它对每个词的顺序是有要求的。 循环神经网络如何保存记忆功能? 当前样本只…

Window10开放某个端口

需求:由于防火墙原因,开放某个端口:如9999 在开始那里搜索防火墙-进入防火墙 第一步:核实是否启动了防火墙,之后进行 第二步:点击“高级设置”,→“入站规则”→“新建规则”→“端口”→ “下一步” …

【前端领域】3D旋转超美相册(HTML+CSS)

世界上总有一半人不理解另一半人的快乐。 ——《爱玛》 目录 一、前言 二、本期作品介绍 3D旋转相册 三、效果展示 四、详细介绍 五、编码实现 index.html style.css img 六、获取源码 公众号获取源码 获取源码?私信?关注?点赞&…

基于微信小程序的游戏账号交易小程序

文末联系获取源码 开发语言:Java 框架:ssm JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏览器…

【C++初阶】十二、STL---反向迭代器的实现

目录 一、反向迭代器 二、反向迭代器的实现 一、反向迭代器 之前的模拟实现vector、list 的时候,这些都是实现了正向迭代器,反向迭代器都没有实现,这里就要实现反向迭代器 反向迭代器也是适配器(配接器)的一种&#…

在阿里干了2年的测试,总结出来的划水经验

测试新人 我的职业生涯开始和大多数测试人一样,开始接触都是纯功能界面测试。那时候在一家电商公司做测试,做了一段时间,熟悉产品的业务流程以及熟练测试工作流程规范之后,效率提高了,工作比较轻松,这样我…

代码随想录第55天(动态规划):● 309.最佳买卖股票时机含冷冻期 ● 714.买卖股票的最佳时机含手续费

一、最佳买卖股票时机含冷冻期 题目描述: 思路和想法: 这道题相较于之前的题目,注重对状态的分析,这里分为四个状态。 (1)状态一,买入状态 dp[i][0] 操作一:前一天就是持有状态(状…

day39【代码随想录】动态规划之

文章目录前言一、不同路径(力扣62)二、不同路径||(力扣63)三、最小路径和(力扣64)前言 1、不同路径 2、不同路径|| 3、最小路径和 一、不同路径(力扣62) 一个机器人位于一个 m x n…

MyBatis-Plus分页插件和MyBatisX插件

MyBatis-Plus分页插件和MyBatisX插件六、插件1、分页插件a>添加配置类b>测试八、代码生成器1、引入依赖2、快速生成十、MyBatisX插件1、新建spring boot工程a>引入依赖b>配置application.ymlc>连接MySQL数据库d>MybatisX逆向生成2、MyBatisX快速生成CRUD申明…

学习open62541 --- [74] 软链接的妙用

一 原理 在同一台电脑里,可能会有多个工程同时用到open62541,比较简单的办法是每个工程都拷贝一份open62541源码,但是这样会造成空间浪费,而且open62541的源码包本身也不小。 对于Linux用户来说,可以使用软链接来解决…

【Python学习笔记】28.Python3 错误和异常

前言 作为 Python 初学者,在刚学习 Python 编程时,经常会看到一些报错信息,在前面我们没有提及,这章节我们会专门介绍。 Python3 错误和异常 Python 有两种错误很容易辨认:语法错误和异常。 Python assert&#xf…

德国奔驰、博世和保时捷的员工年薪有多少?

点击 欧盟IT那些事 关注我们公告:因企鹅审核规定,本公众号从《德国IT那些事》更名为《欧盟IT那些事》。从职场新人到总裁,一个个盘。位于德国斯图加特的梅赛德斯-奔驰集团及其子公司梅赛德斯-奔驰是世界最知名的汽车制造商之一。奔驰车代表着…