2010-05-21 10 views
3

Я хочу сделать компонент, который включает в себя список целых чисел в качестве одного из его сериализованных свойств. Я знаю, что не могу объявить TList<integer> как , опубликованное, потому что оно не спускается с TPersistent. Я читал, что вы можете определить «поддельные» опубликованные свойства, если переопределить DefineProperties, но я не совсем уверен, как это работает, особенно когда дело доходит до создания поддельного свойства, которое является списком, а не для одного значения.Как опубликовать список целых чисел?

Может кто-нибудь указать мне в правильном направлении?

+0

Что смысл целых чисел? Если они каким-то образом связаны с экземплярами компонентов в форме, вы можете сделать что-то подобное, например, TGridPanel, например. ColumnSpan. –

ответ

5

Вот минимальный пример с DefineBinaryProperty (написанными на D2007, нет дженериков):

type 
    TTestComponent = class(TComponent) 
    private 
    FList: TList; 

    function GetValueCount: Integer; 
    function GetValues(Index: Integer): Integer; 
    procedure ReadValueList(Stream: TStream); 
    procedure SetValues(Index: Integer; Value: Integer); 
    procedure WriteValueList(Stream: TStream); 
    protected 
    procedure DefineProperties(Filer: TFiler); override; 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 

    function AddValue(Value: Integer): Integer; 
    procedure ClearValues; 
    procedure DeleteValue(Index: Integer); 

    property ValueCount: Integer read GetValueCount; 
    property Values[Index: Integer]: Integer read GetValues write SetValues; 
    end; 

{ TTestComponent } 

function TTestComponent.GetValueCount: Integer; 
begin 
    Result := FList.Count; 
end; 

function TTestComponent.GetValues(Index: Integer): Integer; 
begin 
    Result := Integer(FList[Index]); 
end; 

procedure TTestComponent.ReadValueList(Stream: TStream); 
var 
    Count, I, Value: Integer; 
begin 
    ClearValues; 
    Stream.Read(Count, SizeOf(Count)); 
    for I := 0 to Count - 1 do 
    begin 
    Stream.Read(Value, SizeOf(Value)); 
    AddValue(Value); 
    end; 
end; 

procedure TTestComponent.SetValues(Index: Integer; Value: Integer); 
begin 
    FList[Index] := Pointer(Value); 
end; 

procedure TTestComponent.WriteValueList(Stream: TStream); 
var 
    Count, I, Value: Integer; 
begin 
    Count := ValueCount; 
    Stream.Write(Count, SizeOf(Count)); 
    for I := 0 to Count - 1 do 
    begin 
    Value := Values[I]; 
    Stream.Write(Value, SizeOf(Value)); 
    end; 
end; 

procedure TTestComponent.DefineProperties(Filer: TFiler); 
begin 
    inherited DefineProperties(Filer); 
    Filer.DefineBinaryProperty('ValueList', ReadValueList, WriteValueList, ValueCount > 0); 
end; 

constructor TTestComponent.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    FList := TList.Create; 
    // add some values for testing 
    AddValue(0); 
    AddValue(1); 
    AddValue(2); 
end; 

destructor TTestComponent.Destroy; 
begin 
    FList.Free; 
    inherited Destroy; 
end; 

function TTestComponent.AddValue(Value: Integer): Integer; 
begin 
    Result := FList.Add(Pointer(Value)); 
end; 

procedure TTestComponent.ClearValues; 
begin 
    FList.Clear; 
end; 

procedure TTestComponent.DeleteValue(Index: Integer); 
begin 
    FList.Delete(Index); 
end; 

и .dfm выглядит следующим образом:

object TestComponent1: TTestComponent 
    Left = 96 
    Top = 56 
    ValueList = {03000000000000000100000002000000} 
    end 
+0

Спасибо, это то, что мне нужно. –

+0

+1 отличное решение @TOndrej – RRUZ

1

Самый быстрый и простой способ сделать это - использовать TCollection, но вы заплатите цену за «украшение» каждого целого Integer классом TCollectionItem! Если нет целых чисел, это путь, потому что вы получаете интеграцию Object Inspector практически бесплатно (бесплатно, так как в течение небольшого количества дополнительных часов работы).

Если вы хотите сохранить свой список в текущей, высокоэффективной форме (TList), тогда вы правы, то есть способ определить свою собственную собственность. Посмотрите в подразделе Graphics.pas, как реализуется TPicture.DefineProperties, потому что это очень близкое соответствие с тем, что вам нужно!

Идея: Если вы идете по маршруту DefineProperties, вы можете посмотреть в RegisterComponentEditor, потому что ваш список Integer не будет виден в Object Inspector!

Смежные вопросы