2013-05-29 15 views
7

Ich versuche, ein Array einer benutzerdefinierten Klasse als eine Eigenschaft für meine Komponente zu verwenden, aber das Problem ist, dass die Werte nicht in der Komponente gespeichert wurden, das heißt, wenn ich gesetzt die Werte, alles speichern und wieder öffnen Sie das Projekt, um die Werte für die Komponente ... Mein Code verschwindet sieht wie folgt aus:Array einer benutzerdefinierten Klasse als Eigenschaft

unit Unit1; 

interface 

uses Windows, ExtCtrls,Classes,Controls; 

type 

    TMyClass=class(TPersistent) 
    private 
    FName: string; 
    FValue: double; 
    public 
    property Name: string read FName write FName; 
    property Value: double read FValue write FValue; 
    end; 

    TMyComponent= class(TCustomPanel) 
    private 
    FMyArray: array[0..200] of TMyClass; 

    function GetmyArray(Index: Integer): TMyClass; 

    procedure SetMyArray(index: Integer; Value: TMyClass); 
    public 
    property myArray[index: Integer]: TMyClass read GetMyArray write SetMyArray; 
    end; 

implementation 

function TMyComponent.GetmyArray(Index: Integer): TMyClass; 
begin 
    result:= FmyArray[Index]; 
end; 

procedure TMyComponent.SetMyArray(index: Integer; Value: TMyClass); 
begin 
    FMyArray[index].FName:= Value.FName; 
    FMyArray[index].FValue:= Value.FValue; 
end; 

end. 

ich weiß, dass nur die veröffentlichten Eigenschaften gestreamt werden können, aber das Problem ist, dass meine Eigenschaft ist ein Array und es kann nicht veröffentlicht werden ... Ein Vorschlag, den ich hatte, war, DefineProperties() zu verwenden, um ein kundenspezifisches streaming zu liefern, aber ich sehe nicht, wie man das mit einem Array tut. Andere Möglichkeit, die ich dachte, war, TMyClass zu einer Art von Klasse zu ändern, die TMyComponent könnte das Elternteil davon sein, wie es in TChart getan wird, dem Sie verschiedene Klassen von Serien hinzufügen können. Aber ich weiß nicht, was Klasse dies, dass sein sollte

TMyClass=class(T???????????) 

Mit mir die Eigenschaft MyArray nehmen könnte und TMyClass erstellen und zu TMyComponent wie die folgenden hinzu:

MyArray1.parent:= MyComponent1; 
MyArray2.parent:= MyComponent2; 
... 

. Welches ist die bessere Option? Oder gibt es eine andere bessere Idee?

Antwort

14

Die einfachste (und bevorzugt) Lösung ist TMyClass Änderungen von TCollectionItem und ändern TMyComponent.FMyArray-TOwnedCollection abzuleiten. Dann streamt der DFM die Objekte automatisch für Sie und Sie erhalten native Design-Time-Unterstützung für das Erstellen und Bearbeiten von TMyClass Objekten und deren Eigenschaften.

Try this:

unit Unit1; 

interface 

uses 
    Windows, ExtCtrls, Classes, Controls; 

type 
    TMyClass = class(TCollectionItem) 
    private 
    FName: string; 
    FValue: double; 

    procedure SetName(const AValue: string); 
    procedure SetValue(AValue: double); 
    public 
    procedure Assign(ASource: TPersistent); override; 
    published 
    property Name: string read FName write SetName; 
    property Value: double read FValue write SetValue; 
    end; 

    TMyArray = class(TOwnedCollection) 
    private 
    function GetItem(Index: Integer): TMyClass; 
    procedure SetItem(Index: Integer; const Value: TMyClass); 
    public 
    constructor Create(AOwner: TPersistent); 
    function Add: TMyClass; reintroduce; 
    function Insert(Index: Integer): TMyClass; reintroduce; 
    property Items[Index: Integer]: TMyClass read GetItem write SetItem; default; 
    end; 

    TMyComponent = class(TCustomPanel) 
    private 
    FMyArray: TMyArray; 

    procedure SetMyArray(Value: TMyArray); 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    published 
    property myArray: TMyArray read FMyArray write SetMyArray; 
    end; 

