Aprendiendo BORLAND Delphi. Marta Sananes Universidad de Los Andes, Venezuela. Mayo 2002.

HolaForma Revisar el programa
El siguiente ejemplo es una aplicación que se comunica con los usuarios mediante una ventana o forma de interfaz gráfica. Al igual que el ejemplo HolaLee , este programa simula la parte de un Sistema de Información que captura datos personales de alumnos. Para Delphi es un proyecto construido en forma visual con su ambiente de desarrollo. Si el programador lo desea, puede establecer además comunicación con los usuarios en modo "Consola", mediante el uso de los procedimientos Read, ReadLn, Write, WriteLn, lo cual puede ser útil en la fase de pruebas de programas. Para ello basta con compilar la aplicación bajo la Opción "Generate Console Application" o colocando la directiva al compilador {$APPTYPE CONSOLE}. (Por defecto la directiva que aplica es la {$APPTYPE GUI}).

La construcción de un Proyecto (Project) con interfaz gráfica (GUI) comienza siempre con la construcción de la Forma. Delphi va generando los archivos del Proyecto. Después el programador va agregando código de programación ObjectPascal a los procedimientos de respuesta de los Eventos de los usuarios, según el plan de la aplicación. Puede agregar sus propias declaraciones y procedimientos, incluyendo nuevas Clases con sus métodos. En una aplicación compleja puede agregar más Formas. Por cada Forma se genera una Unit  (archivo o módulo OP con declaraciones y código de programación). También puede agregar Units sin formas asociadas.

Con este ejemplo se muestra otra manera de hacer las cosas. Se intenta no sólo desarrollar una aplicación para una necesidad particular sino a la vez planificar y desarrollar recursos programados reusables para un dominio de aplicación (contexto organizacional) en el que ella se inserta. La planificación y diseño (Arquitectura de software) busca: standarizar uso del almacenamiento y procedimientos, resguardar la integridad de los datos, facilitar el desarrollo de futuras aplicaciones o sistemas de información, permitir enfrentar el desarrollo de aplicaciones y sistemas de gran complejidad, facilitar la verificación y el mantenimiento de aplicaciones y sistemas . El paradigma de Programación Orientada a Objetos (OOP), soportado en Delphi y otros lenguajes, permite el logro de esos objetivos con gran eficiencia.

También este ejemplo muestra en forma simple la aplicación de un criterio arquitectónico muy productivo en Computación: el diseño e implantación (arquitectura e ingeniería) por capas o niveles.Cada capa consiste en uno o más Librerías que proporcionan un conjunto de recursos y servicios. Las capas a bajo nivel o básicas proporcionan recursos y servicios de propósito general mientras que capas a niveles más altos proporcionan recursos y servicios cada vez más especializados y orientados a dominios particulares. Con la OOP en las librerías se definen jerarquías de Clases de Objetos extensibles o adaptables en librerías de capas superiores. 

El concepto de Objeto integra en un solo ente recursos (atributos) y servicios (métodos). En el lenguaje ObjectPascal de Delphi las librerías se construyen como módulos tipo Unit o como módulos tipo Library. Las Units al compilarse generan archivos de extensión .dcu (Delphi Compiled Unit), que se enlazan en tiempo de compilación con la aplicación. 

Delphi proporciona una extensa jerarquía de Clases en diversas Units. Uno de los beneficios esperados de la OOP es que desarrolladores independientes distribuyan Librerías con Clases aprovechables por otros desarrolladores para facilitar la construcción de aplicaciones complejas. El trabajo necesario para desarrollar librerías de niveles genéricos se compensa ampliamente con la facilidad para desarrollar y mantener aplicaciones complejas, más especializadas, a niveles superiores.

El contenido de los archivos se muestra en forma de tablas, en la columna izquierda el código en ObjectPascal y en la derecha explicaciones y comentarios. En los archivos de programa (.dpr y .pas), las líneas que son generadas automáticamente por Delphi están en color amarillo; en blanco sólo las que el programador tuvo que agregar. Aparecen resaltadas en ambos casos las palabras reservadas de ObjectPascal, tal como lo hace el Editor de Delphi.
Se muestra el contenido de los cinco archivos que conforman este proyecto, en orden ascendente por capas:

