Ivan Prodanov
Ivan Prodanov

Reputation: 35522

How to create an array of controls?

I have to create an array and place all controls there in order to access them.Here's a short example:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    const Test:Array[0..2] of TButton = (Button1,Button2,Button3);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

end.

Undeclarated idenitifier 'Button1' at the line where I declarated my array.But it's declarated three lines above.

Where's the problem,how to put all controls in an array?

EDIT:

Thank you for your answers,but I've got problems:

 var TestA:TObjectList<TButton>;

 var index:TComponent;
 begin
 TestA := TObjectList<TButton>.Create(false);
   for index in Form7 do
     if pos(index.name, 'Button') = 1 then
       TestA.add(TButton(index));

 TestA[0].Caption := 'Test'; //Exception out of range.

Upvotes: 2

Views: 9193

Answers (6)

MajidTaheri
MajidTaheri

Reputation: 3983

Try this var TestA:TObjectList;

 index:TComponent;
begin
   TestA := TObjectList<TButton>.Create(false);
   try
     for index in Form7 do
       if (pos is TButton) OR {or/and} (pos.tag and 8=8) then
         TestA.add(TButton(index));
     if TestA.Count>0 then //Fix:Exception out of range.
       TestA[0].Caption := 'Test'; 
    finally
      TestA.Free; 
    end;
end;

Upvotes: 1

Alan Bailey
Alan Bailey

Reputation:

I use this all the time - it is simple and fast (despite Mr Wheeler's comment)- declare the maxbuttons as a constant

var Form1: TForm1; pbutton:array[1..maxbuttons] of ^tbutton;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

(* Exit *)

var k:integer;

begin

for k:=1 to maxbuttons do dispose(pbutton[k]);

close;

end;

procedure TForm1.FormActivate(Sender: TObject);

var k:integer;

begin

(*note the buttons must be Button1, Button2 etc in sequence or you need to allocate them manually eg pbutton[1]^:=exitbtn etc *)

for k:=1 to maxbuttons do

begin

new(pbutton[k]);

pbutton[k]^:= tbutton(FindComponent('Button'+IntToStr(k)));

end;

end;

procedure TForm1.ButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

var k:integer; b:boolean;

begin b:=false; k:=1;

while (k<= maxbuttons) and (not b) do

begin

if pbutton[k]^ = sender then (Note sender indicates which button has been clicked)

begin

  { found it so do something}

  b:=true;

end;

k:=k+1;

end;

end;

Upvotes: 1

CodeAndCats
CodeAndCats

Reputation: 7984

This function will iterate over all the controls on a specified container, like a particular TPanel or even the entire form, and populate a specified TObjectList with your TImage controls.

procedure TForm1.AddImageControlsToList(AParent: TWinControl; AList: TObjectList; Recursive: boolean);
var 
  Index: integer;
  AChild: TControl;
begin
  for Index := 0 to AParent.ControlCount - 1 do
  begin
    AChild := AParent.Controls[Index];
    if AChild is TImage then // Or whatever test you want to use
      AList.Add(AChild)
    else if Recursive and (AChild is TWinControl) then
      AddImageControlsToList(TWinControl(AChild), AList, True);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Call like this or similar to get your list of images
  // (assumes MyImageList is declared in Form)
  MyImageList := TObjectList.Create(False);
  AddImageControlsToList(Self, MyImageList, True);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // Destroy the list
  FreeAndNil(MyImageList);
end;

Upvotes: 2

Mason Wheeler
Mason Wheeler

Reputation: 84590

Ben's right. You can't set up a control array in the form designer. But if you have 110 images, for this specific case you can put them into a TImageList component and treat its collection of images as an array.

If you've got a bunch of more normal controls, like buttons, you'll have to create an array and load them into it in code. There are two ways to do this. The simple way, for small arrays at least, is Ben's answer. For large control sets, or ones that change frequently, (where your design is not finished, for example,) as long as you make sure to give them all serial names (Button1, Button2, Button3...), you can try something like this:

var
  index: TComponent;
  list: TObjectList;
begin
  list := TObjectList.Create(false); //DO NOT take ownership
  for index in frmMyForm do
    if pos('Button', index.name) = 1 then
      list.add(index);
   //do more stuff once the list is built
end; 

(Use a TObjectList<TComponent>, or something even more specific, if you're using D2009.) Build the list, based on the code above, then write a sorting function callback that will sort them based on name and use it to sort the list, and you've got your "array."

Upvotes: 4

LachlanG
LachlanG

Reputation: 4087

How about this?

procedure TForm1.FormCreate(Sender: TObject);
begin
  for b := 1 to 110 do
    Test[b] := FindComponent('Button' + IntToStr(b)) as TButton;
end;

You'll have to declare the array as a variable rather than a constant and it will have to go from 1 to 110 rather than 0 to 109 but that's no problem.

Upvotes: 1

CodeAndCats
CodeAndCats

Reputation: 7984

You may not be able to reference public properties of your form in an array constant like that. Try doing it in your form constructor/OnCreate event instead.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Test[0] := Button1;
  Test[1] := Button2;
  Test[2] := Button3;
end;

Upvotes: 4

Related Questions