implementation 

procedure TMyClass.Assign(ASource: TPersistent); 
begin 
    if ASource is TMyClass then 
    begin 
    with TMyClass(ASource) do 
    begin 
     Self.FName := Name; 
     Self.FValue := Value; 
    end; 
    Changed(False); 
    end else 
    inherited; 
end; 

procedure TMyClass.SetName(const AValue: string); 
begin 
    if FName <> AValue then 
    begin 
    FName := AValue; 
    Changed(False); 
    end; 
end; 

procedure TMyClass.SetValue(AValue: double); 
begin 
    if FValue <> AValue then 
    begin 
    FValue := AValue; 
    Changed(False); 
    end; 
end; 

constructor TMyArray.Create(AOwner: TPersistent); 
begin 
    inherited Create(AOwner, TMyClass); 
end; 

function TMyArray.GetItem(Index: Integer): TMyClass; 
begin 
    Result := TMyClass(inherited GetItem(Index)); 
end; 

procedure TMyArray.SetItem(Index: Integer; const Value: TMyClass); 
begin 
    inherited SetItem(Index, Value); 
end; 

function TMyArray.Add: TMyClass; 
begin 
    Result := TMyClass(inherited Add); 
end; 

function TMyArray.Insert(Index: Integer): TMyClass; 
begin 
    Result := TMyClass(inherited Insert(Index)); 
end; 

constructor TMyComponent.Create(AOwner: TComponent); 
begin 
    inherited; 
    FMyArray := TMyArray.Create(Self); 
end; 

destructor TMyComponent.Destroy; 
begin 
    FMyArray.Free; 
    inherited; 
end; 

procedure TMyComponent.SetMyArray(Value: TMyArray); 
begin 
    FMyArray.Assign(Value); 
end; 

end. 
+0

Ich habe diese Version getestet und es funktioniert gut, ich muss nur in meinem echten Code testen, der ein bisschen komplexer ist, vielen Dank – Felipe

+0

War auf der Suche nach der gleichen Sache. Tolle Antwort von Remy, vielen Dank. –

5

Ich würde für DefineProperties stimmen! Der notwendige Code wie dieser aussehen könnte (vorausgesetzt, keiner der Fälle in der Anordnung ist gleich Null):

procedure TMyComponent.DefineProperties(Filer: TFiler); 
begin 
    inherited; 
    Filer.DefineProperty('MyArray', ReadMyArray, WriteMyArray, true); 
end; 

procedure TMyComponent.ReadMyArray(Reader: TReader); 
var 
    N: Integer; 
begin 
    N := 0; 
    Reader.ReadListBegin; 
    while not Reader.EndOfList do begin 
    Reader.ReadListBegin; 
    FMyArray[N].Name := Reader.ReadString; 
    FMyArray[N].Value := Reader.ReadFloat; 
    Reader.ReadListEnd; 
    Inc(N); 
    end; 
    Reader.ReadListEnd; 
end; 

procedure TMyComponent.WriteMyArray(Writer: TWriter); 
var 
    I: Integer; 
begin 
    Writer.WriteListBegin; 
    for I := 0 to High(FMyArray) do begin 
    Writer.WriteListBegin; 
    Writer.WriteString(FMyArray[I].Name); 
    Writer.WriteFloat(FMyArray[I].Value); 
    Writer.WriteListEnd; 
    end; 
    Writer.WriteListEnd; 
end; 
+1

Ich habe einen Fehler: [DCC Error] MyComponentTest1.pas (155): E2362 Kein Zugriff auf geschützte Symbol TReader.ReadProperty Und das gleiche für WriteProperties – Felipe

+1

der Tat! Ich vergaß, dass ich einen Klassenhelfer im Umfang hatte, der das Ding tat. Die Antwort wurde aktualisiert. –

+0

Noch nicht mein Ziel bekommen .. Ich überprüfe das Formular als Text, und ich habe das: 'Objekt MyComponent1: TMyComponent Links = 160 Top = 181 Width = 185 Höhe = 41 MyArray = ( ()) ' – Felipe

Verwandte Themen