DatosValidos.pas: es una Unit que contiene la definición de la jerarquía de clases de datos diseñada para soportar manejo de diversos tipos de datos con integridad. Tiene un diseño genérico, para que pueda ser aplicable a cualquier dominio. Como ejemplo sencillo de aplicación del criterio de desarrollo por capas, corresponde a una capa de nivel básico, que utiliza a su vez, como todos los demás archivos, las librerías de las capas aún más básicas proporcionadas por Delphi.

Alumno.pas: es una Unit que contiene la definición de una clase diseñada (en forma muy simplificada) para el manejo del tipo de entes asociados al dominio de la aplicación particular: alumnos de un postgrado. Como capa utiliza las clases definidas en DatosValidos.pas para definir la clase TAlumno que queda disponible para
ésta y otras aplicaciones en el mismo dominio.

HolaFormaU.pas: es la Unit que contiene la programación correspondiente a la forma de interfaz de usuario del proyecto particular. Como capa, corresponde al nivel más alto utilizado en el proyecto, utilizando a su vez la clase definida en Alumno.pas.

HolaFormaU.dfm: es parte de la visualización en modo texto de la Forma diseñada por el programador como interfaz de usuario. Este archivo de extensión .dfm (Delphi ForM) contiene las declaraciones correspondientes al diseño de la Forma; es generado por Delphi transcribiendo la construcción que hace el usuario en forma visual. No hace falta que el programador vea este archivo ni debe modificar manualmente el texto, Delphi se encarga de su actualización cada vez que visualmente se modifique la apariencia o el contenido de la Forma asociada, ya sea por acciones directas sobre la Forma o modificando propiedades con el Object Inspector .

HolaForma.dpr: es el archivo raíz o índice del proyecto, de extensión .dpr (Delphi PRoject).

DatosValidos.pas
 
unit DatosValidos;
interface
uses StdCtrls, Dialogs, Controls, Forms, SysUtils;
Unit construida por el programador.
Comienzo de bloque de declaraciones.
Units que contienen librerías Delphi utilizadas.
type
   TDatoTexto  = class
   protected
      pNombreDato: string;
      pDato: string;
      pAsignado: boolean;
      SuEdit: TEdit;
   public 
Comienzo de declaraciones de tipos (tipos de datos y clases)

Se define nueva clase, por defecto, hija de TObject, clase raíz de todas las clases en Delphi.
El nivel de protección protected establece que sólo la clase y sus descendientes tienen acceso a la lista protegida.
El resto tiene acceso público (sin rectricción)

     constructor Crea(const aNombreDato: string
                       aSuEdit:TEdit);
     constructor CreaInicia(const aNombreDato,
                 aDato: string; aSuEdit:TEdit);
Un constructor es un método especializado para instanciar objetos de la clase. Toda clase en Delphi tiene al menos un constructor heredado de TObject: Create. Se pueden definir varios.
Observe la declaración de dos métodos constructores.
El segundo adicionalmente asigna un valor al dato.
  procedure   EntradaDato; virtual; Observe la declaración de este método con el calificativo virtual, que indica que en los objetos de clases descendientes se selecciona siempre dinámicamente (en tiempo de ejecución) la versión propia de su clase, aún cuando la referencia se haga con un nombre de objeto declarado en una clase antecesora. 
Esto es Polimorfismo en OOP.
  function    NombreDato: string;
    function    Dato: string;
    function    Asignado: boolean;
Función: Código reutilizable que retorna un valor del tipo especificado. 
Métodos-Funciones para obtener los valores de los atributos protegidos.
El método-función Asignado retorna verdad cuando se ha registrado un dato que pasa los controles de validación.
  end; Fin de la declaración de la clase.
   TDatoCuantitativo = class (TDatoTexto)
   protected
      limI, limS: double;
      ValorNumerico: double;
      pUnidad: string;
      procedure Valida;
Clase descendiente de TDatoTexto para registrar y validar datos numéricos. Diseñada para manejar tipo de dato double, el tipo real más general en Delphi después del extended. Sus descendientes pueden diseñarse para soportar otros tipos numéricos.
(En Delphi el tipo Pascal real equivale a double, ver real types en el Help de Delphi)
Para datos numéricos se registra Rango de validez, valor asignado válido (ValorNumerico) y nombre de Unidad de medición del dato.
El método Valida aplica los controles de validación.
  public El resto tiene acceso público (sin rectricción)
      constructor Crea(const aNombreDato: string;
                       aSuEdit:TEdit;
                       alimI, alimS: double; 
                  const aUnidad: string);
