How to publish a list of integers?

I want to create a component that includes a list of integers as one of its serialized properties. I know that I cannot declare TList<integer>as a published property , because it does not descend from TPersistent. I read that you can define “fake” published properties by overriding DefineProperties, but I'm not quite sure how this works, especially when it comes to creating a fake property, not just a single value.

Can someone point me in the right direction?

+3
source share
2 answers

Here's a minimal example with DefineBinaryProperty(written in D2007, without generics):

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;

and .dfm looks like this:

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

The fastest and easiest way to do this is to use TCollection - but you will pay the price to "decorate" each Integer with the TCollectionItem class! If there aren’t many integers, this is the way to go, because you get Object Inspector integration almost for free (for free, like for a little extra hours of work).

If you want to keep your list in a current, high-performance form (TList), then you are right, the way is to define your own property. Look in the Graphics.pas subsection how TPicture.DefineProperties is implemented, because it is very close matching with what you need!

: DefineProperties, RegisterComponentEditor, Integer Object Inspector!

+1

Source: https://habr.com/ru/post/1746505/


All Articles