I'm trying to create a component descending from TImage, with the difference that I can assign a variable number of TPictures in the property list (not assign the TPictures by code) and activate one of them by code to be displayed in the TImage.
It would not be a problem to have a property that sets the overall number of TPictures (length of the dynamic array), if that's necessary to have all the TPictures assignable within the properties.
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.
I turned this code around in many ways, but i just can't get anything to work really.
I do have this exact same idea already working in my component 'Image2States'. Then I needed 'Image4States' and so on, until I decided that I absolutely need this with a variable amount of TPictures...
You told us that your approach "didn't work" (I assume you meant "didn't compile"): That is because of a few syntactical errors and because you are not using the right tool for the job.
If you only have pictures of the same size, then think about using the already existing, well tested and IDE-supported TImageList
and don't try to reinvent the wheel.
If, however, you must have a list of pictures of different sizes, then use a TObjectList
and not an array of TPicture
. TObjectLists allow you to add, remove, query, etc. objects and they can automatically free them, if you wish.
If your compiler supports generics, then include System.Generics.Collections and use a TObjectList<TPicture>
to manage your pictures. That way, you don't have to cast to TPicture
, because the generics lists are type safe.
If it doesn't support them, include the unit Contnrs and use a TObjectList
. When reading from that list, you will have to cast using as
, i.e. as TPicture
, but otherwise you can do similar things.
The name of your type makes me think you only need multiple states for a certain control. In that case, I think a TImageList
is the best tool for the job (and it already is for other controls with similar needs) and there is no need to make your own one. But if you want to make your own, don't use a dynamic array and don't produce loops like the one with for TPicture in FPictures do
. Do yourself a favour and use an object list.