Al crear un objeto de la clase, se define el Rango de validez y la Unidad de medición. También se establece la relación, através del parámetro aSuEdit con un control de tipo TEdit donde el usuario escribe el dato que el método EntradaDato recoge.
      procedure    EntradaDato; override; El calificativo override indica que ésta es la versión polimórfica del método virtual definido en TDatoTexto.
  function     LimiteInferior: double;
      function     LimiteSuperior: double;
      function     Valor: double;
      function     Unidad: string;
Siguen las definiciones de métodos-funciones para obtener los valores de los atributos protegidos.
   end; Fin de la declaración de la clase.
   TDatoEntero = class(TDatoCuantitativo)
   protected
     pValor: integer;
   public
     constructor CreaInicia(
       const aNombreDato,aDato: string;
                 aSuEdit: TEdit;
                 alimI, alimS: double;
       const aUnidad: string);
Definición de descendiente de TDatoCuantitativo para datos tipo entero.
Se agrega un atributo para guardar el valor entero.
Se agrega un constructor propio para inicializar valor de dato. const indica que los parámetros son referencias a variables no modificables definidas en el entorno que invoque al método. Los valores de parámetros sin calificativo se guardan localmente y sólo son modificables internamente.
  procedure   EntradaDato; override; Versión polimórfica del método EntradaDato.
  function    Valor: integer; Se redefine la función Valor, para entregar entero.
Un método que se declara con el mismo nombre de uno ya existente en la clase o en alguna antecesora, pero con diferente encabezado (lista de parámetros o tipo de resultado si es función), se interpreta como un método distinto. Se dice en OOP que se hace sobrecarga (overload) del nombre.
  end; Fin de la declaración de la clase.
   TDatoSimple = class(TDatoCuantitativo)
   protected
      pValor: single;
   public
Definición de otro descendiente de TDatoCuantitativo para datos tipo simple. Se agrega un atributo para guardar el valor simple (simple precisión, ver real types en Help)
       constructor CreaInicia(
        const aNombreDato,aDato: string;
                   aSuEdit: TEdit;
                   alimI, alimS: double;
        const aUnidad: string);
Constructor propio para inicializar valor de dato.
  procedure    EntradaDato; override;
     function     Valor: single;
   end;
Versión polimórfica del método EntradaDato.
Se redefine la función Valor, para entregar single.
Fin de la declaración de la clase.
   TDatoDoble = class(TDatoCuantitativo)
   public
     constructor CreaInicia(
       const aNombreDato,aDato: string;
                 aSuEdit: TEdit;
                 alimI, alimS: double;
       const aUnidad: string);
     procedure    EntradaDato; override;
Definición de otro descendiente de TDatoCuantitativo para datos tipo doble. 
TDatoCuantitativo ya registra dato tipo double. Sólo hay que definir el constructor CreaInicia y el método polimórfico EntradaDato.
  end; Fin de la declaración de la clase.
implementation

var coderr: integer; 
 

Comienzo de bloque de implementación de métodos de las clases definidas y de procedimientos y funciones no asociados a ninguna clase. En esta sección también puede definirse variables internas a la Unit. En este caso se define una variable global interna  que guarda el estado de la última validación de datos.
constructor TDatoTexto.Crea( 
          const aNombreDato:string;
                     aSuEdit:TEdit);
begin
  inherited Create;
  pNombreDato:=aNombreDato; pDato:='';
  pAsignado:=false;
  SuEdit:=aSuEdit;
end;
Codificación del primer constructor de la clase TDatoTexto.
Recibe valores de la referencia al Nombre que se asigna al Objeto y al de la referencia al TEdit asociado.
Lo primero que hay que hacer es invocar al método constructor heredado (inherited) de su antecesor inmediato, la clase TObject, para que Delphi se encargue de la tarea inicial de creación. Después se agrega lo específico de la nueva clase, en este caso, guardar los valores de los parámetros en atributos protegidos.
constructor TDatoTexto.CreaInicia(
          const aNombreDato, aDato: string;
                     aSuEdit:TEdit);
begin
  Crea(aNombreDato,aSuEdit);
  pDato:=aDato;  pAsignado:=true;
end;
Codificación del segundo constructor de la clase TDatoTexto.
Invoca al otro constructor y luego agrega lo específico de este constructor, que es la asignación de valor al dato.
procedure TDatoTexto.EntradaDato; 
begin
  pAsignado:=true; pDato:=SuEdit.Text;
  if pDato='' then pAsignado:=false;
