Está en la página 1de 10

Formularios

Pablo Reyes
PReyes@excite.com

El Rinconcito de Delphi

El presente artculo se publica tal cual por su autor. Cualquier manipulacin o publicacin sin la debida autorizacin puede vulnerar los derechos de autor.

Tutoriales Delphi 7
Introduccin
Formularios
Los formularios son el punto de comunicacin entre una aplicacin y sus usuarios. Delphi nos permite crear formularios de manera visual generando el cdigo fuente necesario para pueda ser mostrado por la aplicacin en tiempo de ejecucin. En este tutorial vamos a conocer los detalles que hay por detrs de un formulario Delphi.

Algunos conceptos de programacin orientada a objetos


No nos vamos a sumergir en las profundidades de la programacin orientada a objetos pero para entender un poco mejor qu es un formulario vamos a darle un vistazo a la superficie. Un formulario es un objeto. Un objeto es una instancia de una clase. Por lo tanto cuando creamos un formulario estamos creando una clase. Esta clase no la creamos desde cero sino a partir de una clase existente. Es decir, heredamos funcionalidad de otra clase. De qu clase? De la clase TForm. Cuando creamos un formulario nuevo, Delphi genera el siguiente cdigo:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} end.

Prestemos atencin a todo lo que dice Form1. Por un lado est la declaracin de la clase del formulario, es decir, de la clase TForm1. Por otro la declaracin de la variable Form1 del tipo TForm1. Si modificamos el nombre del formulario, es decir, el valor de su propiedad Name el nombre de la clase y el de la variable tambin cambiarn. Para que no queden dudas: si cambiamos el valor de la propiedad Name de este formulario a, por ejemplo, FRMPrueba, el nombre de la clase cambiar a TFRMPrueba y el nombre de la variable a FRMPrueba. Este comportamiento puede ser un poco confuso. Parece

como si entre el valor de la propiedad Name, el nombre de la clase del formulario y el nombre de la variable hubiera una relacin muy estrecha. Pues bien, no la hay. Delphi hace estos cambios para que nos resulte ms fcil trabajar con el formulario pero la realidad demuestra que no hay ninguna relacin entre estos tres elementos. Vamos a hacer un ejemplo para comprobar lo que acabo de decir. Crear un proyecto nuevo. Para ello seleccionar del men File | New | Application. Aadir al formulario principal los siguientes componentes: De la pgina Standard, un Label, un Edit y dos Button. El formulario debera verse as:

Como se puede ver en la imagen de pantalla, modifiqu el valor de la propiedad Caption del Label y de los dos Button y el valor de la propiedad Text del Edit. Lo que vamos a hacer es escribir cdigo para el evento OnClick de los dos Button. En el caso del Button "GetName" simplemente vamos a mostrar el nombre del formulario en el Label. En el caso del Button "SetName" vamos a asignarle un valor a la propiedad Name del formulario. El cdigo del evento OnClick del Button "GetName" es el siguiente:
procedure TForm1.Button1Click(Sender: TObject); begin Label1.Caption := Format('Form.Name = %s', [Form1.Name]); end;

El cdigo del evento OnClick del Button "SetName" es el siguiente:


procedure TForm1.Button2Click(Sender: TObject); begin Form1.Name := Edit1.Text; end;

Como puede verse claramente en el cdigo de arriba, estoy haciendo referencia al formulario por su nombre o, mejor dicho, por la variable que inicialmente tiene el mismo nombre que el formulario. Al cambiar el valor de la propiedad Name el cdigo sigue funcionando perfectamente. Lo vuelvo a decir. No existe una relacin implcita entre el nombre de la clase del formulario, el nombre de la variable del formulario y el nombre del formulario, es decir, el valor de la propiedad Name. Guardar el proyecto, compilarlo y ejecutarlo. Un detalle adicional es que al cambiar el nombre del formulario, es decir (insisto), el valor de su propiedad Name tambin cambia el ttulo del formulario, es decir, el valor de su propiedad Caption. Cuando el valor de la propiedad Caption es igual al valor de la propiedad Name, si cambiamos el valor de la propiedad Name tambin cambia el valor de la propiedad Caption.

