Delphi 具有可变数量的 TPictures 的组件
Delphi component with a variable amount of TPictures
我正在尝试创建一个从 TImage 下降的组件,不同之处在于我可以在 属性 列表中分配可变数量的 TPictures(不是通过代码分配 TPictures)并激活其中之一通过代码显示在 TImage 中。
设置 TPictures 总数(动态数组的长度)的 属性 不是问题,如果有必要在属性中分配所有 TPictures。
unit ImageMultiStates;
interface
uses
Vcl.Graphics, Vcl.StdCtrls, System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Forms;
type
TPictures = Array of TPicture;
TImageMultiStates = class(TImage)
private
FPictures: TPictures;
procedure SetPicture(Which: Integer; APicture: TPicture);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Activate(Which: Integer);
published
property Images: TPictures read FPictures write FPictures; default;
end;
procedure Register;
implementation
constructor TImageMultiStates.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
for TPicture in FPictures do
TPicture := TPicture.Create;
end;
destructor TImageMultiStates.Destroy;
var
APicture: TPicture;
begin
for APicture in FPictures do
APicture.Free;
inherited Destroy;
end;
procedure TImageMultiStates.Activate(Which: Integer);
begin
Picture.Assign(FPictures[Which]);
end;
procedure TImageMultiStates.SetPicture(Which: Integer; APicture: TPicture);
begin // i would also like to use SetPicture instead of "write FPictures"
FPictures[Which].Assign(APicture);
if Which=0 then // because: First Picture will be displayed in the VCL editor
Picture.Assign(FPictures[Which]);
end;
procedure Register;
begin
RegisterComponents('Standard', [TImageMultiStates]);
end;
end.
我以多种方式修改了这段代码,但我就是无法真正发挥任何作用。
我的组件中确实已经有了完全相同的想法 'Image2States'。然后我需要 'Image4States' 等等,直到我决定我绝对需要它和可变数量的 TPictures...
我会这样回答:你希望它做什么:
for TPicture in FPictures do
TPicture := TPicture.Create;
首先,如所写,这根本无法编译。 TPicture循环变量未声明(与类型名称相同,即使声明也会导致后续编译错误)。
即使假设循环是有效的可编译代码,当构造函数执行时 FPictures 是一个空数组,因此此循环将执行 0(零)次。您没有显示任何代码来告诉组件它应该支持多少张图片,因此它始终支持 0(零)。
问题不止于此。
如果您确实声明了一个适当的变量用作循环变量,循环代码仍将无法编译,因为它涉及对循环变量的赋值,这是不允许的。
即使在简单的 for 循环以及基于迭代器的循环(例如您尝试使用的循环)中也是如此。在简单循环的情况下,这是为了使编译器能够生成最佳代码。在迭代器循环的情况下,它还可以保护您避免可能容易犯的错误。
考虑到在这种情况下,在循环的每次迭代中,您将创建一个新的 TPicture 实例并将其分配给循环变量 ,但这确实 不将其分配给初始化循环变量的数组中的项目。
也许最简单的解释方法是 "unroll the loop"(展开循环就是为每次迭代明确地重写代码,就好像根本没有循环一样)。
所以考虑一下循环是否包含 2 个项目,让我们也更改循环变量的名称以使事情既有效又更清晰。我们将简单地使用 pic。换句话说,我们将展开此循环的 2 次迭代版本:
for pic in FPictures do // fPictures contains 2 items
pic := TPicture.Create;
请记住,这 不会 编译,当我们展开它将创建的循环时,这有助于防止我们犯错的原因变得显而易见,if 有可能:
// Iteration #1
pic := fPictures[0];
pic := TPicture.Create;
// Iteration #2
pic := fPictures[1];
pic := TPicture.Create;
希望您能看到问题所在。您在每次迭代时覆盖 循环变量 的值,但这不会修改数组项本身。更糟糕的是,循环的每次迭代都在泄漏 TPicture.
希望这现在可以帮助您理解为什么您的代码无法正常工作(实际上,无法正常工作)并进行必要的更正。
您需要一些机制来设置您的组件支持的图片数量
您需要正确初始化保存这些图片的数组中的项目
您告诉我们您的方法“无效”(我假设您的意思是“未编译”):那是因为一些语法错误并且因为您没有使用正确的工具来完成工作.
如果您只有 相同尺寸的图片,那么请考虑使用已经存在、经过良好测试和 IDE 支持的 TImageList
并且不要'尝试重新发明轮子。
尝试...
但是,如果您必须拥有不同尺寸图片的列表,请使用 TObjectList
而不是 array of TPicture
。 TObjectLists 允许您添加、删除、查询等对象,如果您愿意,它们可以自动释放它们。
如果您的编译器支持泛型,则包含 System.Generics.Collections 并使用 TObjectList<TPicture>
来管理您的图片。这样,您就不必强制转换为 TPicture
,因为泛型列表是类型安全的。
如果不支持它们,请包含单位 Contnrs 并使用 TObjectList
。从该列表中读取时,您将必须使用 as
进行转换,即 as TPicture
,否则您可以做类似的事情。
终于...
你的类型name让我觉得你只需要多个状态来实现某个控件。在那种情况下,我认为 TImageList
是完成这项工作的最佳工具(并且它已经适用于具有类似需求的其他控件)并且没有必要制作自己的工具。但是如果你想自己制作,不要使用动态数组,也不要产生像 for TPicture in FPictures do
这样的循环。帮自己一个忙,使用对象列表。
结束
我正在尝试创建一个从 TImage 下降的组件,不同之处在于我可以在 属性 列表中分配可变数量的 TPictures(不是通过代码分配 TPictures)并激活其中之一通过代码显示在 TImage 中。
设置 TPictures 总数(动态数组的长度)的 属性 不是问题,如果有必要在属性中分配所有 TPictures。
unit ImageMultiStates;
interface
uses
Vcl.Graphics, Vcl.StdCtrls, System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Forms;
type
TPictures = Array of TPicture;
TImageMultiStates = class(TImage)
private
FPictures: TPictures;
procedure SetPicture(Which: Integer; APicture: TPicture);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Activate(Which: Integer);
published
property Images: TPictures read FPictures write FPictures; default;
end;
procedure Register;
implementation
constructor TImageMultiStates.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
for TPicture in FPictures do
TPicture := TPicture.Create;
end;
destructor TImageMultiStates.Destroy;
var
APicture: TPicture;
begin
for APicture in FPictures do
APicture.Free;
inherited Destroy;
end;
procedure TImageMultiStates.Activate(Which: Integer);
begin
Picture.Assign(FPictures[Which]);
end;
procedure TImageMultiStates.SetPicture(Which: Integer; APicture: TPicture);
begin // i would also like to use SetPicture instead of "write FPictures"
FPictures[Which].Assign(APicture);
if Which=0 then // because: First Picture will be displayed in the VCL editor
Picture.Assign(FPictures[Which]);
end;
procedure Register;
begin
RegisterComponents('Standard', [TImageMultiStates]);
end;
end.
我以多种方式修改了这段代码,但我就是无法真正发挥任何作用。
我的组件中确实已经有了完全相同的想法 'Image2States'。然后我需要 'Image4States' 等等,直到我决定我绝对需要它和可变数量的 TPictures...
我会这样回答:你希望它做什么:
for TPicture in FPictures do
TPicture := TPicture.Create;
首先,如所写,这根本无法编译。 TPicture循环变量未声明(与类型名称相同,即使声明也会导致后续编译错误)。
即使假设循环是有效的可编译代码,当构造函数执行时 FPictures 是一个空数组,因此此循环将执行 0(零)次。您没有显示任何代码来告诉组件它应该支持多少张图片,因此它始终支持 0(零)。
问题不止于此。
如果您确实声明了一个适当的变量用作循环变量,循环代码仍将无法编译,因为它涉及对循环变量的赋值,这是不允许的。
即使在简单的 for 循环以及基于迭代器的循环(例如您尝试使用的循环)中也是如此。在简单循环的情况下,这是为了使编译器能够生成最佳代码。在迭代器循环的情况下,它还可以保护您避免可能容易犯的错误。
考虑到在这种情况下,在循环的每次迭代中,您将创建一个新的 TPicture 实例并将其分配给循环变量 ,但这确实 不将其分配给初始化循环变量的数组中的项目。
也许最简单的解释方法是 "unroll the loop"(展开循环就是为每次迭代明确地重写代码,就好像根本没有循环一样)。
所以考虑一下循环是否包含 2 个项目,让我们也更改循环变量的名称以使事情既有效又更清晰。我们将简单地使用 pic。换句话说,我们将展开此循环的 2 次迭代版本:
for pic in FPictures do // fPictures contains 2 items
pic := TPicture.Create;
请记住,这 不会 编译,当我们展开它将创建的循环时,这有助于防止我们犯错的原因变得显而易见,if 有可能:
// Iteration #1
pic := fPictures[0];
pic := TPicture.Create;
// Iteration #2
pic := fPictures[1];
pic := TPicture.Create;
希望您能看到问题所在。您在每次迭代时覆盖 循环变量 的值,但这不会修改数组项本身。更糟糕的是,循环的每次迭代都在泄漏 TPicture.
希望这现在可以帮助您理解为什么您的代码无法正常工作(实际上,无法正常工作)并进行必要的更正。
您需要一些机制来设置您的组件支持的图片数量
您需要正确初始化保存这些图片的数组中的项目
您告诉我们您的方法“无效”(我假设您的意思是“未编译”):那是因为一些语法错误并且因为您没有使用正确的工具来完成工作.
如果您只有 相同尺寸的图片,那么请考虑使用已经存在、经过良好测试和 IDE 支持的 TImageList
并且不要'尝试重新发明轮子。
尝试...
但是,如果您必须拥有不同尺寸图片的列表,请使用 TObjectList
而不是 array of TPicture
。 TObjectLists 允许您添加、删除、查询等对象,如果您愿意,它们可以自动释放它们。
如果您的编译器支持泛型,则包含 System.Generics.Collections 并使用 TObjectList<TPicture>
来管理您的图片。这样,您就不必强制转换为 TPicture
,因为泛型列表是类型安全的。
如果不支持它们,请包含单位 Contnrs 并使用 TObjectList
。从该列表中读取时,您将必须使用 as
进行转换,即 as TPicture
,否则您可以做类似的事情。
终于...
你的类型name让我觉得你只需要多个状态来实现某个控件。在那种情况下,我认为 TImageList
是完成这项工作的最佳工具(并且它已经适用于具有类似需求的其他控件)并且没有必要制作自己的工具。但是如果你想自己制作,不要使用动态数组,也不要产生像 for TPicture in FPictures do
这样的循环。帮自己一个忙,使用对象列表。