end;
Cada clase descendiente puede definir su propia versión polimórfica del procedimiento EntradaDato.
Toma el valor textual del dato de la propiedad Text del TEdit asociado. Si es vacío, lo da por no asignado.
function    TDatoTexto.NombreDato: string;
   begin       Result:=pNombreDato;   end;
function    TDatoTexto.Dato:       string;
   begin       Dato:=pDato;           end;
function    TDatoTexto.Asignado:   boolean;
   begin       Result:=pAsignado;     end;
Codificación de funciones para acceder a los valores de atributos protegidas (protected).
Ver en el Help de Delphi la declaración de tipo de atributo property, que hubiera podido usarse alternativamente en en el caso de estos atributos.
constructor TDatoCuantitativo.Crea( 
       const aNombreDato: string;
                  aSuEdit: TEdit;
                  alimI, alimS: double;
       const aUnidad: string);
begin
  inherited Crea(aNombreDato,aSuEdit);
  ValorNumerico:=0;
  if alimI <=alimS then 
  begin limI:=alimI; limS:=alimS; end
  else
  if MessageDlg('Rango Inválido para '+NombreDato+ 
     '. Se asigna Valor Límite Inferior',mtError,
     [mbOK,mbCancel],0)=mrOK then
   begin limI:=alimI; limS:=alimI; end 
   else  Application.Terminate;
  pUnidad:=aUnidad;
end;
Codificación del constructor de decendiente de TDatoTexto.
Lo primero que hay que hacer es invocar a un método constructor heredado (inherited) de su antecesor inmediato, la clase TDatoTexto.
Inicializa al atributo protegido ValorNumerico.
Verifica que el rango sea consistente. Si no lo es, se da mensaje en forma interactiva, lo que permite al usuario continuar o cancelar la ejecución. (MessageDlg en Unit Dialogs).
Las constantes mrOK, ... están definidas en la Unit Controls.La Clase TApplication lo está en la Unit Forms. 
Ver HolaFormaU.pas)
procedure TDatoCuantitativo.EntradaDato;
begin
  inherited;
  coderr:=0; // para validación numérica
end;
Versión polimórfica del método EntradaDato. Base para versiones polimórficas de descendientes de la clase TDatoCuantitativo. Lo primero es invocar a la versión heredada del antecesor. (No hace falta poner el nombre por ser el mismo).
Observe el comentario estilo C++.
procedure TDatoCuantitativo.Valida;
begin
  if coderr > 0 then 
  begin pAsignado:=false;
        MessageDlg(pNombreDato+'Inválido',
                   mtError,[mbOK],0);
  end
  else if coderr = 0 then
if (ValorNumerico < limI) or (ValorNumerico > limS)
then
  begin pAsignado:=false;
    MessageDlg(pNombreDato+'Fuera de Rango: '+
               FloatToStr(limI)+', '+
               FloatToStr(limS),mtError,[mbOK],0);
  end;
end;
Este método se invoca después de tomado un dato y haberlo convertido a numérico con el procedimiento Val. En la variable global coderr se deja el estado exitoso o fallido de la conversión. Observe que aunque MessageDlg es una función, puede invocarse como procedimiento, descartando el resultado.
Si el dato es numérico, hay que validar además que esté dentro del rango definido.
Si no pasa las validaciones, queda no asignado.
Observe el uso de FloatToStr, una de las funciones de conversión de Delphi (Unit SysUtils). Ver Help.
function  TDatoCuantitativo.LimiteInferior: double;
begin    Result:=limI; end;
function TDatoCuantitativo.LimiteSuperior: double;
begin    Result:=limS; end;
function TDatoCuantitativo.Unidad: string;
begin    Result:=pUnidad; end;
Métodos-Funciones que entregan los valores de atributos protegidos.
function TDatoCuantitativo.Valor:          double;
begin    Result:=ValorNumerico; end;
Método-Función que entrega el valor numérico double.
constructor TDatoEntero.CreaInicia( 
       const aNombreDato,aDato: string;
           aSuEdit: TEdit;
           alimI, alimS: double;
       const aUnidad: string);
begin
  Crea(aNombreDato,aSuEdit,alimI,alimS,aUnidad);
  pDato:=aDato; Val(pDato,pValor,coderr);
  ValorNumerico:=pValor; Valida;
end;
Constructor propio disponible para cuando se quiere crear e inicializar valor del dato entero. Si no, basta usar el constructor heredado.
Se aplica primero el constructor heredado, después se toma y valida el valor inicial dado.
procedure TDatoEntero.EntradaDato; 
begin
  inherited;
  Val(pDato,pValor,coderr); ValorNumerico:=pValor;
  Valida;
