Interesante

Crear componentes dinámicamente (en tiempo de ejecución)

Crear componentes dinámicamente (en tiempo de ejecución)

La mayoría de las veces, cuando se programa en Delphi, no es necesario crear dinámicamente un componente. Si suelta un componente en un formulario, Delphi maneja la creación del componente automáticamente cuando se crea el formulario. Este artículo cubrirá la forma correcta de crear componentes mediante programación en tiempo de ejecución.

Creación dinámica de componentes

Hay dos formas de crear componentes dinámicamente. Una forma es hacer que un formulario (o algún otro TComponent) sea el propietario del nuevo componente. Esta es una práctica común cuando se compilan componentes compuestos donde un contenedor visual crea y posee los subcomponentes. Hacerlo asegurará que el componente recién creado se destruya cuando se destruya el componente propietario.

Para crear una instancia (objeto) de una clase, llama a su método "Crear". El constructor Create es un método de clase, a diferencia de prácticamente todos los demás métodos que encontrará en la programación de Delphi, que son métodos de objeto.

Por ejemplo, el TComponent declara el constructor Create de la siguiente manera:

constructor Create (AOwner: TComponent); virtual;

Creación dinámica con propietarios
Aquí hay un ejemplo de creación dinámica, donde Yo es un descendiente de TComponent o TComponent (por ejemplo, una instancia de un TForm):

con TTimer.Create (Self) do
empezar
Intervalo: = 1000;
Habilitado: = Falso;
OnTimer: = MyTimerEventHandler;
fin;

Creación dinámica con una llamada explícita a la libertad
La segunda forma de crear un componente es usar nulo como el dueño Tenga en cuenta que si hace esto, también debe liberar explícitamente el objeto que cree tan pronto como ya no lo necesite (o producirá una pérdida de memoria). Aquí hay un ejemplo del uso de nil como propietario:

con TTable.Create (nil) do
tratar
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
Abierto;
Editar;
FieldByName ('Ocupado'). AsBoolean: = Verdadero;
Enviar;
finalmente
Gratis;
fin;

Creación dinámica y referencias de objetos
Es posible mejorar los dos ejemplos anteriores asignando el resultado de la llamada Crear a una variable local del método o perteneciente a la clase. Esto es a menudo deseable cuando las referencias al componente deben usarse más tarde, o cuando los problemas de alcance potencialmente causados ​​por los bloques "Con" deben evitarse. Aquí está el código de creación de TTimer desde arriba, usando una variable de campo como referencia para el objeto TTimer instanciado:

FTimer: = TTimer.Create (Self);
con FTimer do
empezar
Intervalo: = 1000;
Habilitado: = Falso;
OnTimer: = MyInternalTimerEventHandler;
fin;

En este ejemplo, "FTimer" es una variable de campo privado del formulario o contenedor visual (o lo que sea "Self"). Al acceder a la variable FTimer desde los métodos de esta clase, es una muy buena idea verificar si la referencia es válida antes de usarla. Esto se hace usando la función Asignada de Delphi:

si está asignado (FTimer), entonces FTimer.Enabled: = True;

Creación dinámica y referencias a objetos sin propietarios
Una variación de esto es crear el componente sin propietario, pero mantener la referencia para su posterior destrucción. El código de construcción para el TTimer se vería así:

FTimer: = TTimer.Create (nil);
con FTimer do
empezar

fin;

Y el código de destrucción (presumiblemente en el destructor del formulario) se vería así:

FTimer.Free;
FTimer: = nulo;
(*
O utilice el procedimiento FreeAndNil (FTimer), que libera una referencia de objeto y reemplaza la referencia con nil.
*)

Establecer la referencia de objeto a nulo es fundamental al liberar objetos. La llamada a Free primero verifica si la referencia del objeto es nula o no, y si no lo es, llama al destructor del objeto Destroy.

Creación dinámica y referencias a objetos locales sin propietarios

Aquí está el código de creación de TTable desde arriba, usando una variable local como referencia para el objeto TTable instanciado:

localTable: = TTable.Create (nil);
tratar
con localTable do
empezar
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
fin;

// Más tarde, si queremos especificar explícitamente el alcance:
localTable.Open;
localTable.Edit;
localTable.FieldByName ('Ocupado'). AsBoolean: = Verdadero;
localTable.Post;
finalmente
localTable.Free;
tabla local: = nulo;
fin;

En el ejemplo anterior, "localTable" es una variable local declarada en el mismo método que contiene este código. Tenga en cuenta que después de liberar cualquier objeto, en general, es una muy buena idea establecer la referencia en nil.

Una palabra de advertencia

IMPORTANTE: No mezcle una llamada a Free con pasar un propietario válido al constructor. Todas las técnicas anteriores funcionarán y son válidas, pero las siguientes deberían nunca aparece en tu código:

con TTable.Create (self) do
tratar

finalmente
Gratis;
fin;

El ejemplo de código anterior introduce golpes de rendimiento innecesarios, afecta ligeramente la memoria y tiene el potencial de introducir errores difíciles de encontrar. Averigua porque.

Nota: Si un componente creado dinámicamente tiene un propietario (especificado por el parámetro AOwner del constructor Crear), ese propietario es responsable de destruir el componente. De lo contrario, debe llamar explícitamente a Free cuando ya no necesite el componente.

Artículo escrito originalmente por Mark Miller

Se creó un programa de prueba en Delphi para cronometrar la creación dinámica de 1000 componentes con recuentos de componentes iniciales variables. El programa de prueba aparece en la parte inferior de esta página. El cuadro muestra un conjunto de resultados del programa de prueba, comparando el tiempo que lleva crear componentes tanto con propietarios como sin ellos. Tenga en cuenta que esto es solo una parte del golpe. Se puede esperar un retraso de rendimiento similar al destruir componentes. El tiempo para crear dinámicamente componentes con propietarios es de 1200% a 107960% más lento que el de crear componentes sin propietarios, dependiendo de la cantidad de componentes en el formulario y el componente que se está creando.

El programa de prueba

Advertencia: Este programa de prueba no rastrea y libera componentes que se crean sin propietarios. Al no rastrear y liberar estos componentes, los tiempos medidos para el código de creación dinámica reflejan con mayor precisión el tiempo real para crear dinámicamente un componente.

Descargar código fuente

¡Advertencia!

Si desea crear una instancia dinámica de un componente Delphi y liberarlo explícitamente en algún momento posterior, siempre pase nil como propietario. De lo contrario, puede introducir riesgos innecesarios, así como problemas de rendimiento y mantenimiento del código. Lea el artículo "Una advertencia sobre la creación dinámica de instancias de componentes de Delphi" para obtener más información ...