2016-07-21 23 views
0

Ich versuche, eine VCL-Komponente wie TImage zu erstellen, mit dem ich eine variable Menge von unterschiedlich großen TPictures hinzufügen kann. Ziel ist es, diese Anzahl von TPictures über den VCL-Editor in der Eigenschaftsliste zuweisen zu können.Delphi-Komponente mit einer Sammlung von TPictures

delphi component property: TObjectList<TPicture> hier kamen wir zu der Schlussfolgerung, dass eine TCollection mit TCollectionItems verwendet werden sollte. Das ist, was ich versuche jetzt zu tun, aber so oft, bevor ich mit dem Compiler-Fehler am Ende: in dieser Zeile „Veröffentlicht Eigenschaft‚Pictures‘nicht vom Typ ARRAY sein kann“: 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. 

Da niemand damit zu rechnen scheint, dass dieser Fehler ausgelöst wird, hängt das vielleicht mit meinen installierten Komponenten zusammen? Ich habe den internen GetIt Package-Manager verwendet, um die Jedi-Codebibliothek 2.8, Jedi Visual Component Library und PNGComponents 1.0 zu installieren. Ich denke, das ist so weit, was TImage-bezogene Komponenten betrifft. Vielleicht überschreibt eine dieser Dateien einige meiner TImage-Inhalte mit funky stuff ...

+0

Wenn Sie mehrere Bilder zur Entwurfszeit mit 'Objekt Inspector' wie Bearbeitung andere Eigenschaft zuweisen wollen, dann fürchte ich Dich nicht in der Lage sein, dies zu tun. Gut nicht direkt mit dem Objektinspektor. Was Sie tun müssen, ist Ihren eigenen benutzerdefinierten Eigenschaftseditor zu erstellen. Ich schlage vor, den Quellcode der 'TImageList'-Komponente zu überprüfen, um besser zu verstehen, wie es gemacht wird. – SilverWarior

+0

Es ist eine Weile her, seit ich es das letzte Mal benutzt habe, aber IIRC, so funktioniert TCollection nicht. Sehen Sie sich an, wie eine Statusleiste ihre Panels verwaltet oder wie ein Listview seine Spaltenüberschriften verwaltet. AFAIK verwenden beide Nachkommen von TCollection. –

+0

Eine nette Erklärung hier: http://www.atug.com/andypatterns/collections.htm#TCollectionMerits. Der beste Teil einer Tcollection ist, dass sie im Objektinspektor gut funktioniert und über einen Eigenschaftseditor verfügt, mit dem Sie Elemente hinzufügen können. –

Antwort

3

Ich experimentierte ein wenig und leitete eine TPicturePanel von TPanel. Es hat eine Eigenschaft, die eine TPictures ist, ein Nachkomme von TOwnedCollection und die TPics enthält. Jede TPic hat eine Picture Eigenschaft. Ich kann diese Komponente installieren, und es ermöglicht mir, die Pictures Sammlung mit dem so genannten Collection Editor zu bearbeiten, mit dem Sie TPic Instanzen hinzufügen oder entfernen können. Wenn Sie ein TPic im Sammlung Editor auswählen, können Sie ein Bild auf seine Picture Eigenschaft, das heißt Last von Datei zuweisen usw.

Hier ist der Arbeitscode für TPicturePanel. Sie können Ihre Komponente nach diesem Modell:

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. 
+0

Ich habe den genauen Code kopiert; Ich steige erstmal in den CollectionEditor ein, also ist es großartig. Abgesehen wirft es ein Fehler „TPIC kann nicht auf TPIC zugewiesen werden“ auf den Editor zu öffnen und ein Bild assgning, aber was zählt hier, dass ich die Augen auf einem Arbeitsbeispiel legen kann, die mich tatsächlich in die Sammlung Editor bringt. Danke vielmals! – hzzmj

+0

Hah! Basierend auf Ihrem Code habe ich den Editor für meine Komponente gestartet. Mit dem gleichen Fehler, dass TPIC nicht ist TPic.Assign obwohl – hzzmj

+0

Das Problem TPIC zugewiesen werden: wenn Sie es zuerst erben, ist der Zug weg, wenn Sie versuchen FPicture.Assign (TPIC (Quelle) .FPicture); So etwas wie "beginne, wenn Quelle ist TPic dann FPicture: = TPic (Quelle) .FPicture sonst geerbt; Ende;" macht den Job – hzzmj

0

Ihre indizierte Eigenschaft verwendet Syntax, die aussieht, als ob sie ein Array zurückgibt, aber das tut es nicht. Die pictures-Eigenschaft gibt eine indizierte TPic zurück. Es kann immer nur eine TPic gleichzeitig zurückgeben.

Wenn Sie ein Array zurückgeben möchten Sie so sagen:

function GetPictures: TArray<TPicture>; 
procedure SetPictures(const value: TArray<TPicture>); 
property Pictures: TArray<TPicture> read GetPictures write SetPictures; 

//GetPictures might look something like this: 
function TMyClass.GetPictures: TArray<TPicture>; 
var 
    i: integer; 
begin 
    SetLength(Result, Self.FPictureCount); 
    for i:= 0 to FPictureCount - 1 do begin 
    Result[i]:= GetMyPicture[i]; 
    end; 
end; 

Ich bin nicht sicher, wie Sie Ihre TPIC Sammlung funktioniert, so dass Sie es einstellen müssen, um werden an Ihre Bedürfnisse anzupassen.
Offensichtlich können Sie eine TArray<TArray<TPicture>> (aka: array of array of TPicture) haben, wenn Sie dies wünschen.

+0

Ich habe http://www.kadner-online.de/delphi/collection.html und http: // stackoverflow gefunden.com/Fragen/1050724/using-TOwnedCollection-Abkömmling-in-delphi, die beide scheinen erfolgreich ohne Arrays – hzzmj

+1

auch als 'Indexed properties' nur als public deklariert sind dafür bekannt, in beiden Fällen' Array properties' beteiligt diese Syntax zu verwenden und nicht veröffentlicht . Der Grund, warum 'Objekt Inspector' nicht in der Lage ist, mit dem veröffentlichten' Array properties' zu arbeiten, weil damit 'Objekt Inspector' sie manipulieren Sie zur Eingabe von zwei Parameter (Artikel-Index und Einzelteilwert) gleichzeitig müßten in der Lage sein Zeit. Oder anders ausgedrückt: Sie benötigen zwei Bearbeitungsfelder für diese Eigenschaft im Objektinspektor. – SilverWarior