Dynamic Forms

Besides a form visually, sometimes this will not be possible. You may have to create the form dynamically. To create a form dynamically, declare a pointer to a TForm class.

Dynamic Local Forms

If you want to quickly use a form in a function or an even, you can create it easily. There are two options you have. If you want to create a duplicate of the form you already have, you can use it as the base class and simply create an instance of the form using the new operator. When dynamically creating a form, you must provide a parent for the form. If you are creating a duplicate of the form, set the parent as the this pointer. The parent is provided to the constructor. For example, to create a duplicate form using a form’s OnDblClick event, you can implement the event as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
    TForm1* Former = new TForm1(this);
}
//---------------------------------------------------------------------------

The problem with a duplicate is that, unless you go through a big deal of code writing, everytime you do anything on the form, the duplicate produces the same action. For example, if you use the above code, everytime you double-click the form, a new duplicate is created. Therefore, the second option you have on creating a local object is to create a fresh form. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
    TForm* Former = new TForm(this);
}
//---------------------------------------------------------------------------

Dynamic Global Forms

The biggest problem with a locally created form is that it is available only in the event or the function in which it is created. If you try to access it outside, you would receive an error. If you want a form to be available to more than one event or function, you must create it in a header file of an existing form. You could create the form as follows:

//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
    TForm* Comet;
private: // User declarations

public: // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------

If you try running the application, you would receive a noisy warning that seems harmless:

If you insist, you can click No and the program would compile and run fine. But, this would be unprofessional and unpredictable. This is because you would have declared a non-visually added control to your application. The solution is to make sure you declare your dynamic object in one of the other sections. If you want the form to be available outside of the parent form that “owns” the header file, you must declare it in the public section. Otherwise, you should declare it in the private section:

//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components

private: // User declarations
    TForm* Comet; // A dynamically created form
public: // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

After declaring the form, since you cannot initialize a variable in the header file, you can use the constructor of the host form to initialize the dynamic form. This is done by using the new operator and initializing the TForm class with the this pointer, like this:

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"TForm1 *Form1;
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    Comet = new TForm(this);
}
//---------------------------------------------------------------------------

Customizing Dynamic Forms

Whatever technique you use to create your form, you can set its properties using code. The most basic thing you should do is to display it using the TForm::ShowModal() method. If the form was created locally, you must display it in the function or event where it was created:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
    TForm* Former = new TForm(this);
    Former->ShowModal();
}
//---------------------------------------------------------------------------

If the form was created globally, you can use almost any event to display it. The best way to display such a form is through a button, which we will learn soon. Otherwise, to display a glogally created form when the user double-clicks the main form, you can write:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
    Comet->ShowModal();
}
//---------------------------------------------------------------------------

After creating a form, such as Comet, you can programmatically set any of its properties and use any of its methods.

After creating and using a form, you should make sur the memory allocated to it is regained. The Borland C++ Builder compiler can take care of cleaning your dynamic controls when the application exists. Otherwise, you can delete it manually:

delete MyForm;

Furthermore, to avoid any memoly leak, you can reclaim the dynamically allocated memory by assigning NULL to the deleted object:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
    TForm1 *Cosmos = new TForm1(this);
    Cosmos->ShowModal();
    delete Cosmos;
    Cosmos = NULL;
}
//---------------------------------------------------------------------------

Practical Learning: Using a Dynamic Form

  1. To create a new application, on the Standard toolbar, click the New button.
  2. On the New Items dialog, double-click Application.