Creacin de formularios
Cuando ejecutamos la aplicacin, Delphi se encarga de mostrar el formulario principal. Lo que ocurre detrs de escena es que Delphi se encarga de crear una instancia de la clase del formulario, es decir, un objeto del tipo TForm1, y asignar una referencia a dicho objeto en la variable Form1. Dnde lo hace? En el cdigo fuente del proyecto podemos verlo claramente. Para visualizar el cdigo fuente del proyecto seleccionar del men Project | View Source. La siguiente lnea:
Application.CreateForm(TForm1, Form1);

Se encarga de crear una instancia de la clase TForm1 y asignar una referencia al objeto creado en la variable Form1. Ambos elementos, es decir, la clase TForm1 y la variable Form1 estn declarados en la unidad Unit1, incluida en la clusula uses del proyecto. Hagamos un pequeo experimento. Aadir al formulario principal el siguiente componente: De la pgina Standard, un Button. Asignarle a su propiedad Caption el valor "Form1A". Ahora vamos a declarar una variable llamada Form1A del tipo TForm1, o sea, el formulario. El cdigo es el siguiente:
var Form1: TForm1; Form1A: TForm1;

Hemos declarado la variable Form1A debajo de la declaracin de la variable Form1. Escribir el siguiente cdigo para el evento OnClick del Button "Form1A":
procedure TForm1.Button3Click(Sender: TObject); begin Form1A := Form1; ShowMessage(Form1A.Name); end;

Cualquier variable declarada como TForm1 es capaz de mantener una referencia a un objeto del tipo TForm1. Como la variable Form1 es del tipo TForm1 y la variable Form1A tambin es del tipo TForm1 significa que ambas variables son compatibles y por lo tanto podemos asignarle el valor de una a la otra. Esto es precisamente lo que hemos hecho y el cdigo funciona perfectamente. Vamos a hacer otro experimento. Aadir el siguiente componente al formulario: De la pgina Standard, un Button. Asignarle a su propiedad Caption el valor "Nuevo". Escribir el siguiente cdigo para el evento OnClick del Button "Nuevo":
procedure TForm1.Button4Click(Sender: TObject); begin Application.CreateForm(TForm1, Form1A); Form1A.Left := Form1A.Left + 10; Form1A.Top := Form1A.Top + 10; Form1A.Show; end;

Lo que estamos haciendo aqu es creando una nueva instancia de la clase TForm1 y asignndole a la variable Form1A una referencia al objeto creado. Luego modificamos el valor de las propiedades Left y Top para que al mostrar el nuevo formulario no aparezca en la misma posicin que el formulario que ya tenemos. Ahora el comportamiento del cdigo es un poco extrao. Si modificamos el nombre del formulario desde el nuevo objeto vemos como cambian las propiedades del formulario que ya tenamos. Esto es as porque ahora tenemos dos objetos del tipo TForm1. El primero creado al ejecutarse la aplicacin y el segundo al hacer clic en el Button "Nuevo". En la variable Form1 tenemos una referencia al primero y en la variable Form1A tenemos una referencia al segundo.

La palabra reservada Self


La palabra reservada Self nos permite hacer referencia al objeto para el cual estamos ejecutando un mtodo. Si en lugar de escribir cdigo como el que escribimos:
Label1.Caption := Format('Form.Name = %s', [Form1.Name]); Form1.Name := Edit1.Text;

Hubiramos utilizado la palabra reservada Self, el cdigo hubiera tenido efecto sobre el objeto en el cual lo ejecutamos y no sobre el objeto al cual hace referencia la variable utilizada. Vamos a cambiar el cdigo y a ejecutar el proyecto para comprobar todo esto. Ahora bien, qu pasa si hacemos clic ms de una vez sobre el Button "Nuevo"? El cdigo del evento OnClick se encarga de crear una nueva instancia de la clase TForm1 y de asignar una referencia al objeto creado en la variable Form1A. Pues bien, cada vez que hacemos clic en el Button "Nuevo" creamos un nuevo formulario TForm1. Qu pasa con el anterior? No pasa nada. Slo que sigue existiendo en memoria pero perdimos toda referencia al mismo. En la variable Form1A slo mantenemos una referencia al ltimo formulario creado. Sin embargo el cdigo sigue funcionando porque tiene efecto sobre el objeto en el cual lo ejecutamos.

