No reaction when "..." clicked on a TCollectionItem property that represents another TCollection

137 Views Asked by At

I've never been in a situation that needed it, and this is the first time I try to have a TCollection as TCollectionItem of another TCollection. It all compiles fine, but there is no reaction when the three dots behind the TCollectionItem's TCollection property are clicked, ie. the dialog with the list of that sub-TCollection does not appear.

I was under the impression that, since no fancy property editors should be necessary (the sub-TCollection only carries items that have a string and a single property), the IDE would pretty much handle it automatically.

Apparently that's not the case, or I'm overseeing the obvious, which is a chronic affliction.

The implementation (run-time) unit has this:

type

  TBitmapItemTag = class(TCollectionItem)
  private
    FTagName: string;
    FTagFloat: Single;
  published
    property TagName: string read FTagName write FTagName;
    property TagFloat: Single read FTagFloat write FTagFloat;
  end;

  TBitmapItemTags = class(TOwnedCollection)

  end;

  TBitmapItem = class(TCollectionItem)
  private
    FBitmap: TBitmap;
    FBitmapItemTags: TBitmapItemTags;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
  published
    property Bitmap: TBitmap read FBitmap write FBitmap;
    property Tags: TBitmapItemTags read FBitmapItemTags write FBitmapItemTags;
  end;

  TBitmaps = class(TCollection)

  end;

  TBitmapCollection = class(TComponent)
  private
    FBitmaps: TBitmaps;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Bitmaps: TBitmaps read FBitmaps write FBitmaps;
  end;

implementation

{ TBitmapItem }

constructor TBitmapItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FBitmap := TBitmap.Create(0, 0);
  FBitmapItemTags := TBitmapItemTags.Create(Self,TBitmapItemTag);
end;

destructor TBitmapItem.Destroy;
begin
  FBitmap.Free;
  FBitmapItemTags.Free;
  inherited;
end;

{ TBitmapCollection }

constructor TBitmapCollection.Create(AOwner: TComponent);
begin
  inherited;
  FBitmaps := TBitmaps.Create(TBitmapItem);
end;

destructor TBitmapCollection.Destroy;
begin
  FBitmaps.Free;
  inherited;
end;

The Register procedure is implemented in the design-time unit and just calls the RegisterComponents procedure. And holds some lazy RegisterPropertyEditor tries that were to no avail.

If anyone can point me to the shortest path in order for the IDE to recognize the TBitmapItemTag TCollectionItem, I'd be grateful.

1

There are 1 best solutions below

5
On BEST ANSWER

You need to change TBitmaps to derive from TOwnedCollection instead of TCollection.

I also suggest defining explicit constructors for TBitmapItemTags and TBitmaps.

You also need to add some setter methods to your object-based properties, otherwise you risk memory leaks at runtime. Your setters should be calling Assign() on your objects to copy property values from one object to another. TCollection already implements Assign() for you, but you will have to implement Assign() in your collection items.

Try this:

type
  TBitmapItemTag = class(TCollectionItem)
  private
    FTagName: string;
    FTagFloat: Single;
  public
    procedure Assign(ASource: TPersistent); override;
  published
    property TagName: string read FTagName write FTagName;
    property TagFloat: Single read FTagFloat write FTagFloat;
  end;

  TBitmapItem = class;

  TBitmapItemTags = class(TOwnedCollection)
  public
    constructor Create(AOwner: TBitmapItem); reintroduce;
  end;

  TBitmapItem = class(TCollectionItem)
  private
    FBitmap: TBitmap;
    FTags: TBitmapItemTags;
    procedure SetBitmap(AValue: TBitmap);
    procedure SetTags(AValue: TBitmapItemTags);
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(ASource: TPersistent); override;
  published
    property Bitmap: TBitmap read FBitmap write SetBitmap;
    property Tags: TBitmapItemTags read FTags write SetTags;
  end;

  TBitmapCollection = class;

  TBitmaps = class(TOwnedCollection)
  public
    constructor Create(AOwner: TBitmapCollection); reintroduce;
  end;

  TBitmapCollection = class(TComponent)
  private
    FBitmaps: TBitmaps;
    procedure SetBitmaps(AValue: TBitmaps);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Bitmaps: TBitmaps read FBitmaps write SetBitmaps;
  end;

{ TBitmapTagItem }

procedure TBitmapItemTag.Assign(ASource: TPersistent);
begin
  if ASource is TBitmapItemTag then
  begin
    FTagName := TBitmapItemTag(ASource).TagName;
    FTagFloat := TBitmapItemTag(ASource).TagFloat;
  end
  else
    inherited;
end;

{ TBitmapItemTags }

constructor TBitmapItemTags.Create(AOwner: TBitmapItem);
begin
  inherited Create(AOwner, TBitmapItemTag);
end;

{ TBitmapItem }

constructor TBitmapItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FBitmap := TBitmap.Create(0, 0);
  FTags := TBitmapItemTags.Create(Self);
end;

destructor TBitmapItem.Destroy;
begin
  FBitmap.Free;
  FTags.Free;
  inherited;
end;

procedure TBitmapItem.Assign(ASource: TPersistent);
begin
  if ASource is TBitmapItem then
  begin
    FBitmap.Assign(TBitmapItem(ASource).Bitmap);
    FTags.Assign(TBitmapItem(ASource).Tags);
  end
  else
    inherited;
end;

procedure TBitmapItem.SetBitmap(AValue: TBitmap);
begin
  FBitmap.Assign(AValue);
end;

procedure TBitmapItem.SetTags(AValue: TBitmapItemTags);
begin
  FTags.Assign(AValue);
end;

{ TBitmaps }

constructor TBitmaps.Create(AOwner: TBitmapCollection);
begin
  inherited Create(AOwner, TBitmapItem);
end;

{ TBitmapCollection }

constructor TBitmapCollection.Create(AOwner: TComponent);
begin
  inherited;
  FBitmaps := TBitmaps.Create(Self);
end;

destructor TBitmapCollection.Destroy;
begin
  FBitmaps.Free;
  inherited;
end;

procedure TBitmapCollection.SetBitmaps(AValue: TBitmaps);
begin
  FBitmaps.Assign(AValue);
end;