end;
Versión polimórfica del método EntradaDato. Observe como a partir de la invocación del método heredado del mismo nombre, se ejecutan hacia atrás los demás de la subjerarquía que comienza con la clase TDatoTexto.
Se hace la conversión a numérico entero (indicado por el tipo de pValor) y se pasa a validar.
function  TDatoEntero.Valor: integer;
begin     Result:=pValor; end;
Método-Función que entrega el valor numérico integer.
constructor TDatoSimple.CreaInicia( 
       const aNombreDato,aDato: string;
           aSuEdit: TEdit;
           alimI, alimS: double;
       const aUnidad: string);
begin
  Crea(aNombreDato,aSuEdit,alimI,alimS,aUnidad);
  pDato:=aDato; Val(pDato,pValor,coderr);
  ValorNumerico:=pValor; Valida;
end;
Constructor propio disponible para cuando se quiere crear e inicializar valor del dato simple. Si no, basta usar el constructor heredado.
Se aplica primero el constructor heredado, después se toma y valida el valor inicial dado.
procedure TDatoSimple.EntradaDato;
  inherited;
  Val(pDato,pValor,coderr); ValorNumerico:=pValor;
  Valida;
end;
Versión polimórfica del método EntradaDato. Vale la misma obseración que en la versión para TDatoEntero.
Se hace la conversión a numérico simple (indicado por el tipo de pValor) y se pasa a validar.
function  TDatoSimple.Valor: single;
begin     Result:=pValor; end;
Método-Función que entrega el valor numérico single.
constructor TDatoDoble.CreaInicia(
       const aNombreDato, aDato: string;
           aSuEdit: TEdit;
           alimI, alimS: double; 
       const aUnidad: string);
begin
  Crea(aNombreDato,aSuEdit,alimI,alimS,aUnidad);
  pDato:=aDato; Val(pDato,ValorNumerico,coderr);
  Valida;
end;
Constructor propio disponible para cuando se quiere crear e inicializar valor del dato doble. Si no, basta usar el constructor heredado.
Se aplica primero el constructor heredado, después se toma y valida el valor inicial dado.
procedure TDatoDoble.EntradaDato;
begin
  inherited;
  Val(pDato,ValorNumerico,coderr); Valida;
end;
Versión polimórfica del método EntradaDato. Vale la misma obseración que en la versión para TDatoEntero.
Se hace la conversión a numérico doble (indicado por el tipo de ValorNumerico) y se pasa a validar.
end. Fin de la Unit.

Alumnos.pas
 
unit Alumnos;
interface
uses DatosValidos,Dialogs,Forms,StdCtrls,SysUtils;

type

Unit construida por el programador.
Comienzo de bloque de declaraciones.
En la lista de Units de la declaración uses se incluye a DatosValidos (la Unit anterior), que contiene clases que se aplican para definición de tipos de datos. Las demás Units son de Delphi.
  NombreCampos=(Nombre,Apellido, Edad, Peso, Altura); Tipo enumerado. Equivale a definir las constantes: Nombre=0,Apellido=1,Edad=2,Peso=3,Altura=4
Se usa para mejor legibilidad del código de programación.
  Editores = array[NombreCampos] of TEdit; Arreglo de referencias a objetos de tipo TEdit, indizados por los valores de tipo NombreCampos.
  TAlumno = class
    Campos: array[NombreCampos] of TDatoTexto;
    constructor Crea(const elEdit: Editores);
    function    MostrarDatos: boolean;
  end;
