我正在尝试创建一个从TImage降下来的组件,其不同之处在于,我可以在属性列表中分配一个可变数量的TPictures (而不是按代码分配TPictures ),并通过要在TImage中显示的代码激活其中的一个。
如果有必要在属性中分配所有的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.
我在很多方面改变了这段代码,但我真的无法得到任何东西。
在我的组件“Image2State”中,我确实有同样的想法。然后我需要'Image4States‘等等,直到我决定我绝对需要一个可变数量的TPictures.
发布于 2016-07-21 00:53:15
您告诉我们,您的方法“不起作用”(我猜您的意思是“没有编译”):这是因为一些语法错误,而且您没有在工作中使用正确的工具。
如果您只有相同大小的图片,那么请考虑使用已经存在的、经过良好测试和IDE支持的TImageList
,不要试图重新发明轮子。
试着..。
但是,如果您必须有一个大小不同的图片列表,则使用TObjectList
而不是array of TPicture
。TObjectLists允许您添加、删除、查询等对象,如果您愿意,它们可以自动释放它们。
如果编译器支持泛型,则包含System.Generics.Collections并使用TObjectList<TPicture>
来管理图片。这样,您就不必强制转换为TPicture
,因为泛型列表是类型安全的。
如果不支持它们,请包含单元Contnrs并使用TObjectList
。当从该列表中读取时,您将不得不使用as
(即as TPicture
)进行强制转换,但否则您可以做类似的事情。
终于..。
您类型的名称使我认为您只需要一个特定控件的多个状态。在这种情况下,我认为TImageList
是作业的最佳工具(而且它已经适用于具有类似需求的其他控件),并且不需要自己制作一个。但是,如果您想创建自己的数组,就不要使用动态数组,也不要像使用for TPicture in FPictures do
的循环那样产生循环。帮你自己一个忙,并使用一个对象列表。
结束
发布于 2016-07-20 22:26:12
我回答这个问题时会问:你期望这样做是什么?
for TPicture in FPictures do
TPicture := TPicture.Create;
首先,正如所写的,这根本不编译。没有声明TPicture循环变量(即使声明了该变量,与类型名称相同也会导致后续编译错误)。
即使假设循环是有效的、可编译的代码,当构造函数执行FPictures时也是一个空数组,因此这个循环将执行0(0)次。您没有显示任何代码来告诉组件它应该支持多少张图片,所以它总是支持0(零)。
问题不会就此结束。
如果您确实声明了一个适当的变量作为循环变量,则循环代码仍然不会编译,因为它涉及到不允许的对循环变量的赋值。
即使在简单的for-循环以及基于迭代器的循环(如您试图使用的循环)中也是如此。在简单循环的情况下,这是为了使编译器能够产生最佳代码。在迭代器循环的情况下,它还可以保护您免受错误的影响,否则可能很容易出错。
在本例中,在循环的每次迭代中,您将创建一个新的TPicture实例,并将其分配给循环变量,但这会使而不是将其分配给初始化循环变量的数组中的项。
也许解释这一点的最简单的方法是“展开循环”(展开循环是为每次迭代显式重写代码,就好像根本没有循环一样)。
因此,请考虑循环是否包含两个项,并让我们还更改循环变量的名称,以使内容既有效又清晰。我们将使用简单的图片。换句话说,我们将展开这个循环的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;
希望你能看到问题所在。您可以在每次迭代中重写循环变量的值,但这不会修改数组项本身。更糟糕的是,循环的每一次迭代都泄漏了一个TPicture。
希望这能帮助您理解为什么您的代码不能工作(实际上,无法工作),并做出必要的更正。
https://stackoverflow.com/questions/38496203
复制相似问题