2016-07-21 16 views
1

プロパティとしてサイズの異なる複数のTImageを挿入できるVCLコンポーネントを作成しようとしています。 私はTObjectList(Delphi component with a variable amount of TPictures)を一番よく使うように言われましたが、今は、プロパティエディタで単一のTPi​​cturesをに割り当てることに苦労しています。delphiコンポーネントのプロパティ:TObjectList <TPicture>

私は現時点で持っているもの:どのような動作しないことのPropertyEditorで最終的な結果である

unit ImageMultiStates; 

interface 

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

type 

    TImageMultiStates = class(TImage) 
    private 
    FPictures: TObjectList<TPicture>; 
    procedure SetPicture(Which: Integer; APicture: TPicture); 
    function GetPicture(Which: Integer): TPicture; 
    public 
    Count: integer; 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    procedure Activate(Which: Integer); 
    published 
    // property Pictures: TObjectList<TPicture> read GetPicture write SetPicture; 
    // property Pictures[Index: Integer]: TObjectList<TPicture> read GetPicture write SetPicture; 
    property Pictures: TObjectList<TPicture> read FPictures write FPictures; 
    end; 

procedure Register; 

implementation 

constructor TImageMultiStates.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    FPictures := TObjectList<TPicture>.Create; 
end; 

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

procedure TImageMultiStates.SetPicture(Which: Integer; APicture: TPicture); 
begin 
    FPictures[Which] := APicture; 
    if Which=0 then 
    Picture.Assign(APicture); 
end; 

function TImageMultiStates.GetPicture(Which: Integer): TPicture; 
begin 
    Result := FPictures[Which]; 
end; 

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

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

end. 

(それがコンパイルされます)。値 "(TObjectList)"を持つ "Pictures"という1つの項目が表示されます。それをクリックすると何もしない、私は適切なエディタを取得しません。 最初のものはコンパイラエラー "E2008 Incompatible Types"をスローし、もう1つは "Publishedプロパティ 'Pi​​ctures'をタイプARRAYにすることはできません。

+1

は、より多くのこのような何かを試してみてください。代わりにTOwnedCollectionを使用しているだけでなく、ストリーミングシステムがどのように処理するのか知っている理由はありますか?また、パブリッシュされたプロパティは配列型ではありません。 getter/setterでは* public *配列プロパティを持つことができますが、* published *ではできません。 –

+0

前の質問へのコメントで述べたようなコレクションを使用する必要があります –

+0

複雑さを避けるためにTObjectListの提案が好きでした。さて、次のアプローチはコレクションから始まります。乾杯! – hzzmj

答えて

0

IDEは設計時にTObjectListを編集する方法を知らず、DFMストリーミングシステムはTObjectListをストリームする方法を知らない。カスタムプロパティエディタとカスタムストリーミングロジックを実装する必要があります。それは確かに可能ですが、それは多くの仕事です。

あなたがしようとしているのは、代わりにSystem.Classes.TCollectionを使用してください。 IDEおよびDFMストリーミングシステムには、TCollectionを自動的に処理してストリーミングするためのビルトインサポートが組み込まれています。私はあなたがパブリッシュプロパティ(私はところで、いずれか、することはできませんわからない)としてジェネリックを使用することができるかわからない

unit ImageMultiStates; 

interface 

uses 
    System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.Graphics; 

type 
    TImagePictureItem = class(TCollectionItem) 
    private 
    FPicture: TPicture; 
    procedure PictureChanged(Sender: TObject); 
    procedure SetPicture(Value: TPicture); 
    public 
    constructor Create(Collection: TCollection); override; 
    destructor Destroy; override; 
    published 
    property Picture: TPicture read FPicture write SetPicture; 
    end; 

    TImagePictureEvent = procedure(Sender: TObject; Index: Integer) of object; 

    TImagePictures = class(TOwnedCollection) 
    private 
    FOnPictureChange: TImagePictureEvent; 
    function GetPicture(Index: Integer): TImagePictureItem; 
    procedure SetPicture(Index: Integer; Value: TImagePictureItem); 
    protected 
    procedure Update(Item: TCollectionItem); override; 
    public 
    constructor Create(Owner: TComponent); reintroduce; 
    property Pictures[Index: Integer]: TImagePictureItem read GetPicture write SetPicture; default; 
    property OnPictureChange: TImagePictureEvent read FOnPictureChange write FOnPictureChange; 
    end; 

    TImageMultiStates = class(TImage) 
    private 
    FActivePicture: Integer; 
    FPictures: TImagePictures; 
    function GetPicture(Index: Integer): TPicture; 
    procedure PictureChanged(Sender: TObject; Index: Integer); 
    procedure SetActivePicture(Index: Integer); 
    procedure SetPicture(Index: Integer; Value: TPicture); 
    procedure SetPictures(Value: TImagePictures); 
    protected 
    procedure Loaded; override; 
    public 
    constructor Create(Owner: TComponent); override; 
    function Count: integer; 
    property Pictures[Index: Integer]: TPicture read GetPicture write SetPicture; 
    published 
    property ActivePicture: Integer read FActivePicture write SetActivePicture default -1; 
    property Picture stored False; 
    property Pictures: TImagePictures read FPictures write SetPictures; 
    end; 