Definición de la clase TAlumno, descendiente de TObject, como lo es toda clase por defecto en Delphi. Se define con un único atributo de tipo múltiple (array). TDatoTexto es la clase raíz de la jerarquía de clases definida en DatosValidos (diversos tipos de datos con aplicación de reglas de validación). Cada campo se especializará al momento de creación de los respectivos objetos y para su uso se aprovechará la propiedad de Polimorfismo de la OOP.
Un constructor es un procedimiento especializado para instanciar objetos de la clase. Toda clase en Delphi tiene al menos un constructor heredado de TObject: Create. Se pueden definir varios.
Función: Código reutilizable que retorna un valor del tipo especificado. 
implementation Comienzo de bloque de implementación de métodos de las clases definidas y de procedimientos y funciones no asociados a ninguna clase. En esta sección también puede definirse variables internas a la Unit.
constructor TAlumno.Crea(const elEdit: Editores);
begin
 inherited Create;
 Campos[Nombre]:=TDatoTexto.CreaInicia('Nombre: ',
           elEdit[Nombre].Text, elEdit[Nombre]);
 Campos[Apellido]:=TDatoTexto.CreaInicia('Apellido:',
        elEdit[Apellido].Text,elEdit[Apellido]);
 Campos[Edad]:=TDatoEntero.Crea('Edad: ',
        elEdit[Edad],16,80,' años ');
 Campos[Peso]:=TDatoSimple.Crea('Peso: ',
        elEdit[Peso],40,120,' Kg. ');
 Campos[Altura]:=TDatoDoble.Crea('Estatura: ',
        elEdit[Altura],120,200,' cm. ');
end;
Con el constructor se crean y asignan las referencias a los objetos especializados para cada Campo. Por el parámetro elEdit se le entrega, como arreglo, la lista de las referencias a los controles TEdit de la Forma en los que se recibirán los respectivos datos del usuario. 
Para comenzar, se invoca al constructor heredado de la clase primitiva TObject.
CreaInicia es un constructor de la clase TDatoTexto definida en la Unit DatosValidos. Observe la forma especial de invocar a un constructor: se invoca como método de tipo función, no de un objeto particular ya creado, sino de la clase misma, por su nombre. Devuelve el valor de la referencia al objeto recién creado, el cual se asigna a la variable de tipo referencia a objetos de clase TDatoTexto, a la izquierda.
Observe la asignación de clase para los campos que alojarán valores numéricos (usables en expresiones aritméticas). Se aplican constructores de las clases derivadas de TDatoTexto definidas en la Unit DatosValidos.
function TAlumno.MostrarDatos: boolean;
var i: NombreCampos; Saludo, Mensaje: string;
begin
  Result:=true;
  Saludo:='Hola ';  Mensaje:='Datos Validados: ';
  for i:=Nombre to Altura do
    if not (Campos[i].Asignado) then
    begin
      MessageDlg('Entre o corrija su '+
          Campos[i].NombreDato,mtError,[mbOK],0);
    if Campos[i] is TDatoCuantitativo then
    with TDatoCuantitativo(Campos[i]) do
 MessageDlg('Rango válido: '+ 
 FloatToStr(LimiteInferior)+', '+
 FloatToStr(LimiteSuperior),mtInformation,[mbOK],0);
      Result:=false;
    end else
    begin
      if Campos[i] is TDatoCuantitativo then
    with TDatoCuantitativo(Campos[i]) do
    Mensaje:=Mensaje+NombreDato+Dato+Unidad+' '
    else Saludo:=Saludo+' ' + Campos[i].Dato;
    end;
  ShowMessage(Saludo);  ShowMessage(Mensaje);
end;
Método de tipo función que devolvuelve truesi el usuario introduce correctamente todos los datos solicitados en la forma, si no, devolvuelve false.

Observe la manera de asignar resultado a una función. También puede hacerse asignando el valor al nombre de la función usado como variable a la izquierda. 
Se le darán al usuario dos tipos de mensajes: uno para los datos no-numéricos y otro para los numéricos.

Observe el uso de la instrucción for para recorrer todos los campos definidos.
Con MessageDlg se dan mensajes informando de error u omisión en el campo. MessageDlg reside en la Unit Dialogs de Delphi.
Observe el uso del operador ispara averiguar si el objeto es de clase TDatoCuantitativo o de alguna descendiente.
Si el dato es numérico, se le informa al usuario cual es el Rango válido.
Observe el uso de la función FloatToStrpara convertir un valor numérico a string. 

Al fallar al menos un campo, se asigna resultado false.
Si los datos son todos correctos, se dan los mensajes de saludo mostrando los valores de los datos registrados.

end. Fin de la Unit.

HolaFormaU.pas
 
unit HolaFormaU; Unit preparada usando la programación visual de Delphi, que genera la declaración de la forma y los esqueletos de los métodos. El progrmador completa y agrega codificación en ObjectPascal.
interface Comienzo de bloque de declaraciones.

uses Windows, Messages, SysUtils, Classes,
     Graphics, Controls, Forms, Dialogs, 
     StdCtrls, ExtCtrls, DatosValidos, Alumnos;
