3.2.3. Estructura de un Programa en Delphi

Tomado de: http://www.programatium.com/manuales/delphi/5.htm

Estructura del código fuente.

En Delphi existen dos tipos de código fuente: el programa principal, que en nuestro caso es el que se almacena en el archivo .dpr (Proyecto Delphi) y que a su vez toma el nombre del ejecutable que estamos creando; y luego tenemos las unidades o programas que hemos hecho; son anexos al programa principal y Delphi los nombra con la extensión .pas.

Para el caso de los .dpr la estructura interna de su código fuente se puede ver haciendo click en la IDE de Delphi en Project y View Source, es como sigue:

Todos comienzan con la palabra reservada Program seguida del nombre del programa, aunque no es obligatoria conviene usarla para tener un control de qué programa se trata.

A continuación tenemos la palabra reservada uses luego de la cual se listan los nombres de los programas de biblioteca .pas, si no vamos a usar ninguna no es necesario usar esta cláusula aunque como veremos más adelante es extremadamente raro que no usemos al menos, una biblioteca.

Le sigue la palabra reservada const en la cual se se declaran las constantes absolutas del programa, no es obligatoria.

Luego tenemos la cláusula type, donde se declaran los tipos definidos por el usuario, tampoco es obligatoria.

A continuación la cláusula var luego de la cual se declaran las variables globales, es decir, las que son visibles a todo el programa.

Luego se declaran los procedimientos (procedure) y funciones (function) en el orden que se deseen.

Finalmente tenemos el bloque del programa principal comenzando por la palabra reservada begin y terminando con la palabra reservada end. (presta atención al punto). Ambos son obligatorios.

Entonces la estructura general es:

program nombre_del_programa;
uses Unit1, Unit2, Unit3… etc…
Const
……
Type
…..
var
….
procedure ejemplo1;
begin
…..
end;
function ejemplo2:
tipo_de_retorno;
begin
….
end;
begin
{ desarrollo del programa }
end.

Tomemos por ejemplo el .dpr de una aplicación que al hacer clic sobre un boton aparezca el mensaje Hola Mundo! el cual es este:

program Project1;

uses
Forms,
Unit1 in ‘Unit1.pas’ {Form1};

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

Como verás aquí faltan algunas de las cláusulas enumeradas antes pero eso es perfectamente válido pues no todas son obligatorias, lo que aquí vemos es lo mínimo necesario para formar una aplicación Windows de una sola ventana.

Hay varias cosas para explicar. Primero salta a la vista la presencia de la declaración Forms en la cláusula uses, Forms es una biblioteca que ya está predefinida en Delphi por lo que no tiene un .pas correspondiente en la carpeta de nuestro proyecto (en realidad el código fuente de la unidad Forms reside en otro lugar que está compartido a todos los proyectos creados con Delphi), luego tenemos esto: Unit1 in ‘Unit1.pas’ {Form1}; Unit1 no es más que el .pas que hemos modificado pero en este caso Delphi aclara que es el que está en Unit1.pas en la carpeta actual, lo que sigue entre llaves es un comentario que agrega el IDE de Delphi para hacernos saber que en esa unidad reside la declaración de la ventana Form1.

