Delphi组件,具有可变数量的TPictures
我试图创建一个从TImage开始的组件,不同的是我可以在属性列表中分配一个可变数量的TPictures(而不是按代码分配TPictures),并按代码激活其中一个以显示在TImage中 如果有必要在属性中分配所有TPictures,那么设置TPictures总数(动态数组的长度)的属性就不会有问题Delphi组件,具有可变数量的TPictures,delphi,vcl,Delphi,Vcl,我试图创建一个从TImage开始的组件,不同的是我可以在属性列表中分配一个可变数量的TPictures(而不是按代码分配TPictures),并按代码激活其中一个以显示在TImage中 如果有必要在属性中分配所有TPictures,那么设置TPictures总数(动态数组的长度)的属性就不会有问题 unit ImageMultiStates; interface uses Vcl.Graphics, Vcl.StdCtrls, System.SysUtils, System.Classe
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”等等,直到我决定我绝对需要这张带有可变数量图片的图片…我会问:你希望它做什么:
for TPicture in FPictures do
TPicture := TPicture.Create;
首先,如前所述,这根本不需要编译。未声明TPicture循环变量(如果与类型名称相同,则即使已声明,也会导致后续编译错误)
即使假设循环是有效的可编译代码,当构造函数执行FPictures时,它也是一个空数组,因此该循环将执行0(零)次。您不会显示任何告诉组件应该支持多少图片的代码,因此它始终支持0(零)
问题还不止于此
如果您确实声明了一个合适的变量用作循环变量,那么循环代码仍然不会编译,因为它涉及到对循环变量的赋值,这是不允许的
即使在简单for循环以及基于迭代器的循环(如您尝试使用的循环)中也是如此。对于简单循环,这是为了使编译器能够生成最佳代码。在迭代器循环的情况下,它还可以保护您避免可能容易犯的错误
考虑到在这种情况下,在循环的每次迭代中,您都会创建一个新的TPicture实例并将其分配给循环变量,但这不会将其分配给初始化循环变量的数组中的项
也许解释这一点最简单的方法是“展开循环”(展开循环就是为每次迭代显式地重新编写代码,就好像根本没有循环一样)
如果循环包含2个项,那么我们也可以改变循环变量的名称,使事情既有效又清楚一些。我们将简单地使用pic。换句话说,我们将展开此循环的2个迭代版本:
for pic in FPictures do // fPictures contains 2 items
pic := TPicture.Create;
请记住,这是而不是编译,当我们展开它将创建的循环(如果可能的话)时,这有助于防止我们犯错误的原因变得很明显:
// Iteration #1
pic := fPictures[0];
pic := TPicture.Create;
// Iteration #2
pic := fPictures[1];
pic := TPicture.Create;
希望你能看到问题所在。在每次迭代中覆盖循环变量的值,但这不会修改数组项本身。更糟糕的是,循环的每次迭代都会泄漏一张t图片
希望这能帮助您理解为什么代码不能工作(实际上,不能工作)并进行必要的更正
您告诉我们您的方法“不起作用”(我想您的意思是“未编译”):这是因为一些语法错误,并且您没有使用正确的工具来完成此工作 如果您只有相同大小的图片,请考虑使用现有的、经过良好测试且受IDE支持的
TImageList
,不要尝试重新发明轮子
尝试
但是,如果必须有不同大小的图片列表,则使用TObjectList
而不是图片数组。TobjectList允许您添加、删除、查询等对象,如果您愿意,它们可以自动释放这些对象
如果编译器支持泛型,请包含System.generics.Collections,并使用TObjectList
来管理图片。这样,您就不必强制转换到TPicture
,因为泛型列表是类型安全的
如果不支持它们,则包括单元Contnrs并使用TObjectList
。在阅读该列表时,您必须使用as
,即as TPicture
,否则您可以执行类似的操作
最后
您类型的名称使我认为,对于某个控件,您只需要多个状态。在这种情况下,我认为TImageList
是这项工作的最佳工具(对于其他具有类似需求的控件来说,它已经是了),并且没有必要制作自己的工具。但是如果你想自己制作,不要使用动态数组,也不要像FPictures do
中的TPicture那样生成循环。帮自己一个忙,使用对象列表
End您需要维护一组图片。希望您能在构造函数中创建图片实例是一个错误。@David Heffernan:哦,是的,当然。我真傻。但除此之外,我在这里尝试的东西能起作用吗?我应该在属性中设置图片数量,还是由适当的PropertyEditor正确显示一组图片?我想您应该使用包含图片对象的
t集合。然后它应该可以很容易地连接到属性编辑器。以防万一,您确实知道TImageList
,是吗?它可以保存TImage支持的任何类型的动态大小相同的图像,并具有设计时编辑器。限制是,图像需要相同的大小,默认值是16×16,但是可以在任何图像被添加到列表之前根据需要改变高度和宽度。但是考虑使用TimaGelistor,如果YO