Delphi component design - get property from component from subproperty

1.1k views Asked by At

I'm making a Delphi vcl component, the component class has a 'images' property which lets me select a TImagelist.

The component class also has a subproperty 'buttons' which itself has a imageindex property.

I have written a component editor for the imageindex property so that i can select a image on the buttons from the imagelist; i have done this in other components before but the problem i'm facing now is that i need to get the images property of the base class from the event in the 'buttons' subclass event.

So, the base class of the component has these properties:

property Buttons: TFlexButtons read FButtons write FButtons;
property Images: TCustomImageList read FImages write SetImages;

The buttons class has this property:

property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;

I register a property editor in a seperate unit for the ImageIndex property, in order to pick a image but in this event i need to get the imagelist from the baseclass of the component, how do i get this property from this sub property?

function TImageIndexProperty.GetImageListAt(Index: Integer): TCustomImageList;
var APersistent: TPersistent;
begin
  APersistent := GetComponent(Index);
  if APersistent is TFlexButton then
    Result := ??????????.Images //how do i refer to the images property of the component here?
  else
    Result := nil;
end;

All classes:

TFlexButton = class(TCollectionItem)
private
  FWidth: Word;
  FCaption: string;
  FHeight: Word;
  FImageIndex: TImageIndex;
  procedure SetCaption(const Value: string);
  procedure SetHeight(const Value: Word);
  procedure SetWidth(const Value: Word);
  procedure SetImageIndex(const Value: TImageIndex);
public
  constructor Create(AOwner: TComponent);
  destructor Destroy; override;
published
  property Caption: string read FCaption write SetCaption;
  property Height: Word read FHeight write SetHeight;
  property Width: Word read FWidth write SetWidth;
  property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
end;

TFlexButtons = class(TCollection)
private
  function GetItem(Index: Integer): TFlexButton;
public
  function Add: TFlexButton;
  property Item[index: Integer]: TFlexButton read GetItem;
end;

TFlexButtonGroupBox = class(TcxGroupBox)
private
  FDataLink: TFieldDataLink;
  FAbout: string;
  FAlignment: TAlignment;
  FEnabled: Boolean;
  FButtons: TFlexButtons;
  FImages: TCustomImageList;
  FSql: TStrings;
  FAutosize: Boolean;
  procedure SetAlignment(const Value: TAlignment);
  function GetDataField: string;
  function GetDataSource: TdataSource;
  procedure SetDataField(const Value: string);
  procedure SetDataSource(const Value: TdataSource);
  procedure DataChange(Sender: TObject);
  procedure SetEnabled(const Value: Boolean);
  procedure SetImages(const Value: TCustomImageList);
  procedure SetSql(const Value: TStrings);
  procedure SetAutosize(const Value: Boolean);
protected
public
  procedure Loaded; override;
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
published
  property DataField: string read GetDataField write SetDataField;
  property DataSource: TdataSource read GetDataSource write SetDataSource;
  property Enabled: Boolean read FEnabled write SetEnabled;
  property Autosize: Boolean read FAutosize write SetAutosize;
  property About: string read FAbout write FAbout;
  property Buttons: TFlexButtons read FButtons write FButtons;
  property Images: TCustomImageList read FImages write SetImages;
  property Alignment: TAlignment read FAlignment write SetAlignment;
  property Sql: TStrings read FSql write SetSql;
end;
1

There are 1 answers

1
Remy Lebeau On BEST ANSWER

When exposing a collection at design time, use TOwnedCollection instead of TCollection directly. This facilitates DFM streaming without having to write extra code to enable it.

TCollectionItem has a Collection property, which in turn has an Owner method that TOwnedCollection implements. This way, you can get from a button to its owning group box in code.

Try this:

TFlexButton = class(TCollectionItem)
private
  ...
public
  constructor Create(ACollection: TCollection); override;
end;

TFlexButtonGroupBox = class;

TFlexButtons = class(TOwnedCollection)
private
  ...
public
  constructor Create(AOwner: TFlexButtonGroupBox); reintroduce;
  ...
end;

TFlexButtonGroupBox = class(TcxGroupBox)
private
  ...
  procedure SetButtons(AValue: TFlexButtons;
public
  constructor Create(AOwner: TComponent); override;
  ...
published
  ...
  property Buttons: TFlexButtons read FButtons write SetButtons;
  ...
end;

constructor TFlexButton.Create(ACollection: TCollection);
begin
  inherited;
  ...
end;

constructor TFlexButtons.Create(AOwner: TFlexButtonGroupBox);
begin
  inherited Create(AOwner, TFlexButton);
  ...
end;

constructor TFlexButtonGroupBox.Create(AOwner: TComponent);
begin
  inherited;
  FButtons := TFlexButtons.Create(Self);
  ...
end;

procedure TFlexButtonGroupBox.SetButtons(AValue: TFlexButtons;
begin
  FButtons.Assign(AValue);
end;

function TImageIndexProperty.GetImageListAt(Index: Integer): TCustomImageList;
begin
  Result := ((GetComponent(Index) as TFlexButton).Collection.Owner as TFlexButtonGroupBox).Images;
end;