2016-07-21 21 views
1

Ich versuche, eine VCL-Komponente zu erstellen, mit der Sie mehrere TImages verschiedener Größen als Eigenschaften einfügen können. Mir wurde gesagt, am besten eine TObjectList (Delphi component with a variable amount of TPictures) zu verwenden, aber jetzt habe ich Mühe, die einzelnen TPictures im Eigenschafteneditor zuweisbar zu machen.Delphi Komponente Eigenschaft: TObjectList <TPicture>

Was ich im Moment haben: (kompiliert)

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. 

Was nicht funktioniert das Endergebnis in der Property ist. Es zeigt ein einzelnes Element namens "Bilder" mit dem Wert "(TObjectList)". Wenn ich darauf klicke, habe ich keinen richtigen Editor. Andere Ideen für die fragliche Zeile wurden auskommentiert, sie bringen andere Fehler: Die erste wirft den Compilerfehler "E2008 Incompatible Types", der zweite wirft "Published property 'Pictures' kann nicht vom Typ ARRAY sein".

+1

Ich bin nicht sicher, Sie Generika veröffentlichten Eigenschaften verwenden können (ich bin nicht sicher, Sie können nicht, entweder, BTW). Gibt es einen Grund, warum Sie nicht einfach eine TOwnedCollection verwenden, mit der das Streaming-System umgehen kann? Und eine veröffentlichte Eigenschaft kann nicht vom Typ array sein; Sie können eine * public * -Array-Eigenschaft mit Getter/Setter haben, aber nicht * veröffentlicht *. –

+0

Sie sollten eine Sammlung verwenden, wie ich in den Kommentaren zu Ihrer vorherigen Frage –

+0

Ich mochte den Vorschlag einer TObjectList, um Komplexität zu vermeiden. Okay, der nächste Ansatz beginnt mit einer Sammlung. Prost! – hzzmj

Antwort

0

Die IDE hat keine Ahnung, wie man eine TObjectList zur Entwurfszeit bearbeitet, und das DFM-Streaming-System hat keine Ahnung, wie man eine TObjectList streamen. Sie müssten einen benutzerdefinierten Eigenschaftseditor und eine benutzerdefinierte Streaming-Logik implementieren. Das ist sicherlich möglich, es ist eine Menge Arbeit.

Was Sie zu tun versuchen, wird besser mit System.Classes.TCollection stattdessen behandelt. Sowohl das IDE- als auch das DFM-Streaming-System verfügen über eine integrierte Unterstützung für die Bearbeitung und das automatische Streamen von TCollection.

Versuchen Sie, etwas mehr wie folgt aus:

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.