Ms sobre creacin de formularios


Vamos a aadir otro formulario al proyecto. Para ello seleccionar del men File | New | From. A travs de las opciones del proyecto podemos decirle a Delphi que se encargue de crear una instancia de la clase del nuevo formulario al ejecutar la aplicacin. Seleccionar del men Project | Options... y seleccionar la pgina Forms.

Los formularios que estn en la lista Auto-create forms: son creados automticamente por Delphi al ejecutar la aplicacin. Los formularios que estn en la lista Available forms: no son creados automticamente por Delphi al ejecutar la aplicacin. Simplemente estn disponibles para que nosotros explcitamente por cdigo nos encarguemos de crearlos cuando los necesitamos. Todas las clases que se pueden crear en Delphi tienen un ancestro comn en la clase TObject. Esta clase es responsable de proveer la funcionalidad bsica de todos los objetos. Para ello implementa un constructor y un destructor responsables de crear objetos y de destruirlos. Por convencin de nombres, el nombre del constructor es siempre create y el nombre del destructor destroy. Para crear explcitamente por cdigo un formulario tenemos que utilizar el constructor de su clase. Vamos a colocar el segundo formulario en la lista Available forms:. Podemos controlar a qu lista van a parar los formularios nuevos a travs de las opciones del entorno de desarrollo. Seleccionar del men Tools | Environment Options... y luego seleccionar la pgina Designer. En el recuadro Module creation options el campo Auto create forms & data modules controla a qu lista van a parar los formularios nuevos. Si el campo est marcado entonces los formularios nuevos van a parar a la lista Auto-create forms:. Si el campo est desmarcado entonces van a para a la otra lista.

Aadir el siguiente componente al formulario principal: De la pgina Additional, un SpeedButton. Escribir el siguiente cdigo para el evento OnClick del SpeedButton:
procedure TForm1.SpeedButton1Click(Sender: TObject); begin Form2 := TForm2.Create(Self); Form2.Show; end;

Presionar Ctrl+F9 para compilar. Obtenemos el siguiente mensaje:

El compilador se da cuenta de que estamos haciendo referencia a cosas declaradas en la unidad Unit2 y nos ofrece aadir dicha unidad en la clusula uses de la unidad Unit1 que es la unidad en la que estamos codificando. Si contestamos s, Delphi se encarga de aadir la unidad Unit2 en la clusula uses de la seccin implementation de la unidad Unit1. Ahora si presionamos Ctrl+F9 nuevamente la aplicacin se compilar sin errores.

Lo que hicimos en el cdigo anterior fue crear una instancia de la clase TForm2 y asignarle una referencia a la variable Form2. Luego ejecutamos el mtodo Show de la clase TForm, la clase de la que desciende TForm2, para mostrar el formulario. Tenemos que llamar al mtodo Show para mostrar el formulario porque por defecto la propiedad Visible tiene el valor "False". En realidad lo nico que hace el mtodo Show es asignarle el valor "True" a la propiedad Visible. Tambin podemos mostrar el formulario llamando al mtodo ShowModal, En este caso el comportamiento ser diferente ya que mostraremos al formulario de manera modal. Un formulario modal no nos permite acceder a ningn otro formulario de la aplicacin hasta que lo cerremos. Cuando cerramos un formulario el formulario no se destruye sino que se oculta, es decir, su propiedad Visible pasa a tener el valor "False". Esto mismo lo logramos haciendo una llamada al mtodo Hide. Hagamos una prueba. Aadir el siguiente componente al segundo formulario: De la pgina Additional, un BitButton. Escribir el siguiente cdigo para el evento OnClick del BitButton:
procedure TForm2.BitBtn1Click(Sender: TObject); begin Hide; end;