procedure Register; 

implementation 

{ TImagePictureItem } 

constructor TImagePictureItem.Create(Collection: TCollection); 
begin 
    inherited Create(Collection); 
    FPicture := TPicture.Create; 
    FPicture.OnChange := PictureChanged; 
end; 

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

procedure TImagePictureItem.PictureChanged(Sender: TObject); 
begin 
    Changed(False); 
end; 

procedure TImagePictureItem.SetPicture(Value: TPicture); 
begin 
    FPicture.Assign(Value); 
end; 

{ TImagePictures } 

constructor TImagePictures.Create(Owner: TComponent); 
begin 
    inherited Create(Owner, TImagePictureItem); 
end; 

function TImagePictures.GetPicture(Index: Integer): TImagePictureItem; 
begin 
    Result := TImagePictureItem(inherited GetItem(Index)); 
end; 

procedure TImagePictures.SetPicture(Index: Integer; Value: TImagePictureItem); 
begin 
    inherited SetItem(Index, Value); 
end; 

procedure TImagePictures.Update(Item: TCollectionItem); 
begin 
    if Assigned(FOnPictureChange) then 
    begin 
    if Item <> nil then 
     FOnPictureChange(Self, Item.Index) 
    else 
     FOnPictureChange(Self, -1); 
    end; 
end; 

{ TImageMultiStates } 

constructor TImageMultiStates.Create(Owner: TComponent); 
begin 
    inherited Create(Owner); 
    FPictures := TImagePictures.Create(Self); 
    FPictures.OnPictureChange := PictureChanged; 
    FActivePicture := -1; 
end; 

procedure TImageMultiStates.Loaded; 
begin 
    inherited; 
    PictureChanged(nil, FActivePicture); 
end; 

function TImageMultiStates.Count: Integer; 
begin 
    Result := FPictures.Count; 
end; 

procedure TImageMultiStates.PictureChanged(Sender: TObject; Index: Integer); 
begin 
    if (FActivePicture <> -1) and ((Index = -1) or (Index = FActivePicture)) then 
    Picture.Assign(GetPicture(FActivePicture)); 
end; 

function TImageMultiStates.GetPicture(Index: Integer): TPicture; 
begin 
    Result := FPictures[Index].Picture; 
end; 

procedure TImageMultiStates.SetPicture(Index: Integer; Value: TPicture); 
begin 
    FPictures[Index].Picture.Assign(Value); 
end; 

procedure TImageMultiStates.SetActivatePicture(Value: Integer); 
begin 
    if FActivePicture <> Value then 
    begin 
    if ComponentState * [csLoading, csReading] = [] then 
     Picture.Assign(GetPicture(Value)); 
    FActivePicture := Value; 
    end; 
end; 

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

    // the inherited TImage.Picture property is published, and you cannot 
    // decrease the visibility of an existing property. However, if you move 
    // this procedure into a separate design-time package, you can then use 
    // DesignIntf.UnlistPublishedProperty() to hide the inherited 
    // Picture property at design-time, at least: 
    // 
    // UnlistPublishedProperty(TImageMultiStates, 'Picture'); 
    // 
    // Thus, users are forced to use the TImageMultiStates.Pictures and 
    // TImageMultiStates.ActivePicture at design-time. The inherited 
    // Picture property will still be accessible in code at runtime, though... 
end; 

end. 
関連する問題