John Boe
John Boe

Reputation: 3611

Pointer to Control

I would like to create array of all listboxes and access them. I tried to do it using pointers, however my program crashes during runtime with error access violation at address...

type ControlsCount = 4;
type PLB = ^TListBox;

var listBoxes: array of PLB;

procedure TExport.FormCreate(Sender: TObject);
var i: word; n: integer;
begin
  with FormExport do
  begin
    ListRowHeight := List_sex.height;
    List_sex.items.add('---');
    List_sex.items.add('Man');
    List_sex.items.add('Woman');
    List_sex.onmousemove:=ListMouseMove;

    setLength(listBoxes, ControlsCount);
    n := -1;
    for i := 0 to ControlsCount - 1 do
        if Components[i] is TWinControl then
          if TWinControl(Components[i]).CanFocus then
            begin
            inc(n);
            // mistake here: should be listBoxes[n] not listBoxes[i]
            listBoxes[i] := PLB(Components[i]);
            end;
    realControlsCount := n;
  end;
end;

procedure TExport.resetListBoxes;
var i: word;
begin
 for i := 0 to realControlsCount-1 do
  begin
    TListBox(listBoxes[i]^).height := ListRowHeight;
  end;
end;

So here I try to set the pointer of the control to listBoxes[i].

listBoxes[i] := PLB(Components[i]);

and here I try to access it:

TListBox(listBoxes[i]^).height := ListRowHeight;

this is the line where it generates error.

What am I doing wrong?

Upvotes: 0

Views: 170

Answers (2)

Adriaan
Adriaan

Reputation: 806

Regarding the answere MBo gave this is how I would use it with a TList

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, Generics.Collections,
  FMX.Layouts, FMX.ListBox, FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    lst1: TListBox;
    lst2: TListBox;
    lst3: TListBox;
    btn1: TButton;
    pnl1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  listboxes: TList<TListBox>; // Define list that will contain listboxes

implementation

{$R *.fmx}

procedure TForm1.btn1Click(Sender: TObject);
var
  lstbx: TListBox;
begin
  for lstbx in listboxes do
    ShowMessage(lstbx.Height.ToString); Loop through all listboxes and show their height
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  control: TControl;
begin
  listboxes := TList<TListBox>.Create; // Create the TList

  for control in pnl1.Controls do
  begin
    if control is TListBox then
      listboxes.Add(control as TListBox); // Loop through all listboxes on a panel and add then to the list if they are a listbox
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  listboxes.Free; // Free the list
end;

end.

Upvotes: 1

MBo
MBo

Reputation: 80107

Just remove all pointer stuff and check whether control is really TListBox. Also you misused ControlsCount while accessed another list Components[i]

 var listBoxes: array of TListBox;
 ...
for i := 0 to ControlsCount - 1 do
  if Controls[i] is TListBox then  //note strict constraint
     listBoxes[n] := Controls[i] as TListBox;
 ...
  listBoxes[i].height := ListRowHeight;

Aslso consider using TList<TListBox> instead of array

Upvotes: 3

Related Questions