Luego notarás este comentario entre llaves {$R *.res} este no es un comentario normal, es una directiva de compilación como se denota por la combinación de los caracteres {$ seguida de una letra, en este caso la R, esta directiva de compilación le indica al compilador que tome en cuenta un archivo .res, los archivos .res se usan para almacenar recursos visuales o de audio para nuestra aplicación que luego copiará dentro del .exe final. En nuestro ejemplo no usamos ninguna de estas cosas, no hemos creado ningún archivo de recursos explícitamente, el IDE de Delphi lo ha hecho por nosotros (aunque podemos modificarlo para agregarle cosas este tema no será tratado en este tutorial), específicamente allí ha almacenado el ícono por omisión de nuestra aplicación. Más adelante explicaré cómo cambiar el ícono por omisión. En la directiva de compilación está indicado *.res, ese asterico no significa lo que normalmente significa en Windows (es decir “todos los archivos .res”) sino que quiere decir que el archivo de recursos tiene el mismo nombre que el .dpr.

Ahora concentrémonos en lo que está entre begin y end. del .dpr

El objeto Application es un objeto predefinido en todos los programas Delphi el cual hace referencia a la propia aplicación (nuestro programa Hola Mundo!), el método Initialize le indica al compilador que allí deben ejecutarse todos los procedimientos de inicialización requeridos por Windows para una aplicación. Luego sigue la llamada a la creación de la ventana, nuestra ventana. Y luego el método Run es la indicación de que debe ponerse en espera de eventos, lo que en Windows equivale a que la aplicación se está ejecutando. Estos tres pasos son los mínimos requeridos para una aplicación de al menos una ventana.

Si tenemos más de una ventana en nuestra aplicación, el IDE de Delphi agregará una llamada Application.CreateForm(); por cada una de ellas, pero es importante recordar que la primera llamada a CreateForm establece que esa ventana es la principal de la aplicación, esto significa que cuando se cierra (con Alt+F4 o haciendo click en el botón X de la esquina superior derecha) la ventana principal, se abandona el método Run y concluye la aplicación.

La estructura de una unidad Pascal.

Pasemos ahora al código fuente de nuestro programa, desde ahora las llamaré unidades.

La estructura general es como sigue:

unit Unit1; interface uses { Lista de unidades } type { Lista de tipos definidos por el usuario } { Luego encabezado de los procedimientos y funciones visibles desde afuera } var { variables visibles desde afuera } implementation uses { lista de unidades usadas localmente } var { variables visibles solo localmente } { Luego implementación de los procedimientos y funciones declaradas en interface más otras } initialization { código de inicialización } finalization { código de finalización } end.

Igual que en el caso de los .dpr no todas las cláusulas son obligatorias, en especial initialization y finalization que sirve para colocar código que se ejecutará antes de que se cargue la unidad y luego cuando esta termine de usarse.

Las que sí son obligatorias son unit seguido del nombre de la unidad que DEBE SER IGUAL AL NOMBRE FÍSICO DEL ARCHIVO .pas, interface, implementation y end. El resto de las cláusulas no son obligatorias.

Como verás una unidad tiene sus propias cláusulas uses, esto significa que una unidad puede usar a su vez otras unidades, ya sean predefinidas por Delphi o hechas por nosotros.

Todo lo que está declarado a continuación de la cláusulas interface hasta implementation es lo que puede “verse” desde otras partes de la aplicación. Para entender esto veamos el código fuente de la unidad Unit1 de nuestra aplicación Hola Mundo1! del capítulo anterior la cual, con nuestras reformas incluidas, debería verse más o menos así:

unit Unit1;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end;

var Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(‘Hola Mundo!’); end;

end.

Lo que haremos será mover las dos líneas “var Form1: TForm1” y ponerlas justo debajo de la palabra reservada implementation, de modo que esa parte del código quede como sigue:

implementation

var Form1: TForm1;

{$R *.dfm}

Ahora compilaremos de nuevo el programa, pero solo lo compilaremos sin ejecutarlo, esto se consigue presionando las teclas Ctrl+F9. Inmediatamente obtendermos un error de compilación, la siguiente figura lo muestra:

Fig. 1 – Error de compilación.

El IDE de Delphi nos trae en la ventana Editor de Código el código de nuestro .dpr resaltando la línea donde encontró el error y debajo aparece una nueva ventana con el mensaje de error, el cual es: [Error] Project1.dpr(11): Undeclared identifier: ‘Form1’, el cual quiere decir que la variable Form1 no está declarada o no está visible para el .dpr al compilar la línea 11 ¿por qué?, porque en la unidad Unit1 nosotros dejamos de hacer visible desde fuera de la unidad la variable Form1. Para reparar esto solo es necesario volver a hacer visible esa variable trayéndola de nuevo a la sección interface de la unidad Unit1. Restaura las lineas que movimos a su lugar y vuelve a compilar el proyecto con Ctrl+F9.

Esto me lleva a decir que las unidades Pascal sirven para no redundar código, es decir, no declarar más de una vez una misma variable o procedimiento, el uso de las unidades sirve para concentrar el código en común a toda la aplicación en un solo código fuente, bastando solamente compartir lo que nos interesa que sea visible desde otros lugares de la aplicación. Pero también para hacer uso de ella es necesario agregar el nombre de la unidad donde reside tal declaración a la cláusula uses de la unidad donde se necesite.

Esto último es evidente tanto en el .dpr de nuestro proyecto como en la propia unidad Unit1. Si miras ambas cláusulas uses verás que están listadas un montón de unidades, en especial la cláusula uses de la unidad Unit1 contiene 10 llamadas a unidades externas, ninguna de las cuales las hemos hecho nosotros mismos sino que están predefinidas por Delphi. Esas unidades se llaman unidades estandar, en ellas están, entre otras cosas, declarado el procedimiento ShowMessage que usamos en el evento OnClick del Button, concretamente en la unidad Dialogs. Podemos hacer este experimento. Encierra con llaves a modo de comentario la llamada a Dialogs en la lista de uses de la unidad Unit1 de modo que toda la declaración quede asi:

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, { Dialogs, } StdCtrls;

Compila con Ctrl+F9 y verás que obtienes un error en la llamada a ShowMessage, esto se debe a casi lo opuesto del error que vimos antes, aquí lo que el compilador no encuentra es dónde está declarado el procedimiento ShowMessage entonces asume, como en el caso anterior que se trata de un identificador desconocido.

Exportando variables, tipos, procedimientos y funciones.

Los usos de las unidades de biblioteca (units) de Pascal sirven para hacer visibles variables globales, tipos definidos por el usuario, procedimientos y funciones. Me voy a concentrar en estos dos últimos ya que me parece que el tema de las variables globales quedará más claro de esta forma mientras que de los tipos nos ocuparemos más adelante en este tutorial.

Los procedimientos son pequeños algoritmos dentro del gran algoritmo que es una unidad Pascal. Es la implementación de la filosofía de programación top-down, también llamada programación descendente en donde el problema mayor se divide en problemas menores que se resuelven por separado. Cada procedimiento o función es un programa en sí mismo, más o menos independiente del resto y que a su vez puede llamar a otros procedimientos y funciones dentro de la misma unidad o en otra unidad como ya hemos visto.

La estructura general de un procedimiento Pacal es como sigue:

procedure Nombre_del_procedimiento(parametro: tipo); const { lista de constantes } var { lista de variables locales al procedimiento } begin { desarrollo del procedimiento } end;

Como verás se parece bastante al código que está en el .dpr. Solo son obligatorias las palabras reservadas procedure, begin y end, var y const se usan solo si se necesitan.

En el caso de usar var la declaración de variables solo tienen ámbito en ese procedimiento, es decir, esas variables son de caracter local al procedimiento. Pueden ser de un tipo declarado en la type de la unidad. Los procedimientos pueden hacer uso de otros procedimientos dentro de la misma unidad o los que estén exportados en las unidades de la cláusula uses de esa unidad. La única forma de comunicar resultados fuera del procedimieto es atravez de sus parámetros o bién mediante el uso de variables globales pero esto no es recomendable como veremos más adelante.

La declaración general de una función es como sigue:

function Nombre_de_la_funcion(parametro: tipo): tipo; const { lista de constantes } var { lista de variables locales a la función } begin { desarrollo de la función } end;

Es muy parecida la procedure pero difiere en su comportamiento, las functions SIEMPRE devuelven un valor que será del tipo indicado al final de su encabezado. En Object Pascal (y por ende en Delphi) todas las functions tienen una variable implícitamente definida llamada Result que sirve para enviar el valor de retorno al lugar desde donde es llamada la función. En algun lugar dentro de begin … end esta variable se le debe asignar un valor y puede ser usado como si fuera una variable local más.

Veremos con más detalles algunos aspectos particulares de los procedimientos y funciones más adelante en este tutorial.

Deja un comentario