1

I've a component for plot a spline, the argument for Spline procedure in an array of TPoint. Now, I want to create n dynamic array of TPoint, save this in a TList and after recall for plot the splines.

P.S. Delphi XE5

Example:

var
  l: TList;

procedure CreateSpline;
var i, x: byte;
    p: TPoint;
    a: array of TPoint;
begin
    l := TList.Create;

    for x := 0 to 9 do  // create 10 splines
    begin
        SetLength(a, Random(10) + 5);   Each spline has 5<n<15 points
        for i := 0 to High(a) do
        begin
            p.X := Random(200) - 100;   // X coord
            p.Y := Random(200) - 100;   // Y coord
            a[i] := p;                  // add point to array
        end;
        l.Add(a);                       // add array to TList
    end;
end;

procedure DrawSpline;
var i: byte;
    a: array of TPoint;
begin
    for i := 0 to 9 do
    begin
        a := l[i];
        xyPlot.Spline(a);  // Draw the spline (xyPlot is the graphic component)
    end;
end;

... and don't work. :-(

2
  • 2
    Instead of a TList, you should use a TList<TArray<TPoint>> (uses Generics.Collections). Commented Apr 24, 2020 at 15:41
  • Thanks, now is ok. Commented Apr 25, 2020 at 7:54

1 Answer 1

3

The non-Generic System.Classes.TList is just a container of raw pointers, it has no concept of what it holds. Dynamic arrays are reference-counted, and TList will not manage the reference counts for you, so you have to do it manually to ensure the reference counts are incremented while the arrays are in the list, eg:

ar
  l: TList;

procedure CreateSpline;
var
  i, x: byte;
  p: TPoint;
  a: TArray<TPoint>;
  aptr: Pointer;
begin
  l := TList.Create;

  for x := 0 to 9 do  // create 10 splines
  begin
    SetLength(a, Random(10) + 5);   // Each spline has 5<n<15 points
    for i := 0 to High(a) do
    begin
      p.X := Random(200) - 100;     // X coord
      p.Y := Random(200) - 100;     // Y coord
      a[i] := p;                    // add point to array
    end;
    TArray<TPoint>(aptr) := a;
    try
      l.Add(aptr);                  // add array to TList
    except
      TArray<TPoint>(aptr) := nil;
      raise;
    end;
    a := nil;
  end;
end;

{ alternatively:

procedure CreateSpline;
var
  i, x: byte;
  p: TPoint;
  a: TArray<TPoint>;
begin
  l := TList.Create;

  for x := 0 to 9 do  // create 10 splines
  begin
    SetLength(a, Random(10) + 5);   // Each spline has 5<n<15 points
    for i := 0 to High(a) do
    begin
      p.X := Random(200) - 100;     // X coord
      p.Y := Random(200) - 100;     // Y coord
      a[i] := p;                    // add point to array
    end;
    l.Add(Pointer(a));              // add array to TList
    Pointer(a) := nil;
  end;
end;
}

procedure DrawSpline;
var
  i: byte;
  a: TArray<TPoint>;
begin
  for i := 0 to 9 do
  begin
    a := TArray<TPoint>(l[i]);
    xyPlot.Spline(a);  // Draw the spline (xyPlot is the graphic component)
  end;
end;

...

// later, you need to decrement the refcounts before freeing/clearing the TList...

var
  i: byte;
  aptr: Pointer;
begin
  for i := 0 to 9 do
  begin
    aptr := l[i];
    TArray<TPoint>(aptr) = nil;
  end;
  l.Free;
end;

A better solution is to use the Generic System.Generics.Collections.TList<T> instead, where T is TArray<TPoint>. Then the reference counts will be managed properly for you, eg:

ar
  l: TList<TArray<TPoint>>;

procedure CreateSpline;
var
  i, x: byte;
  p: TPoint;
  a: TArray<TPoint>;
begin
  l := TList<TArray<TPoint>>.Create;

  for x := 0 to 9 do  // create 10 splines
  begin
    SetLength(a, Random(10) + 5);   // Each spline has 5<n<15 points
    for i := 0 to High(a) do
    begin
      p.X := Random(200) - 100;     // X coord
      p.Y := Random(200) - 100;     // Y coord
      a[i] := p;                    // add point to array
    end;
    l.Add(a);                       // add array to TList
  end;
end;

procedure DrawSpline;
var
  i: byte;
  a: TArray<TPoint>;
begin
  for i := 0 to 9 do
  begin
    a := l[i];
    xyPlot.Spline(a);  // Draw the spline (xyPlot is the graphic component)
  end;
end;

...

l.Free;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.