2

I have put in place very nice system to add Columns into VirtualStringTree, as the old system was just too bulky.

Old system:

procedure TForm1.Button1Click(Sender: TObject);
begin
    VST.Header.Columns.Clear;
    VST.Header.Columns.Add.Text:='#';
    VST.Header.Columns.Add.Text:='First name';
    VST.Header.Columns.Add.Text:='Last name';
    VST.Header.Columns.Add.Text:='Address';

    VST.Header.Columns[0].Width:=50;
    VST.Header.Columns[1].Width:=200;
    VST.Header.Columns[2].Width:=200;
    VST.Header.Columns[3].Width:=500;
end;

New system with 3 additional procedures, but much less code in executing them:

SetNames - sets column names in global array of string

SetWidths - sets column widhs in global array of integer

SetColumns - creates Columns based on global arrays values

var 
    gWidths:array of integer;
    gNames:array of string;

    procedure SetNames(vCount:integer; vA:string='';vB:string='';vC:string='';vD:string='';vE:string='';vF:string='';vG:string='';vH:string='';vI:string='';vJ:string='');
    begin
      SetLength(gNames,0);
      SetLength(gNames,vCount);
      If vCount>0 then gNames[0]:=vA;
      If vCount>1 then gNames[1]:=vB;
      If vCount>2 then gNames[2]:=vC;
      If vCount>3 then gNames[3]:=vD;
      If vCount>4 then gNames[4]:=vE;
      If vCount>5 then gNames[5]:=vF;
      If vCount>6 then gNames[6]:=vG;
      If vCount>7 then gNames[7]:=vH;
      If vCount>8 then gNames[8]:=vI;
      If vCount>9 then gNames[9]:=vJ;
    end;

    procedure SetWidths(vCount:integer; v1:integer=0;v2:integer=0;v3:integer=0;v4:integer=0;v5:integer=0;v6:integer=0;v7:integer=0;v8:integer=0;v9:integer=0;v10:integer=0);
    begin
      SetLength(gWidths,0);
      SetLength(gWidths,vCount);
      If vCount>0 then gWidths[0]:=v1;
      If vCount>1 then gWidths[1]:=v2;
      If vCount>2 then gWidths[2]:=v3;
      If vCount>3 then gWidths[3]:=v4;
      If vCount>4 then gWidths[4]:=v5;
      If vCount>5 then gWidths[5]:=v6;
      If vCount>6 then gWidths[6]:=v7;
      If vCount>7 then gWidths[7]:=v8;
      If vCount>8 then gWidths[8]:=v9;
      If vCount>9 then gWidths[9]:=v10;
    end;

    procedure SetColumns(vColumns:TVirtualTreeColumns; vNames:array of string; vWidths:array of integer);
    var i:integer;
    begin
      vColumns.Clear;
      for i := 0 to High(vNames) do
        vColumns.Add.Text:=vNames[i];

      for i := 0 to High(vWidths) do
        vColumns[i].Width:=vWidths[i];
    end;

With these global arrays and 3 new procedure I just do this, very easy, clean:

    procedure TForm1.Button2Click(Sender: TObject);
    begin
        VST.Header.Columns.Clear;

        SetNames(4,'#','First name','Last name','Address');
        SetWidths(4,50,20,20,50);
        SetColumns(VST.Header.Columns,gNames,gWidths);
    end;

  .

Question: Is it possible to reduce the code, skip the global arrays and extra procedure to something like:

SetColumns(VST.Header.Columns,('#','First name','Last name','Address'),(50,20,20,50));
4
  • 2
    Hey there, take a look at is: array as parameter and return type Is it this you are searching for? Commented Dec 23, 2015 at 13:30
  • @rocksteady not sure how you see this would help my case. Maybe to change SetNames and SetWidth to functions and use them in one call: SetColumns(VST.Header.Columns,fSetNames(4,'#','First name','Last name','Address'), fSetWidths(4,50,20,20,50)))? Commented Dec 23, 2015 at 14:40
  • 1
    It shows a way of passing an array as parameter to a function/procedure by declaring the array as a type: Referring to the example given in the link above: type TDayVisitors = array[0..6] of integer; ... procedure DisplayWeekTotal(weekVisitors : TDayVisitors) ; I thought it might help. Commented Dec 23, 2015 at 15:06
  • Thank you, I'm evaluating answer below from LU RD, ti seems cleaner. Commented Dec 23, 2015 at 15:11

1 Answer 1

5

Change the SetColumns to take const open arrays:

procedure SetColumns(  vColumns       : TVirtualTreeColumns;
                       const vNames   : array of string;
                       const vWidths  : array of integer);
var i:integer;
begin
  if Length(vNames) <> Length(vWidths) then
    raise Exception.Create('vNames and vWidth should have same number of elements!')
  else
  begin
    vColumns.Clear;
    for i := 0 to High(vNames) do
      with vColumns.Add do
      begin
        Text := vNames[i];
        Width := vWidths[i];
      end;
  end;
end;

Add brackets around the arrays Using Open Array Constructor:

SetColumns(VST.Header.Columns,['#','First name','Last name','Address'],[50,20,20,50]);

Another alternative (uses the heap to allocate the arrays):

SetColumns( VST.Header.Columns,
            TArray<String>.Create('#','First name','Last name','Address'),
            TArray<Integer>.Create(50,20,20,50));

Christmas bonus update

In a comment the OP asks how to pass an array of a record in brackets in a similar way.

Step 1:

Declare a static class function as a member of your record returning a record:

Type
  TMyRecord =
    record
      myName: string;
      myValue: integer;
      class function Init(const aName: String; aValue: Integer): TMyRecord; static;
    end;

class function TMyRecord.Init(const aName: String; aValue: Integer): TMyRecord;
begin
  Result.myName := aName;
  Result.myValue := aValue;
end;

Step 2:

Call your SetValues2 procedure utilizing the static initialization function:

procedure SetValues2(const vArr: array of TMyRecord);
begin
  ;
end;

SetValues2([TMyRecord.Init(' a ',1),TMyRecord.Init(' b ',2),TMyRecord.Init(' c ',3)]);
Sign up to request clarification or add additional context in comments.

14 Comments

Drat! Silly phone call cost me again. :-) Nice.
@LU RD Maybe I'm wrong but the code above has nothing to do with the new linked feature in XE7: it's how the Format function is usually called. Anyway it works like the answer in XE4 too.
@LU RD obviously the parameters meaning differs but what I meant was the construction of the array [...] during the call. It applies here since an array of const parameter is implemented like an open array of TVarRec behind the scene, like the doc you've linked states
This form of parameter specification, using [...] is known as an open array constructor. A link to the docs would be useful here. @Mike The language documentation is generally good. I recommend it to you.
The open array constructor is generally preferable because it avoids the overhead of heap memory.
|

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.