A component (or control) array, as the name implies, is nothing more than an array of components.
In the first part of this article (Acessing a group of design-time created components using an array), you have learned how to access a group of components by storing a reference to each control into an element of an array.
An Array of Components Created at Run-TimeWhile in most situations you will build the user interface of your application at design-time using the IDE, there are scenarios where you need to programmatically create components at run time.
Consider an entry form for a database application. You could decide to write a function that takes the name of a database table, and creates a DBEdit (data-aware TEdit) for each field (column) in the table. Such a generic database entry form could then be used to edit data from any table.
You could store all DBEdit's into an array and use it to, for example, run a common validation code against all the DBEdit in a loop.
Run-Time Buttons Array Example
Let's start by creating a simple example, but powerful enough to show how to create buttons at run-time, assign the OnClick event handler and store all the buttons into an array.
- A form hosts an edit control and a button. When you click the button an array of buttons will be created (at run-time). The number of buttons to be created is retrieved from the edit control.
- Since we'll be dealing with buttons in an array, we need to declare our array type variable. We will use a dynamic array here, as we do not know how many buttons will be created.
All the buttons will share the same event handler ("ButtonClicked").
We'll need a function to free the memory when we exit the program ("FreeButtons").
Place the following declarations in the private section of the form declaration
TMainForm = class(TForm) ... private buttonsArray : array of TButton; //free the memory procedure FreeButtons(buttons : array of TButton) ; //shared "onclick" handler procedure ButtonClicked(sender : TObject) ;
Here's the code to fill the buttons array:
Each element of the "buttonsArray" is a TButton. To dynamically create the button we use its constructor by passing "nil" for the owner parameter.
var ctrlCount : integer; cnt : integer; begin //first clear any previously created buttons FreeButtons(buttonsArray) ; ctrlCount := StrToInt(edCtrlCount.Text) ; //set the "new" length SetLength(buttonsArray, ctrlCount) ; //create "new" buttons for cnt := 0 to -1 + ctrlCount do begin buttonsArray[cnt] := TButton.Create(nil) ; //assign the OnClick event handler buttonsArray[cnt].OnClick := ButtonClicked; //set the caption buttonsArray[cnt].Caption := Format('Button %d',[cnt]) ; //position randomly buttonsArray[cnt].Left := Random(pnlRunTime.Width - buttonsArray[cnt].Width) ; buttonsArray[cnt].Top := Random(pnlRunTime.Height - buttonsArray[cnt].Height) ; //if no parent is set, button will not be visible! buttonsArray[cnt].Parent := pnlRunTime; //TPanel end; end;
The OnClick event handler is assigned, Caption is set and the button is placed on a parent.
Just for a test, the OnClick event handler display the Caption of the clicked button:
procedure TMainForm.ButtonClicked(sender: TObject) ; begin if Sender is TButton then begin ShowMessage(Format('%s clicked!',[TButton(Sender).Caption])) ; end; end;
- Since we used nil for each button's Owner, the "FreeButtons" procedures ensures that the memory is freed:
procedure TMainForm.FreeButtons(buttons : array of TButton) ; var cnt : integer; begin for cnt := Low(buttons) to High(buttons) do begin buttons[cnt].Free; buttons[cnt] := nil; end; end;