Skip to content

Delphi crear componentes en tiempo de ejecución

A todo programador se nos cruzan dificultades a la hora de desarrollar, y una de ellas es cuando tenemos que crear componentes en tiempo de ejecución.

Es muy sencillo crear formularios en tiempo de diseño, pero muchas veces los vamos a tener que crear en tiempo de ejecución no solo a componentes no visuales, como conexiones a base de datos, ni no también componentes visuales como edit, button, grid entre otros.

Para ello deberemos tener en cuenta una serie de datos que nos pueden dar un dolor de cabeza, no solo a los programadores sino también a os usuarios finales.

Crear componentes en tiempo de ejecución, paso a paso

Existen dos maneras de crear componentes en tiempo de ejecución, la primera es hacer que un formulario (o cualquier otro TComponent) sea el propietario del componente creado.

Creación dinámica con propietario

Esta práctica es común cuando se compilan componentes compuestos donde un contenedor visual posee a los sub componentes. Crearlos de esta manera, es para asegurarnos de que el componente que se ha creado se destruya cuando se destruya el componente propietario.

Para crear un nuevo objeto ( instancia ), se debe llamar a su método Create. El constructor Create es un método de clase, a diferencia del resto de los demás métodos que son métodos de objeto.

Ejemplo 1, crear componentes en tiempo de ejecución con propietario

En este ejemplo, vamos crear un componente TTimer con el Formulario contenedor como propietario. De esta manera nos aseguramos que el Timer estará disponible durante la vida del Formulario y se destruirá junto a él.

En primer lugar, crearemos una variable global llamada vTimer de tipo TTimer:

type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  vTimer: TTimer;

implementation

Ahora, en el evento OnCreate del formulario (queremos que se cree y se destruya junto al formulario) creamos el Timer. A su vez modificamos la propiedad Interval a 5 segundos, Enabled a False y asignamos el procedimiento MyTimerEventHandler al evento OnTimer el cual se ejecutará cada 5 segundos.

El parámetro Self que le enviamos en el método Create, indica que el propietario es el Formulario, ya que se creo dentro del evento OnCreate del Formulario.

procedure TForm1.FormCreate(Sender: TObject);
begin
  vTimer := TTimer.Create(Self);
  with vTimer do
  begin
    Interval := 5000;
    Enabled := False;
    OnTimer := MyTimerEventHandler;
  end;
end;

procedure TForm1.MyTimerEventHandler(Sender: TObject);
begin
  // Este procedimiento se ejecutará en el evento OnTimer
  // del objeto vTimer
end;

Si lo creamos en el evento OnCreate de un button por ejemplo, y de todas maneras queremos que el propietario sea el Formulario deberíamos colocar :

vTimer := TTimer.Create(Form1);

De esta manera ya tenemos creado nuestro Timer y se encuentra disponible para su uso en toda la vida del Formulario.

Creación dinámica sin propietario

La segunda manera de crear un componente en tiempo de ejecución es pasando el parámetro nil, lo que indica que no tiene propietario.

PRECAUCIÓN: esta forma de crear un componente en tiempo de ejecución es peligrosa, ya que debemos destruir el objeto de forma manual. Si no lo destruimos vamos a tener una fuga de memoria por culpa de nuestro programa y puede ser catastrófico para el usuario, produciendo cuelgues y errores de memoria insuficiente.

Ejemplo 2, crear componentes en tiempo de ejecución sin propietario

En este segundo ejemplo, vamos crear el mismo componente TTimer pero sin tener propietario, y añadiremos la destrucción del mismo.

type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  vTimer: TTimer;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  vTimer := TTimer.Create(nil);
  with vTimer do
  begin
    Interval := 5000;
    Enabled := False;
    OnTimer := MyTimerEventHandler;
  end;
end;

procedure TForm1.MyTimerEventHandler(Sender: TObject);
begin
  // Este procedimiento se ejecutará en el evento OnTimer
  // del objeto vTimer
end;

Ahora deberemos destruir el objeto vTimer, para que se destruya al destruirse el formulario, lo declararemos en el evento OnDestroy del Form.

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(vTimer);
end;

Y de esta manera estamos creando componentes en tiempo de ejecución, sin tener fugas de memoria y sin dolores de cabeza.