Search code examples
delphivcl

delphi component with a collection of TPictures


I'm trying to create a VCL component like TImage, that lets me add a variable amount of different sized TPictures. The Goal is to be able to assign that number of TPictures through the VCL editor in the property list.

delphi component property: TObjectList<TPicture> here we came to the conclusion, that a TCollection with TCollectionItems should be used. This is what I'm trying to do now, but as many times before i end up with the compiler error: "Published property 'Pictures' can not be of Type ARRAY" in this line: property Pictures[Index: Integer]: TPic read GetPic write SetPic;

unit ImageMultiStates;

interface

uses
  Vcl.Graphics, Vcl.StdCtrls, System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Forms, Generics.Collections;

type

  TPic = class(TCollectionItem)
  private
    FPicture: TPicture;
  public
    procedure Assign(Source: TPersistent); override;
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
  published
    property Picture: TPicture read FPicture write FPicture;
  end;

  TPictures = class(TCollection)
  private
    function GetPic(Index: Integer): TPic;
    procedure SetPic(Index: Integer; APicture: TPic);
  public
    constructor Create;
  published
    property Pictures[Index: Integer]: TPic read GetPic write SetPic;
  end;

  TImageMultiStates = class(TImage)
  private
    FPictures: TPictures;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Activate(Index: Integer);
  end;

procedure Register;

implementation

constructor TPic.Create(Collection: TCollection);
begin
  inherited Create(Collection);
end;

destructor TPic.Destroy;
begin
  FPicture.Free;
  inherited Destroy;
end;

procedure TPic.Assign(Source: TPersistent);
begin
  FPicture.Assign(Source);
end;


constructor TPictures.Create;
begin
  inherited Create(TPic);
end;

procedure TPictures.SetPic(Index: Integer; APicture: TPic);
begin
  Items[Index].Assign(APicture);
end;

function TPictures.GetPic(Index: Integer): TPic;
begin
  Result := TPic(inherited Items[Index]);
end;


constructor TImageMultiStates.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TImageMultiStates.Destroy;
begin
  FPictures.Free;
  inherited Destroy;
end;

procedure TImageMultiStates.Activate(Index: Integer);
begin
  Picture.Assign(FPictures.Items[Index]);
end;

procedure Register;
begin
  RegisterComponents('Standard', [TImageMultiStates]);
end;

end.

Since noone seems to expect this error to be thrown, maybe it's related to my installed components? I used the internal GetIt Package-Manager to install the Jedi Code Library 2.8, Jedi Visual Component Library and PNGComponents 1.0. I guess that's about it as far as TImage-related components are concerned. Maybe one of these overrides some of my TImage contents with funky stuff...


Solution

  • I experimented a little and derived a TPicturePanel from TPanel. It has a Pictures property, which is a TPictures, a descendant of TOwnedCollection and which contains TPics. Each TPic has a Picture property. I can install this component, and it allows me to edit the Pictures collection using the so called Collection editor, which allows you to add or remove TPic instances. If you select a TPic in the Collection editor, you can assign a picture to its Picture property, i.e. load from file, etc.

    Here is the working code for TPicturePanel. You can model your component after this:

    unit PicturePanels;
    
    interface
    
    uses
      System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.Graphics;
    
    type
      TPic = class(TCollectionItem)
      private
        FPicture: TPicture;
        procedure SetPicture(const Value: TPicture);
      public
        procedure Assign(Source: TPersistent); override;
        constructor Create(AOwner: TCollection); override;
        destructor Destroy; override;
      published
        property Picture: TPicture read FPicture write SetPicture;
      end;
    
      TPictures = class(TOwnedCollection)
      private
        function GetItem(Index: Integer): TPic;
        procedure SetItem(Index: Integer; const Value: TPic);
      public
        constructor Create(AOwner: TPersistent);
        property Items[Index: Integer]: TPic read GetItem write SetItem;
      end;
    
      TPicturePanel = class(TPanel)
      private
        FPictures: TPictures;
        procedure SetPictures(const Value: TPictures);
      published
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        property Pictures: TPictures read FPictures write SetPictures;
      end;
    
    procedure Register;
    
    implementation
    
    procedure Register;
    begin
      RegisterComponents('Samples', [TPicturePanel]);
    end;
    
    { TPicturePanel }
    
    constructor TPicturePanel.Create(AOwner: TComponent);
    begin
      inherited;
      FPictures := TPictures.Create(Self);
    end;
    
    destructor TPicturePanel.Destroy;
    begin
      FPictures.Free;
      inherited;
    end;
    
    procedure TPicturePanel.SetPictures(const Value: TPictures);
    begin
      FPictures.Assign(Value);
    end;
    
    { TPic }
    
    procedure TPic.Assign(Source: TPersistent);
    begin
      inherited;
      if Source is TPic then
        FPicture.Assign(TPic(Source).FPicture);
    end;
    
    constructor TPic.Create(AOwner: TCollection);
    begin
      inherited;
      FPicture := TPicture.Create;
    end;
    
    destructor TPic.Destroy;
    begin
      FPicture.Free;
      inherited;
    end;
    
    procedure TPic.SetPicture(const Value: TPicture);
    begin
      FPicture.Assign(Value);
    end;
    
    { TPictures }
    
    constructor TPictures.Create(AOwner: TPersistent);
    begin
      inherited Create(AOwner, TPic);
    end;
    
    function TPictures.GetItem(Index: Integer): TPic;
    begin
      Result := inherited GetItem(Index) as TPic;
    end;
    
    procedure TPictures.SetItem(Index: Integer; const Value: TPic);
    begin
      inherited SetItem(Index, Value);
    end;
    
    end.