1. Computing

Managing Run-Time Component Arrays

Accessing a group of run-time created components using an array

From , former About.com Guide

Managing Run-Time Component Arrays

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-Time

While 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.

Download buttons array example code.

  1. 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.
  2. 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) ; 
  3. Here's the code to fill the buttons array:
     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; 
    Each element of the "buttonsArray" is a TButton. To dynamically create the button we use its constructor by passing "nil" for the owner parameter.
    The OnClick event handler is assigned, Caption is set and the button is placed on a parent.
  4. 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; 
  5. 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; 
That's it. Be sure to download the sample application.

©2013 About.com. All rights reserved.