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 construyen 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 Crear 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. Crear (Self) do
empezar
Intervalo: = 1000;
Habilitado: = Falso;
OnTimer: = MyTimerEventHandler;
final;
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á un pérdida de memoria). Aquí hay un ejemplo del uso de nil como propietario:
con TTable. Crear (nulo) hacer
tratar
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
Abierto;
Editar;
FieldByName ('Ocupado'). AsBoolean: = Verdadero;
Enviar;
finalmente
Gratis;
final;
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 a componente debe usarse más tarde o cuando alcance Los problemas potencialmente causados por los bloques "Con" deben evitarse. Aquí está el código de creación TTimer desde arriba, usando una variable de campo como referencia para el objeto TTimer instanciado:
FTimer: = TTimer. Crear (auto);
con FTimer hacer
empezar
Intervalo: = 1000;
Habilitado: = Falso;
OnTimer: = MyInternalTimerEventHandler;
final;
En este ejemplo, "FTimer" es una variable de campo privado de la forma 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. Habilitado: = Verdadero;
Creación dinámica y referencias de 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. Crear (nulo);
con FTimer hacer
empezar
...
final;
Y el código de destrucción (presumiblemente en el destructor del formulario) se vería así:
FTimer. Gratis;
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 en nil 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 TTable desde arriba, usando una variable local como referencia para el objeto TTable instanciado:
localTable: = TTable. Crear (nulo);
tratar
con localTable do
empezar
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
final;
...
// Más tarde, si queremos especificar explícitamente el alcance:
localTable. Abierto;
localTable. Editar;
localTable. FieldByName ('Ocupado'). AsBoolean: = Verdadero;
localTable. Enviar;
finalmente
localTable. Gratis;
localTable: = nil;
final;
En el ejemplo anterior, "localTable" es un variable local declarado 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. Crear (auto) hacer
tratar
...
finalmente
Gratis;
final;
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), entonces 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 gráfico 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 componentes dinámicamente con los propietarios es de 1200% a 107960% más lento que el de crear componentes sin propietarios, según el número de componentes en el formulario y el componente que se está creado.
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 nulo 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 ...