Как опубликовать список целых чисел? - PullRequest
3 голосов
/ 21 мая 2010

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

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

Ответы [ 2 ]

5 голосов
/ 21 мая 2010

Вот минимальный пример с 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
1 голос
/ 21 мая 2010

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

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

Идея: если вы пойдете по маршруту «DefineProperties», возможно, вы захотите заглянуть в RegisterComponentEditor, поскольку ваш список целых чисел не будет виден в Инспекторе объектов!

...