Lista de Delphi-Units que contienen Clases de la jerarquía de Clases disponibles en Delphi.
El programador puede agregar Units propias a la lista. Para mejor control del proyecto por parte de Delphi conviene agregar Units existentes, sin o con Formas, con la opciones Add to Projecten  el menu Project. En este caso se han agregado las Units anteriores: DatosValidos y Alumnos.
Si se quiere crear nueva Unit o nueva Forma con su respectiva Unit, entonces utilice las opciones New Unit o New Form del menú File.
type
  TForm1 = class (TForm)
     elNombre: TEdit;   elApellido: TEdit;
       Panel1: TPanel;  laEdad: TEdit; 
       elPeso: TEdit;   laAltura: TEdit; 
       Label1: TLabel;  Label2: TLabel;
       Label3: TLabel;  Buton: TButton;
Delphi genera las declaraciones de los controles y componentes colocados por el programador en la forma y registra en el archivo de la forma (HolaFormaU.dfm en este caso) las propiedades asignadas con el ObjectInspector.
  procedure Inicial(Sender: TObject); 
     procedure LimpiaTexto(Sender: TObject);
     procedure GuardaTexto(Sender: TObject);
     procedure EntraTexto(Sender: TObject;
                          var Key: Char);
     procedure Salida(Sender: TObject);
     procedure SalidaClose(Sender: TObject;
                       var Action: TCloseAction);
     private { Private declarations }
     public { Public declarations }
Delphi genera los encabezados de los métodos que el programador asigna para responder a los eventos seleccionados en cada componente, incluyendo la forma misma. El programador puede agregar otros métodos (procedimientos y funciones) y atributos, públicos o privados.
  end; Fin de la declaración de la forma.

var
  Form1: TForm1;
  Alumno:  TAlumno; 
  LosEditores: Editores;
Se declaran 3 variables: la primera de tipo referencia a objeto de la clase TForma1, la segunda de tipo referencia a Objeto (instancia) de la clase TAlumno, definida en la Unit Alumnos. La tercera de tipo Editores, definido en Alumnos. Es un tipo array cuyos índices, definidos también en Alumnos, están en correspondencia con los atributos (Campos) definidos para la clase TAlumno.
implementation
{$R *.DFM}
Comienzo de bloque de implementación de métodos de las clases definidas y de procedimientos y funciones no asociados a ninguna clase. 
procedure TForm1.Inicial(Sender: TObject);
begin
  LosEditores[Nombre]:=elNombre;
  LosEditores[Apellido]:=elApellido;
  LosEditores[Edad]:=laEdad;
  LosEditores[Peso]:=elPeso;
  LosEditores[Altura]:=laAltura;
  Alumno:=TAlumno.Crea(LosEditores);
end;
Al iniciarse la ejecución del programa, Windows activa la Forma, e inmediatamente se ejecuta este método. (Respuesta al Evento OnActivate).
Aquí se inicializan los elementos del vector (array) con las referencias a los controles de tipo TEdit que se colocaron en la forma para recibir los datos del usuario.
Se termina la acción del método con la llamada al método constructor de la clase TAlumno para creae la instancia del objeto, cuya referencia se guarda en la variable Alumno
procedure TForm1.LimpiaTexto(Sender:TObject);
begin 
   TEdit(Sender).Text:='';
end;
Método de respuesta al evento OnClick en cualquiera de los componentes  de tipo TEdit. Observe el uso de casting para especializar el tipo TObject (que es la clase primitiva de todas las clases en Delphi) al tipo TEdit.
procedure TForm1.GuardaTexto(Sender: TObject);
begin 
  Alumno.Campos[NombreCampos
         (TEdit(Sender).Tag)].EntradaDato;
end;
Método de respuesta al evento OnExit en cualquiera de los componentes de tipo TEdit. OnExitse produce cuando el usuario se cambia de control. También se manda a ejecutar este procedimiento cuando el usuario termina la entrada de un dato con la tecla [Enter].
POLIMÓRFICAMENTE se ejecuta la versión de la clase específica que se usó al crear el campo. (Ver constructor de TAlumno en Alumnos).
Observe el uso del atributo Tag de TEdit. Delphi proporciona este atributo en los controles para que los programadores puedan asociar un valor numérico entero a cada control. En este caso se usa para hacer que el TEdit sirva como índice del array: TEdit(Sender).Tages un número entre 0 y 4 en este caso; el nombre de tipo NombreCampos se usa de castingal tipo entero del tag para compatibilizarlo con el tipo de índice definido para el arreglo de objetos Campos.
procedure TForm1.EntraTexto(Sender: TObject;
                            var Key: Char);
