2013-05-29 45 views
7

Tôi đang cố gắng sử dụng một mảng của một lớp tùy chỉnh làm thuộc tính cho thành phần của tôi, nhưng vấn đề là các giá trị không được lưu vào thành phần, điều đó có nghĩa là nếu tôi đặt các giá trị, tiết kiệm tất cả mọi thứ và mở lại dự án, các giá trị cho các thành phần biến mất ... mã của tôi trông giống như sau:Mảng của một lớp tùy chỉnh là thuộc tính

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. 

tôi biết rằng rằng tài sản chỉ được công bố có thể được xem trực tiếp, nhưng vấn đề là tài sản của tôi là một mảng và nó không thể được xuất bản ... Một gợi ý mà tôi đã sử dụng là DefineProperties() để cung cấp luồng tùy chỉnh nhưng tôi không thấy cách làm điều này với một mảng. Khả năng khác mà tôi nghĩ là sửa đổi TMyClass thành một loại lớp mà TMyComponent có thể là cha mẹ của nó, giống như nó được thực hiện trong TChart, bạn có thể thêm các lớp khác nhau của chuỗi vào nó. Nhưng tôi không biết lớp Điều này nên

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

Với rằng tôi có thể đưa ra các myArray tài sản và tạo TMyClass và thêm vào TMyComponent như sau:

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

. Lựa chọn nào tốt hơn? Hay có ý tưởng nào khác tốt hơn?

Trả lời

14

Các đơn giản nhất (và ưa thích) giải pháp là thay đổi TMyClass để lấy được từ TCollectionItem và thay đổi TMyComponent.FMyArray-TOwnedCollection. Sau đó, DFM sẽ truyền các mục tự động cho bạn, và bạn có được hỗ trợ thiết kế thời gian bản địa để tạo và thao tác các đối tượng TMyClass và các thuộc tính của chúng.

Hãy thử điều này:

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

Tôi đã thử nghiệm phiên bản này và nó hoạt động tốt, tôi chỉ cần kiểm tra trong mã thực sự của tôi mà là một chút phức tạp hơn, cảm ơn rất nhiều – Felipe

+0

Đã tìm kiếm điều tương tự. Câu trả lời tuyệt vời từ Remy, cảm ơn bạn rất nhiều. –

5

Tôi muốn bỏ phiếu cho DefineProperties! Mã cần thiết có thể trông như thế này (giả sử không ai trong số các trường hợp trong mảng là con số không):

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

tôi có một lỗi: [DCC Lỗi] MyComponentTest1.pas (155): E2362 Không thể truy cập biểu tượng bảo vệ TReader.ReadProperty Và điều tương tự cho WriteProperties – Felipe

+1

Thật vậy! Tôi quên rằng tôi đã có một người trợ giúp lớp trong phạm vi đã làm điều đó. Đã cập nhật câu trả lời. –

+0

Vẫn không có được mục tiêu của tôi .. Tôi kiểm tra các hình thức dưới dạng văn bản và tôi đã nhận rằng: 'đối tượng MyComponent1: TMyComponent Left = 160 Top = 181 Width = 185 Height = 41 myArray = ( ()) ' – Felipe

Các vấn đề liên quan