프로그램/바로쓰는델파이

[펌]Managing Run-Time Component Arrays

mulderu 2008. 1. 21. 01:07

Managing Run-Time Component Arrays

From Zarko Gajic,
Your Guide to Delphi Programming.
FREE Newsletter. Sign Up Now!

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

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.
Source Code

Download