Hacer clic en el BitButton tiene el mismo efector que cerrar el formulario desde el botn de Windows. Cada vez que un formulario se cierra se dispara el evento OnClose. En este evento podemos indicarle a Delphi que queremos que haga al cerrar el formulario. Esto lo hacemos a travs del parmetro Action al que le podemos asignar uno de los siguientes valores: caNone: Delphi no hace nada. Es una forma de evitar que el usuario cierre el formulario desde el botn de Windows. caHide: el formulario se oculta. caFree: el formulario se destruye. caMinimize: el formulario se minimiza. Como dije antes, la accin por defecto es caHide. Vamos a modificar el evento OnClose del segundo formulario para que al cerrarlo se destruya. El cdigo es el siguiente:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end;

Desde el punto de vista visual no hay ninguna diferencia. Pero podemos estar seguros de que al cerrarlo el formulario se ha destruido. Vamos a comprobarlo. Aadir el siguiente componente al formulario principal: De la pgina Additional, un BitButton. Escribir el siguiente cdigo para el evento OnClick del nuevo BitButton:
procedure TForm1.BitBtn1Click(Sender: TObject); begin Form2.Show; end;

Qu pasa con la variable Form2?

Luego de destruir el formulario tiene basura. Cuando creamos el formulario "Form2" asignamos una referencia a la variable Form2. Al destruir el formulario la variable hace referencia a un objeto que no existe. Cuando una variable no hace referencia a ningn objeto tiene el valor nil. Cada vez que destruimos el formulario se dispara el evento OnDestroy. Vamos a escribir cdigo para este evento para evitar que la variable Form2 haga referencia a un objeto que no existe. El cdigo es el siguiente:
procedure TForm2.FormDestroy(Sender: TObject); begin Form2 := nil; end;

Como broche de oro ahora estamos en condiciones de controlar si ya existe una instancia de TForm2 y en ese caso en lugar de crear una nueva instancia simplemente podemos mostrar la que ya existe. Vamos a modificar el cdigo del evento OnClick del SpeedButton del formulario para que se vea as:
procedure TForm1.SpeedButton1Click(Sender: TObject); begin if Form2 = nil then Form2 := TForm2.Create(Self); Form2.Show; end;

Antes de crear una instancia de TForm2 nos aseguramos que la variable Form2 sea igual a nil. De esta forma podemos garantizar que slo habr una instancia de la clase TForm2. Este cdigo es muy utilizado en aplicaciones Delphi. An cuando slo ocultemos el formulario Form2 el resultado ser siempre el correcto. Si ocultamos el formulario Form2 haciendo clic en el BitButton no se disparar el evento OnClose por lo que el formulario no se destruir y por lo tanto tampoco se disparar el evento OnDestroy por lo que la variable Form2 tendr un valor distinto de nil.

Destruyendo formularios
Tenemos varias formas de destruir un formulario. Una de ellas acabamos de verla en el ejemplo anterior. Tambin podemos destruir un formulario llamado directamente al mtodo destructor, es decir, al mtodo Destroy. Sin embargo esta no es la forma ms segura ya que si la variable que utilizamos para hacer referencia al objeto en realidad est haciendo referencia a un objeto que no existe la llamada al mtodo Destroy generar un mensaje de error. Para evitar este problema debemos llamar al mtodo Free. El mtodo Free es ms seguro que el mtodo Destroy ya que antes de llamar al mtodo Destroy verifica que la referencia al objeto sea vlida. Si destruimos explcitamente un formulario no debemos olvidarnos de asignarle el valor nil a la variable que lo referencia. Vamos a destruir explcitamente el formulario Form2. Modificar el cdigo del evento OnClick del SpeedButton del formulario principal para que se vea as:
procedure TForm1.SpeedButton1Click(Sender: TObject); begin if Form2 = nil then begin Form2 := TForm2.Create(Self); Form2.Show; end

else begin Form2.Free; Form2 := nil; end; end;

Cuando la variable Form2 es igual a nil creamos una instancia de TForm2 y la mostramos. Cuando la variable Form2 es distinto de nil destruimos el formulario y le asignamos a la variable Form2 el valor nil.

También podría gustarte