2013-05-29 19 views
7

Próbuję użyć tablicy niestandardowej klasy jako właściwości dla mojego komponentu, ale problem polega na tym, że wartości nie zostały zapisane w komponencie, co oznacza, że ​​jeśli ustawię wartości, zapisać wszystko i otwórz ponownie projektu, wartości składnik znika ... Mój kod wygląda następująco:Tablica niestandardowej klasy jako własności

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. 

wiem, że tylko opublikowane właściwości mogą być przesyłane strumieniowo, ale problemem jest to, że moja własność jest tablicą i nie można jej opublikować ... Sugestię, że miałem używać DefineProperties(), aby zapewnić niestandardowe przesyłanie strumieniowe, ale nie widzę, jak to zrobić z tablicą. Inną możliwością, o której myślałem, było zmodyfikowanie TMyClass na rodzaj klasy, w której TMyComponent może być jej rodzicem, tak jak robi to TChart, do którego można dodać różne klasy serii. Ale ja nie wiem, co klasa to powinno być

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

Dzięki, że mogę wyjąć MyArray nieruchomości i stworzyć TMyClass i dodać do TMyComponent jak:

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

. Która z nich jest lepszą opcją? Czy jest jakiś inny lepszy pomysł?

Odpowiedz

14

Najprostszy (i korzystnie) roztwór jest zmiana TMyClass uzyskać z TCollectionItem i zmiany TMyComponent.FMyArray do TOwnedCollection. Następnie moduł DFM automatycznie rozpocznie przesyłanie strumieniowe elementów, a ponadto uzyskasz wsparcie w zakresie projektowania w czasie rzeczywistym w celu tworzenia obiektów i ich właściwości oraz manipulowania nimi.

Spróbuj tego:

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

Przetestowałem tę wersję i działa dobrze, po prostu muszę przetestować w moim prawdziwym kodzie, który jest nieco bardziej złożony, dzięki bardzo dużo – Felipe

+0

Szukałem tego samego. Świetna odpowiedź od Remy'ego, dziękuję bardzo. –

5

Głosowałbym na DefineProperties! Niezbędna kod może wyglądać następująco (przy założeniu, że żaden z tych przypadkach w tablicy wynosi zero)

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

mam błąd: [DCC Error] MyComponentTest1.pas (155): E2362 nie można uzyskać dostępu do chronionego symbolu TReader.ReadProperty i to samo dla WriteProperties – Felipe

+1

rzeczywiście! Zapomniałem, że mam pomocnika klasy w zakresie, który to zrobił. Zaktualizowano odpowiedź. –

+0

Nadal nie dostać mój cel .. sprawdzić formę jako tekst i mam to: 'obiektu MyComponent1: TMyComponent lewy = 160 Top = 181 Szerokość = 185 Wysokość = 41 MyArray = ( ()) ' – Felipe

Powiązane problemy