begin 
 if Key=#13{return} then GuardaTexto(Sender);
end;
Método de respuesta al evento OnKeyPress en cualquiera  de los componentes de tipo TEdit. Al recibir el Return se ordena ejecutar el método para asignación del dato.
procedure TForm1.Salida(Sender:TObject);
begin 
  If Alumno.MostrarDatos then Application.Terminate;
end;
Método de respuesta al evento OnClick en el componente de tipo TButton. Application es el nombre con el que Delphi designa a la aplicación en proceso. Es de Clase TApplication;
Terminate es uno de sus métodos. (Unit Forms)
procedure TForm1.SalidaClose(Sender: TObject;
                   var Action: TCloseAction);
begin
  if Alumno.MostrarDatos then Action:=caFree
  else Action:=caNone;
end;
Método de respuesta al evento de cerrado de la Forma. Devuelve a Windows en la referencia Action el tipo de acción especificada por el programador: caNone si no se quiere que la aplicación termine; caFree si sí. Con este programa si el usuario termina de entrar correctamente todos sus datos, la aplicación puede terminar (MostrarDatos retorna verdadero). Si no, debe continuar activa hasta que el usuario lo haga.
end. Fin de la Unit.

HolaFormaU.dfm
 

object Form1: TForm1
                    ................
    Caption = 'Entrada de Datos'
    ..............
    OnActivate = Inicial
    OnClose = SalidaClose
    object elNombre: TEdit
      Tag = 0
      .............
      Text = 'Alumno'
      OnClick = LimpiaTexto
      OnExit = GuardaTexto
      OnKeyPress = EntraTexto
    end
    object elApellido: TEdit
      Tag  = 1
      Text = ' Postgrado'
      OnClick = LimpiaTexto
      OnExit = GuardaTexto
      OnKeyPress = EntraTexto
    end
    object Panel1: TPanel
                       .............
      object Label1: TLabel
        ..............
        Caption = 'Edad'
      end
      object Label2: TLabel
        ..............
        Caption = 'Peso en Kg.'
      end
      object Label3: TLabel
        ..............
        Caption = 'Estatura en cm.'
      end
      object laEdad: TEdit
        Tag = 2
        ..............
        OnClick = LimpiaTexto
        OnExit = GuardaTexto
        OnKeyPress = EntraTexto
      end
      object elPeso: TEdit
        Tag = 3
        ..............
        OnClick = LimpiaTexto
        OnExit = GuardaTexto
        OnKeyPress = EntraTexto
      end
      object laAltura: TEdit
        Tag = 4
        ..............
        OnClick = LimpiaTexto
        OnExit = GuardaTexto
        OnKeyPress = EntraTexto
      end
    end
    object Boton: TButton
      ..............
      Caption = 'Aceptar'
      TabOrder = 3
      OnClick = SalidaBoton
    end
    object Label4: TLabel
                        .............
                       Caption = 'Nombre: '
                        .............
    end
    object Label5: TLabel
                        .............
                       Caption = 'Apellido:'
                        .............
    end;
end

El archivo de extensión .dfm corresponde a la definición de esta forma. La forma contiene dos componentes de tipo TEdit, dos componentes de tipo TLabel, un componente de tipo TButton, un componente de tipo TPanel dentro del cual están 3 componentes más de tipo TLabel y 3 componentes más de tipo TEdit.

Se muestran sólo porciones del archivo. Observe
como quedan definidos cada uno de los controles
con los valores asignados durante el diseño con
el ObjectInspector o manipulando directamente
sobre el esqueleto de la forma. Observe lo valores asignados a los atributos Tag para hacerlos corresponder con el orden de definición de los atributos (campos) de la clase TAlumno en la Unit Alumnos.

HolaForma.dpr
program HolaForma; 

uses
   Forms, 
   HolaFormaU in 'HolaFormaU.pas' {Form1};
   DatosValidos in 'DatosValidos.pas',
   Alumnos in 'Alumnos.pas';
 

{$R *.RES}

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

Para proyectos diseñados con formas de interfaz gráfica para usuarios, Delphi genera el archivo de extensión .dpr. En la sección uses coloca los nombres y las ubicaciones de todas las Units incorporadas al proyecto, además de la referencia a la Delphi-Unit Forms, que contiene la Clase TForm, clase primitiva de todas las formas.