You are on page 1of 152

Introduccin a la

programacin
con
Object Pascal
Free Pascal / Lazarus
Escrito por: Motaz Abdel Azeem
Editado por: Pat Anderson, Jason Hackney
code.sd
30 Agosto 2012

Introduccin
Este libro est escrito para los programadores que quieran aprender el lenguaje Object Pascal.
Tambin es adecuado como primer libro de programacin para estudiantes nveles y no
programadores. Adems del lenguaje Object Pascal, se tratan tcnicas de programacin en general.
El lenguaje Object Pascal
La primera aparicin del lenguaje Pascal que di apoyo a la programacin orientada a objetos fu
realizado en 1983 por la compaa de computadoras Apple. Despus, Borland di soporte a la
programacin orientada a objetos a su famosa lnea Turbo Pascal.
Object Pascal es un lenguaje hbrido de propsito general (programacin orientada a objetos y
estructurada). Puede ser utilizado para una amplia gama de aplicaciones tales como el aprendizaje,
desarrollo de juegos, aplicaciones de negocios, aplicaciones de Internet, aplicaciones de
comunicacin, el desarrollo de herramientas y ncleos del sistema operativo.
Delphi
Tras el xito de Turbo Pascal, Borland decidi portarlo a Windows e introdujo la tecnologa de
componentes para ello. Delphi pronto se convirti en la mejor herramienta RAD (Rapid Application
Development) herramienta de ese momento.
La primera versin de Delphi fue lanzado en 1995 con un completo conjunto de componentes y
paquetes que soportaban Windows y el desarrollo de base de datos en las aplicaciones
Free Pascal
Despus de que Borland abandon el soporte para la lnea Turbo Pascal , el equipo de Free Pascal
comenz un proyecto de cdigo abierto para escribir desde cero un nuevo compilador compatible
con Turbo Pascal y luego con Delphi. Esta vez, el compilador Free Pascal estaba apuntando a otras
plataformas y sistemas operativos, como Windows, Linux, Mac, ARM, y WinCE.
La versin 1.0 del compilador Free Pascal fue lanzado en julio de 2000.
Lazarus
Free Pascal es un compilador, y carece de un entorno de desarrollo integrado (IDE) similar al IDE
de Delphi para Windows. El proyecto Lazarus se inici para proporcionar un IDE para Free Pascal.
Proporciona un editor de cdigo fuente, un depurador, y contiene una gran cantidad de marcos,
paquetes y libreras de componentes similares al IDE de Delphi.
La versin 1.0 de Lazarus fu publicada en agosto de 2012, pero hay una gran cantidad de
aplicaciones desarrolladas con las versiones anteriores (beta) de Lazarus. Una gran cantidad de
voluntarios escribieron paquetes y componentes de Lazarus, y la comunidad sigue creciendo.

Caractersticas de Object Pascal


Object Pascal es un lenguaje muy sencillo y fcil de leer para los principiantes, sus compiladores
son muy rpidos, y las aplicaciones que produce son fiables, rpidas y se pueden comparar con C y
C + +. Se pueden escribir aplicaciones grandes y robustas con su IDE (Lazarus y Delphi) sin
complejidad.
Autor: Motaz Abdel Azeem
Me gradu en la Universidad de Ciencia y Tecnologa de Sudn en 1999. y comenc a aprender
Pascal como segunda lengua despus de BASIC. Desde entonces, lo he estado usando
continuamente, y me parece una herramienta muy sencilla de usar y de gran alcance, especialmente
despus de estudiar C y C + +. Luego me mud a Delphi. Desde entonces he estado usando Delphi
y Lazarus para la mayora de mis aplicaciones. Yo vivo en Jartum. Mi trabajo actual es
desarrollador de software.

Creditos:
Primer Editor:
Pat Anderson se gradu de la Western Washington State College en 1968 y en la Escuela de
Derecho de Rutgers en 1975. Se desempea como Abogado de la Ciudad de Snoqualmie,
Washington. Pat comenz a programar en un modelo de Radio Shack TRS-80 III en 1982 con
intrprete BASIC incorporado, pero pronto descubri Turbo. l ha sido propietario de todas las
versiones de Turbo Pascal desde la 4,0 a la 7,0, y todas las versiones de Delphi desde la 1,0 a la 4,0.
Pat tom un descanso de la programacin a partir de 1998 hasta 2009, cuando se encontr con Free
Pascal / Lazarus, que reaviv su pasin por la programacin.
Segundo Editor
Jason Hackney es un graduado de la Escuela de Aviacin de la Universidad de Western Michigan.
l trabaja a tiempo completo como piloto profesional para una empresa de energa con sede en el
sudeste de Michigan. Jason ha sido un ocasional programador desde su primer contacto con el
Commodore 64 por el ao 1984. Una breve introduccin del Turbo Pascal en 1990, recientemente
reaviv su latente inters por la programacin despus de descubrir Linux, Lazarus, y Free Pascal.
Traductores: http://www.clubdelphi.com
mightydragonlor
FAUST
MAXIUM
AL GONZALEZ
rretamar
champy
Esta edicin:
Eduardo O. Lpez Garca
Licencia:
II

CC by http://creativecommons.org/licenses/by/3.0/deed.es
Entorno para los ejemplos del libro
Vamos a utilizar Lazarus y Free Pascal para todos los ejemplos de este libro. Usted puede obtener el
IDE Lazarus, incluyendo el compilador Free Pascal, desde este sitio: http://lazarus.freepascal.org
Si est usando Linux, entonces usted puede conseguir Lazarus en el repositorio de software. En
Ubuntu desde la consola se puede utilizar el comando:
sudo apt-get install lazarus
En Fedora puede usar el comando:
yum install lazarus
En Mandriva (o Mageia), puede usar el comando:
urpmi lazarus
Windows, Mac y BSD descargar desde:
Compilador: http://sourceforge.net/projects/freepascal
RAD/IDE: http://sourceforge.net/projects/lazarus/?
Lazarus es una aplicacin gratuita y de cdigo abierto. Y est disponible en muchas plataformas.
Las aplicaciones escritas en Lazarus se pueden volver a compilar en otra plataforma para producir
ejecutables para la misma. Por ejemplo, si usted escribe una aplicacin que utiliza Lazarus en
Windows, y desea producir un ejecutable de esa aplicacin para Linux, slo tiene que copiar el
cdigo fuente a Lazarus en Linux, y compilarlo.
Lazarus produce aplicaciones que son nativas (compiladas) de cada sistema operativo, y no requiere
ninguna librera adicional o mquinas virtuales. Por esa razn, es fcil de implementar y rpido en
su ejecucin.
Usando modo texto
Todos los ejemplos en los primeros captulos de este libro sern las aplicaciones de consola
(aplicaciones en modo texto / aplicaciones de lnea de comandos), ya que son estndares y fciles
de entender. Las aplicaciones con interfaz grfica de usuario se introducirn en captulos
posteriores.

III

Indice
1.........................................................................................................Introduccin
1........................................................................................................Captulo Uno
1.........................................................................................Lo bsico del lenguaje
2..............................................................................Nuestra primera Aplicacin
4.............................................................................................Otros ejemplos
6..........................................................................................................Variables
10.........................................................................................................Subtipos
11...........................................................................Bifurcaciones condicionales
11............................................................................................La condicin If
11................................................................Programa aire acondicionado:
13.......................................................................................Programa peso
15................................................................................Declaracin Case .. of
15............................................................................Programa restaurante
15........................................ Programa restaurante usando la condicin If
16............................................................Programa grados de estudiantes
17...................................................................................Programa teclado
19.............................................................................................................Ciclos
19..................................................................................................El ciclo for
20................................................. Tabla de multiplicar usando el ciclo for
21................................................................................. Programa factorial
22.......................................................................................Ciclo Repeat Until
22....................................... Programa restaurante usando el ciclo Repeat
24.................................................................................................Ciclo While
24............................................... Programa factorial usando el ciclo while
25............................................................................................................Strings
28..............................................................................................Funcin Copy
29..................................................................................Procedimiento Insert
30.................................................................................Procedimiento Delete
30...............................................................................................Funcin Trim
31................................................................................Funcin StringReplace
33..........................................................................................................Arreglos
36........................................................................................................Registros
37.........................................................................................................Archivos
38.......................................................................................Archivos de texto
39.........................................................................Leer un archivo de texto
41.......................................Creando y escribiendo en un archivo de texto
43.............................................................Agregando en un archivo de texto
43.........................................Programa agregando en un archivo de texto
44......................................................................Archivos de acceso aleatorio
44........................................................................................Archivos con tipo
45.................................................................................Programa de notas
46................................................................Leyendo notas de estudiantes
46.................................................Programa agregando notas de alumnos
48.........................................Programa crear y agregar notas de alumnos
49...............................................Programa base de datos de automoviles
50......................................................................................Copiando archivos
51........................................................Copiar archivos usando file of byte
53.........................................................................................Archivos sin tipo
IV

53................................Programa copiar archivos usando archivos sin tipo


55................................................Programa mostrar contenido de archivo
56..............................................................................................Fecha y Hora
59...........................................................................Comparacin Fecha/Hora
60..............................................................Programa grabador de noticias
61.....................................................................................................Constantes
61.......................................................Programa consumo de combustible
62...............................................................................................Tipos ordinales
63............................................................................................Conjuntos (Sets)
66..................................................................................Manejo de excepciones
66...............................................................................Declaracion Try except
67....................................................................................................Try finally
68................................Programa de divisin usando el mtodo try finally:
68............................................................................Elevando una excepcin
69.................................................................................................Ejemplo:
70......................................................................................................Captulo Dos
70..............................................................................Programacin Estructurada
71...................................................................................................Introduccin
71..............................................................................................Procedimientos
72.....................................................................................................Parmetros
74..................................Programa de restaurante usando procedimientos
75.......................................................................................................Funciones
76......................................Usando funciones en el programa Restaurante
77............................................................................................Variables locales
79.........................Aplicacin: base de datos de noticias (News database)
82........................................................Funciones como parmetros de entrada
83....................................Paramtros de salida en procedimientos o funciones
85................................................................Paso de parmetros por referencia
87........................................................................................................Unidades
91................................................................Unidades en Lazarus y Free Pascal
91.......................................................Unidades escritas por el programador
93........................................................................Calendario Islmico Hejri
96.............................Sobrecarga (overloading) de procedimientos y funciones
97.......................................................Valores por defecto para los parmetros
98.....................................................................Ordenando datos (data sorting)
98.........................................................Algoritmo de ordenacin por burbuja
100.....................Ordenando la lista de estudiantes por sus calificaciones
101................................................Algoritmo de ordenacin por seleccin
103.............................................................Algoritmo de ordenacin Shell
105...................................................................Ordenando cadenas (strings)
105............................................Ordenando a los estudiantes por nombre
106.................................................Comparando los algoritmos de ordenacin
110........................................................................................................Captulo 3
110............................................................................................La interfaz grfica
111.................................................................................................Introduccin
111...........................................................................La primera aplicacin GUI.
117...............................................................................Segunda aplicacin GUI
118..........................................................................Aplicacin Lista de objetos
119.....................................................................Aplicacin de edicin de texto
122..................................................................................Aplicacin de noticias
V

123.........................................................Aplicacin con un segundo formulario


124........................................................................................................Captulo 4
124..................................................................Programacin Orientada a Objetos
125.................................................................................................Introduccin
125.............................................................................Objeto = Cdigo + Datos
125..................................................................Primer ejemplo: Fecha y Hora
130..........................Aplicacin de noticias en Pascal Orientado a Objetos
136.....................................................................................Aplicacin Cola
140.........................................................................Archivo orientado a objetos
141........................................................Copiar archivos usando TFileStream
142.......................................................................................................Herencia

VI

Captulo Uno
Lo bsico del lenguaje

Nuestra primera Aplicacin


Una vez que Lazarus est instalado y en funcionamiento, podemos empezar un nuevo programa en
el men principal:
Project/New Project/Program
Podremos ver este cdigo en la ventana del editor de cdigo fuente:
program Project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
{$IFDEF WINDOWS}{$R project1.rc}{$ENDIF}
begin
end.

Podemos guardar este programa haciendo click en File/Save desde el menu principal, y entonces
darle un nombre como por ejemplo, first.lpi.
Entonces podemos escribir estas lneas entre las declaraciones begin y end:
Writeln('Esto es Free Pascal y Lazarus');
Writeln('Presione la tecla Enter para cerrar');
Readln;

El cdigo fuente completo ser:


program first;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
{$IFDEF WINDOWS}{$R first.rc}{$ENDIF}
begin
Writeln('Esto es Free Pascal y Lazarus');

Writeln('Presione la tecla Enter para cerrar');


Readln;
end.

La declaracin Writeln muestra texto en la pantalla (consola de windows). Readln detiene la


ejecucin para permitir al usuario leer el texto mostrado hasta que el/ella presione la tecla enter para
cerrar la aplicacin y retornar al IDE Lazarus.
Para ejecutar la aplicacin presione F9 o haga click sobre el botn:

Despus de ejecutar el programa first, debemos obtener la siguiente salida:


Esto es Free Pascal y Lazarus
Presione la tecla Enter para cerrar

Si usamos Linux, nos encontraremos con un nuevo archivo llamado (first) en un directorio de
programa y en Windows tendremos un archivo llamado first.exe. Ambos archivos se pueden
ejecutar directamente haciendo doble clic con el ratn. El archivo ejecutable se puede copiar a otros
ordenadores para funcionar sin la necesidad de la IDE de Lazarus.

Notas
Si la ventana de aplicacin de consola no aparece, podemos deshabilitar la depuracin en el men
de Lazarus:
Environment/Options/Debugger
En Debugger type and path seleccione (None)

Otros ejemplos
En el programa anterior cambie esta lnea:
Writeln('Esto es Free Pascal y Lazarus');

por esta:
Writeln('Este es un nmero: ', 15);

Luego presione F9 para ejecutar la aplicacin.


Debera obtener este resultado:
Este es un nmero: 15

Cambie la linea previa por la siguientes y ejecute la aplicacin cada vez:


Cdigo:
Writeln('Este es un nmero: ', 3 + 2);

Salida:
Este es un nmero: 5

Cdigo:
Writeln('5 * 2 = ', 5 * 2);

Salida:
5 * 2 = 10

Codigo:
Writeln('Este es un nmero real: ', 7.2);

Salida:
Este es un nmero real: 7.2000000000000E+0000

Cdigo:
Writeln('Uno, Dos, Tres : ', 1, 2, 3);

Salida:
Uno, Dos, Tres : 123

Cdigo:
Writeln(10, ' * ',

3 , ' = ', 10 * 3);

Salida:
10 * 3 = 30

Podemos escribir diferentes valores en la declaracin Writeln cada vez y ver el resultado. Esto nos
ayudar a entenderlo clramente.

Variables
Las variables son contenedores de datos. Por ejemplo cuando decimos que X = 5, , significa que X
es una variable y el valor de su contenido es 5.
Object Pascal es un lenguaje fuertemente tipapdo, esto quiere decir que deber declarar el tipo de
variable antes de poder poner un valor dentro de ella. Si declaramos X como Integer, significa que
slo podremos asignar nmeros enteros a X durante el tiempo de vida de la aplicacin.
Ejemplos de declaracin y uso de variables:
program FirstVar;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
var
x: Integer;
begin
x:= 5;
Writeln(x * 2);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Obtendremos 10 como valor de salida de la aplicacin.


Note que usamos la palabra reservada var , la que indica que las lneas siguientes sern
declaraciones de variables:
x: Integer;

Esto significa dos cosas:


1. El nombre de variable es X; y
2. el tipo de esta variable es Integer, que puede contener slo nmeros enteros sin fracciones.
Tambin puede tener valores negativos y los valores positivos. .
Y la declaracin:
x:= 5;

significa poner el valor 5 en la variable X.

En el siguiente ejemplo hemos agregado la variable Y:


6

var
x, y: Integer;
begin
x:= 5;
y:= 10;
Writeln(x * y);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

La salida de la aplicacin previa es:


50
Presione la tecla Enter para cerrar

50 es el resultado de la frmula (x * y).


En el siguiente ejemplo introduciremos un nuevo tipo de dato llamado character:
var
c: Char;
begin
c:= 'M';
Writeln('Mi primera letra es: ', c);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Este tipo slo puede contener una letra o nmero tomado como caracter alfanumrico no como
valor.
En el siguiente ejemplo introducimos el nmero tipo real, que puede poseer parte decimal:
var
x: Single;
begin
x:= 1.8;
Writeln('La capacidad del motor de mi auto es ', x, ' litros');
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Para escribir aplicaciones mas flexibles e interactivas, necesitamos aceptar ingresos del usuario. Por
ejemplo podramos pedirle al usuario que introduzca el nmero y a continuacin obtener este
nmero mediante el uso del procedimiento Readln:
var
x: Integer;
begin
Write('Por favor introduzca un nmero:');

Readln(x);
Writeln('Ha introducido: ', x);
Writeln('Presione la tecla enter para cerrar');
Readln;
end.

En este ejemplo, la asignacin del valor a X se realiza a travs del teclado en lugar de asignar un
valor constante en la aplicacin.
En el siguiente ejemplo se muestra una tabla de multiplicar para un nmero introducido por el
usuario:
program MultTable;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
var
x: Integer;
begin
Write('Por favor introduzca un nmero:');
Readln(x);
Writeln(x, ' * 1 = ', x * 1);
Writeln(x, ' * 2 = ', x * 2);
Writeln(x, ' * 3 = ', x * 3);
Writeln(x, ' * 4 = ', x * 4);
Writeln(x, ' * 5 = ', x * 5);
Writeln(x, ' * 6 = ', x * 6);
Writeln(x, ' * 7 = ', x * 7);
Writeln(x, ' * 8 = ', x * 8);
Writeln(x, ' * 9 = ', x * 9);
Writeln(x, ' * 10 = ', x * 10);
Writeln(x, ' * 11 = ', x * 11);
Writeln(x, ' * 12 = ', x * 12);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Tenga en cuenta que en el ejemplo anterior todo el texto entre comillas simples (') se muestra en la
ventana de la consola tl como es, por ejemplo:
' * 1 = '

Las variables y expresiones que se escriben sin comillas simples se evalan y se escribe como
valores.
Vea las diferencias entre las dos declaraciones siguientes:

Writeln('5 * 3');
Writeln(5 * 3);

El resultado de la primera declaracin es:


5 * 3

El resultado de la segunda es evaluado y luego mostrado:


15

En el siguiente ejemplo, haremos operaciones matemticas con dos nmeros (x, y), y vamos a
asignar el resultado en una tercera variable (Res):
var
x, y: Integer;
Res: Single;
begin
Write('Ingrese un nmero: ');
Readln(x);
Write('Ingrese otro nmero: ');
Readln(y);
Res:= x / y;
Writeln(x, ' / ', y, ' = ', Res);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Como la operacin de divisin, podra dar lugar a un nmero con una fraccin, hemos declarado la
variable Resultado (Res) como un nmero real (Single). Single significa un nmero real con punto
flotante de simple precisin.

Subtipos
Hay muchos subtipos para las variables, por ejemplo los subtipos de numeros enteros difieren en el
nmero de bytes requeridos para almacenarse en memoria y los valores que son capaces de
almacenar:
La tabla siguiente contiene tipos enteros, rango de valores que admiten y los bytes que ocupan en
memoria:
Type

Min value

Max Value

Size in Bytes

Byte

255

ShortInt

-128

127

SmallInt

-32768

32767

Word

65535

Integer

-2147483648

2147483647

LongInt

-2147483648

2147483647

Cardinal

4294967295

Int64

-9223372036854780000

9223372036854775807

Podemos obtener los valores mximos y mnimos que cada tipo puede almacenar mediante las
funciones Low, High respectivamente, y el tamao que ocupan en memoria mediante la funcin
SizeOf , tl como se muestra en el siguiente ejemplo:
program Types;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
begin
Writeln('Byte: Tamao = ', SizeOf(Byte),
', Valor mnimo = ', Low(Byte), ', Valor mximo = ',
High(Byte));
Writeln('Integer: Tamao = ', SizeOf(Integer),
', Valor mnimo = ', Low(Integer), ', Valor mximo = ',
High(Integer));
Write('Presione la tecla Enter para cerrar');
Readln;
end.

10

Bifurcaciones condicionales
Una de las caractersticas ms importantes de dispositivos inteligentes (como ordenadores,
dispositivos programables) es que pueden tomar acciones acordes a diferentes condiciones. Esto se
puede hacer mediante el uso de bifurcacin condicional. Por ejemplo, algunos coches cierran la
puerta cuando la velocidad alcanza o supera los 40 K / h. La condicin en este caso ser:
If velocidad es >= 40 and puertas estn desbloqueadas, then lock door.
Automviles, lavadoras, y muchos otros dispositivos contienen circuitos programables como
microcontroladores o procesadores pequeos como ARM. Tales circuitos pueden programarse
usando Asembler, C o Free Pascal de acuerdo a su arquitectura.

La condicin If
La declaracin del condicional if es muy sencilla y clara. En el ejemplo siguiente decidiremos si se
debe encender el aire acondicionado o n, de acuerdo a la temperatura ambiente introducida:
Programa aire acondicionado:
var
Temp: Single;
begin
Write('Por favor ingrese la temperatura de esta habitacin:');
Readln(Temp);
if Temp > 22 then
Writeln('Por favor encienda el aire acondicionado')
else
Writeln('Por favor apague el aire acondicionado');
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Hemos introducido la declaracin if then else , en este ejemplo: Si la temperatura es mayor que 22
entonces mostrar la primer sentencia
Por favor encienda el aire acondicionado

si no, (temperatura menor o igual a 22), entonces mostrar esta lnea:


Por favor apague el aire acondicionado

Podemos escribir mltiples condiciones tales como:


11

var
Temp: Single;
begin
Write('Por favor ingrese la temperatura de esta habitacin:');
Readln(Temp);
if Temp > 22 then
Writeln('Por favor encienda el aire acondicionado')
else
if Temp < 18 then
Writeln('Por favor apague el aire acondicionado')
else
Writeln('Do nothing');

Puede probar el ejemplo anterior con diferentes valores de temperatura para observar los resultados.
Podemos hacer las condiciones mas complejas para que sea mas til:
var

Temp: Single;
ACIsOn: Byte;
begin
Write('Por favor ingrese la temperatura de esta habitacin: ');
Readln(Temp);
Write(' Est el aire acondicionado encendido? (1 = Encendido,',
'0 = Apagado'));
Readln(ACIsOn);
if (ACIsOn = 1) and (Temp > 22) then
Writeln('No hacer nada, necesitamos seguir refrigerando')
else
if (ACIsOn = 1) and (Temp < 18) then
Writeln('Por favor apague el aire acondicionado')
else
if (ACIsOn = 0) and (Temp < 18) then
Writeln('No hacer nada, sigue haciendo fro')
else
if (ACIsOn = 0) and (Temp > 22) then
Writeln('Por favor encienda el aire acondicionado')
else
Writeln('Por favor ingrese un valor vlido');
Write('Presione la tecla Enter para cerrar');
Readln;
end.

En el ejemplo anterior hemos usado la nueva palabra (and) que significa que si la primera condicin
es verdadera (ACIsOn = 1), y tambin lo es la segunda (Temp > 22), entonces ejecuta la
declaracin Writeln. Si una o ambas de las condiciones es falsa saltar a la siguiente parte.
Si por ejemplo, el aire acondicionado est conectado a una computadora mediante un puerto serial
entonces podemos activarlo o desactivarlo desde esa aplicacin usandoutilizando procedimientos de
puerto serie o componentes que lo realicen. En este caso necesitamos agregar parmetros
adicionales para la condicin if, como por cuanto tiempo ha estado operando el aire acondicionado.
Si excede el tiempo permitido (por ejemplo 1 hora) entonces se debe desactivar independientemente
12

de la temperatura ambiente. Tambin podemos considerar la tasa de prdida de fro, si es muy lenta
(por la noche), entonces podramos mantenerlo apagado por ms tiempo.

Programa peso

En este ejemplo, se solicita al usuario que introduzca su altura en metros, y el peso en Kilos.
Entonces el programa calcular el peso adecuado para esa persona de acuerdo a los datos
introducidos y, a continuacin, le dir a l/ella los resultados:
program Weight;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
Height: Double;
Weight: Double;
IdealWeight: Double;
begin
Write('Cul es su altura en metros ? (por ejemplo 1,8 metros):');
Readln(Height);
Write(' Cul es su peso en kilos ?: ');
Readln(Weight);
if Height >= 1.4 then
IdealWeight:= (Height - 1) * 100
else
IdealWeight:= Height * 20;
if (Height < 0.4) or (Height > 2.5) or (Weight < 3) or
(Weight > 200) then
begin
Writeln('Valores no vlidos');
Writeln('Por favor, introduzca los valores adecuados');
end
else
if IdealWeight = Weight then
Writeln('Su peso es adecuado')
else
if IdealWeight > Weight then
Writeln('Usted est bajo de peso, usted necesita ',
Format('%.2f', [IdealWeight - Weight]), ' Kilos mas')
else
Writeln('Usted tiene sobrepeso, necesita perder ',
Format('%.2f', [Weight - IdealWeight]), ' Kilos');
Write('Presione la tecla Enter para cerrar');
Readln;

13

end.

En este ejemplo hemos usado nuevas palabras clave:


1. Double: que es similar a Single. Ambos son nmeros reales, pero Double es de punto
flotante de doble precisicin, y ocupa 8 bytes en memoria, mientras que Single slo ocupa 4
bytes.
2. La segunda nueva palabra clave es (Or) y la hemos utilizado para comprobar si una de las
condiciones se cumple o no. Si una de las condiciones se cumple entonces se ejecuta la
instruccin. Por ejemplo: Si la primer condicin (Height < 0.4) devuelve verdadero (True)
,entonces la sentencia Writeln es llamada: Writeln('Valores no vlidos'); . Si la primera
condicin devuelve falso (False) entonces comprobar la segunda, etc. Si todas las
condiciones devuelven False ir a la proxima sentencia.
3. Hemos utilizado las palabras clave begin end con la sentencia if para tomar varias
declaracines como si fuese una, begin end agrupa mltiples sentencias que deben ser
considerados como un bloque (declaracin), entonces varias sentencias podran ser
ejecutadas por si condicin. Mire estas dos declaraciones
Writeln('Valores invlidos');
Writeln('Por favor, introduzca los valores adecuados ');

Estas han sido convertidas a una sola declaracin mediante el uso de begin end:
if (Height < 0.4) or (Height > 2.5) or (Weight < 3) or
(Weight > 200) then
begin
Writeln('Valores invlidos');
Writeln('Por favor, introduzca los valores adecuados ');
end

4. Hemos utilizado el procedimiento Format, que muestra los valores en un formato especfico.
En este caso se necesita mostrar slo 2 dgitos despus del punto decimal. Tenemos que
aadir la unidad SysUtils a la clusula uses para poder utilizar esta funcin.
Cul es su altura en metros ? (por ejemplo 1,8 metros): 1.8
Cul es su peso en kilos ? : 60.2
Usted est bajo de peso, usted necesita 19.80 Kilos mas

Nota:
Este ejemplo puede no ser fiable al 100%. Puede buscar en la web para el clculo del peso en
detalle. Nosotros slo pretendemos explicar cmo el programador podra solucionar estos
problemas y hacer un buen anlisis de la materia para producir aplicaciones confiables.

14

Declaracin Case .. of
Existe otro mtodo para la ramificacin condicional, que es la declaracin Case .. Of. Se ramifica
ejecucin de acuerdo con el valor ordinal del caso. El programa del restaurante ilustra el uso de la
declaracin case of :

Programa restaurante
var
Meal: Byte;
begin
Writeln('Bienvenido al Restaurante Pascal. Por favor, seleccione su orden');
Writeln('1 - Pollo
(10$)');
Writeln('2 - Pescado
(7$)');
Writeln('3 - Carne
(8$)');
Writeln('4 Ensalada
(2$)');
Writeln('5 Jugo de naranja (1$)');
Writeln('6 Leche
(1$)');
Writeln;
Write('Por favor ingrese su eleccin: ');
Readln(Meal);
case Meal of
1: Writeln('Ud. ha ordenado pollo,',
' esto tardar 15 minutos');
2: Writeln('Ud. ha ordenado Pescado, esto tardar 12 minutos');
3: Writeln('Ud. ha ordenado Carne, esto tardar 18 minutos');
4: Writeln('Ud. ha ordenado Ensalada, esto tardar 5 minutos');
5: Writeln('Ud. ha ordenado Jugo de naranja,',
' esto tardar 2 minutos');
6: Writeln('Ud. ha ordenado Leche, esto tardar 1 minuto');
else
Writeln('Entrada errnea');
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Si escribimos la misma aplicacion usando el condicionla if .. then se volver ms complicado y


contendr duplicaciones:

Programa restaurante usando la condicin If


var

15

Meal: Byte;
begin
Writeln('Welcome to Pascal restaurant, please select your meal');
Writeln('1 - Pollo
(10$)');
Writeln('2 - Pescado
(7$)');
Writeln('3 - Carne
(8$)');
Writeln('4 - Ensalada
(2$)');
Writeln('5 - Jugo de naranja (1$)');
Writeln('6 - Leche
(1$)');
Writeln;
Write('Por favor ingrese your selection: ');
Readln(Meal);
if Meal = 1 then
Writeln('Ud. ha ordenado Pollo, esto tardar 15 minutos')
else
if Meal = 2 then
Writeln('Ud. ha ordenado Pescado, esto tardar 12 minutos')
else
if Meal = 3 then
Writeln('Ud. ha ordenado Carne, esto tardar 18 minutos')
else
if Meal = 4 then
Writeln('Ud. ha ordenado Ensalada, esto tardar 5 minutos')
else
if Meal = 5 then
Writeln('Ud. ha ordenado Jugo de naranja,' ,
' esto tardar 2 minutos')
else
if Meal = 6 then
Writeln('Ud. ha ordenado Leche, esto tardar 1 minute')
else
Writeln('Entrada errnea');
Write('Presione la tecla Enter para cerrar');
Readln;
end.

En el siguiente ejemplo, la aplicacin evalua las notas de los estudiantes y las convierte en
categorias: A,B,C,D,E y F:

Programa grados de estudiantes

var
Mark: Integer;
begin
Write('Por favor ingrese la nota del estudiante: ');
Readln(Mark);
Writeln;
case Mark of
0 .. 39 : Writeln('El grado del estudiante es: F');

16

40 .. 49: Writeln('El grado del estudiante es: E');


50 .. 59: Writeln('El grado del estudiante es: D');
60 .. 69: Writeln('El grado del estudiante es: C');
70 .. 84: Writeln('El grado del estudiante es: B');
85 .. 100: Writeln('El grado del estudiante es: A');
else
Writeln('Nota errnea');
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.

En el ejemplo previo hemos usado un rango, como (0..39), que indica que la condicin devolver
True si la nota se encuentra en dicho rango.

Note:
La declaracin Case trabaja solo con tipos ordinales como Integer, char, pero no lo hace con otros
tipos como string o nmeros reales.

Programa teclado

En este ejemplo, tomaremos un caracter desde el teclado y la aplicacin nos dir en que nmero de
fila del teclado se encuentra ese caracter:
var
Key: Char;
begin
Write('Por favor, introduzca una letra inglesa: ');
Readln(Key);
Writeln;
case Key of
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p':
Writeln('Est en la segunda fila del teclado');
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l':
Writeln('Est en la tercera fila del teclado ');
'z', 'x', 'c', 'v', 'b', 'n', 'm':
Writeln('Est en la cuarta fila del teclado');
else
Writeln('Letra desconocida');
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Tenga en cuenta que se ha utilizado una nueva tcnica en la condicin de case, que es un conjunto
17

dewhich means execute case branch statement if the Key was one of these values set: valores:
'z', 'x', 'c', 'v', 'b', 'n', 'm':

lo que significa que ejecutara la sentencia si Key tiene uno de los valores del set declarado:
z, x, c, v, b, n, m
Tambin se puede mezclar rangos de valores definidos as:
'a' .. 'd', 'x', 'y', 'z':

que significa: ejecuta la sentencia si el valor esta entre a y d o es igual a x, y z.

18

Ciclos
Los cclos son usados para ejecutar ciertas partes de cdigo (sentencias) una cantidad especfica de
veces, o hasta que una condicin sea satisfecha:

El ciclo for
Usted puede ejecutar la sentencia for un nmero determinado de veces usando un contador como en
este ejemplo:
var
i: Integer;
Count: Integer;
begin
Write('Cuantas veces? ');
Readln(Count);
for i:= 1 to Count do
Writeln('Hola');
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Debemos utilizar tipos ordinales como Byte, Entero, y Char en las variables de bucle. Llamamos a
esta variable a variable de bucle o bucle contador. El valor del contador de bucles puede ser
inicializada con cualquier nmero, y tambin puede determinar el ltimo valor de contador de
bucle. Por ejemplo, si tenemos que contar de 5 a 10, entonces podemos hacer esto:
fori:=5to10do

Podemos mostrar el contador de bucle en cada ciclo, como en el ejemplo modificado a


continuacin:
var
i: Integer;
Count: Integer;
begin
Write('Cuantas veces? ');
Readln(Count);
for i:= 1 to Count do
begin
Writeln('Ciclo nmero: ', i);
Writeln('Hola');
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Tenga en cuenta que esta vez tenemos que repetir dos declaraciones, y por ello se ha utilizado el
comenzar. . poner fin a las palabras clave para que sean un comunicado.

19

Tabla de multiplicar usando el ciclo for

La versin de for para el programa de tabla de multiplicar es ms fcil y ms concisa:


program MultTableWithForLoop;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
var
x, i: Integer;
begin
Write('Por favor ingrese un nmero: ');
Readln(x);
for i:= 1 to 12 do
Writeln(x, ' * ', i, ' = ', x * i);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

En lugar de escribir la declaracin Writeln 12 veces, se escribe una vez dentro de un bucle que se
ejecuta 12 veces.
Podemos hacer la declaracin del ciclo para que itere de forma decreciente usando la palabra clave
downto en lugar de la palabra clave to con esta sintxis:
for i:= 12 downto 1 do

20

Programa factorial
Factorial en matemticas es la multiplicacin de un nmero por cada uno de sus antecesores hasta el
nmero 1. Por ejemplo, 3! = 3 * 2 * 1 = 6.
var
Fac, Num, i: Integer;
begin
Write('Por favor ingrese un nmero: ');
Readln(Num);
Fac:= 1;
for i:= Num downto 1 do
Fac:= Fac * i;
Writeln('El factorial de ', Num ,' es ', Fac);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

21

Ciclo Repeat Until


A diferencia del ciclo for, que se repite para un nmero determinado de ciclos, El bucle Repeat no
tiene contador. El ciclo se repite hasta que una determinada condicin se cumple (devuelve True),
entonces se pasar a la sentencia siguiente al ciclo.
Ejemplo:
var
Num : Integer;
begin
repeat
Write('Por favor ingrese un nmero: ');
Readln(Num);
until Num <= 0;
Writeln('Terminado,Por favor presione la tecla Enter para
cerrar');
Readln;
end.
En el ejemplo anterior, el programa entra en el bucle, a continuacin, se solicita al usuario que
introduzca un nmero. Si el nmero es menor o igual a cero, se sale del ciclo. Si el nmero
introducido es mayor que cero, el ciclo continuar.

Programa restaurante usando el ciclo Repeat


var
Selection: Char;
Price: Integer;
Total: Integer;
begin
Total:= 0;
repeat
Writeln('Welcome to Pascal Restaurant. Please select your order');
Writeln('1 - Pollo
(10 Geneh)');
Writeln('2 - Pescado
(7 Geneh)');
Writeln('3 - Carne
(8 Geneh)');
Writeln('4 Ensalada
(2 Geneh)');
Writeln('5 - Jugo de naranja (1 Geneh)');
Writeln('6 - Leche
(1 Geneh)');
Writeln('X - Nada');
Writeln;
Write('Por favor ingrese your selection: ');
Readln(Selection);
case Selection of
'1': begin
Writeln('Ud. ha ordenado Pollo, esto tardar 15 minutos');

22

'2':

'3':

'4':

'5':

'6':

Price:= 10;
end;
begin
Writeln('Ud.
Price:= 7;
end;
begin
Writeln('Ud.
Price:= 8;
end;
begin
Writeln('Ud.
Price:= 2;
end;
begin
Writeln('Ud.
Price:= 1;
end;
begin
Writeln('Ud.
Price:= 1;
end;

ha ordenado Pescado, esto tardar 12 minutos');

ha ordenado Carne, esto tardar 18 minutos');

ha ordenado Ensalada, esto tardar 5 minutos');

ha ordenado Jugo de naranja, esto tardar 2 minutos');

ha ordenado Leche, esto tardar 1 minute');

else
begin
Writeln('Entrada errnea');
Price:= 0;
end;
end;
Total:= Total + Price;
until (Selection = 'x') or (Selection = 'X');
Writeln('Precio total
= ', Total);
Write('Presione la tecla Enter para cerrar');
Readln;
end.

En el ejemplo anterior, hemos utilizado las siguientes tcnicas:


1. Adicin de begin end en las selecciones del case para convertir mltiples sentencias a una
sentencia.
2. Inicializamos (dimos valor inicial a una variable) a la variable variable Total en cero, para
acumular el importe total de los pedidos. Luego aadimos el precio seleccionado en cada
ciclo a la variable Total:
Total:= Total + Price;

4. Pusimos dos opciones para terminar los pedidos, ya sea X mayscula o x minscula Ambos
carcteres son diferentes en la representacin (de almacenamiento) en la memoria del
ordenador.
Nota:
Podramos reemplazar esta lnea:

23

until (Selection = 'x') or (Selection = 'X');

Por este cdigo abreviado:


until UpCase(Selection) = 'X';

La funcin Upcase cambiar la variable de seleccin a maysculas si es una letra minscula, y la


condicin devolver True en ambos casos (x o X).

Ciclo While
El ciclo while es similar a el ciclo repeat, pero difiere de l en los siguientes aspectos:
1. En el ciclo while la condicin es comprobada antes de ingresar al ciclo, mientras que repeat
entra al ciclo sin comprobacin alguna. Esto significa que repeat siempre ejecuta las
sentencias al menos una vez, en tanto que while puede prevenir la ejecucin al no ingresar al
ciclo si la condicin no se cumple al inicio.
2. El ciclo while necesita de begin/end si hay varias instrucciones que se deben ejecutar dentro
del bucle, pero repeat no no necesita begin/end, su bloque (declaraciones repetidas) se inicia
a partir de la palabra clave repeat hasta la palabra clave until
Ejemplo:
var
Num: Integer;
begin
Write('Ingrese un nmero: ');
Readln(Num);
while Num > 0 do
begin
Write('Desde el interior de bucle : Ingrese un nmero : ');
Readln(Num);
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Programa factorial usando el ciclo while


var
Fac, Num, i: Integer;
begin
Write('Por favor ingrese un nmero: ');
Readln(Num);

24

Fac:= 1;
i:= Num;
while i > 1 do
begin
Fac:= Fac * i;
i:= i - 1;
end;
Writeln('El factorial de ', Num ,' es ', Fac);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

El bucle while no tiene contador de ciclos, y por esa razn se ha utilizado la variable i para hacer de
contador del bucle. El valor del contador de ciclos se inicia al valor del nmero del nmero del que
necesitamos obtener su factorial, entonces tenemos que reducir su valor de forma manual en cada
ciclo. Cuando el valor de i llegue a 1, el bucle finaliza.

Strings
El tipo String se utiliza para declarar variables que pueden almacenar una cadena de caracteres. Se
puede utilizar para almacenar el texto, un nombre, o una combinacin de caracteres y dgitos como
un nmero de matrcula de coches.
En este ejemplo vamos a ver cmo podemos usar la variable de cadena para aceptar un nombre de
usuario:
var
Name: string;
begin
Write('Por favor ingrese su nombre : ');
Readln(Name);
Writeln('Hola ', Name);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

En el siguiente ejemplo, se utilizan cadenas para almacenar informacin sobre una persona:
var
Name: string;
Address: string;
ID: string;
DOB: string;
begin
Write('Por favor ingrese su nombre : ');
Readln(Name);
Write('Por favor ingrese su direccin : ');
Readln(Address);

25

Write('Por favor ingrese su nmero de identificacin : ');


Readln(ID);
Write('Por favor ingrese su fecha de nacimiento : ');
Readln(DOB);
Writeln;
Writeln('Card:');
Writeln('----------------------------------------------');
Writeln('| Nombre
: ', Name);
Writeln('| Direccin
: ', Address);
Writeln('| Identificacin: ', ID);
Writeln('| Nacimiento
: ', DOB);
Writeln('----------------------------------------------');
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Las cadenas pueden ser concatenadas para producir cadenas mas grandes. Por ejemplo, podemos
concatenar FirstName, SecondName, y FamilyName en otra cadena llamada FullName, similar al
ejemplo siguiente:
var
YourName: string;
Father: string;
GrandFather: string;
FullName: string;
begin
Write('Por favor ingrese su
Readln(YourName);
Write('Por favor ingrese el
Readln(Father);
Write('Por favor ingrese el
Readln(GrandFather);
FullName:= YourName + ' ' +
Writeln('Su nombre completo

primer nombre : ');


nombre de su padre : ');
nombre de su abuelo : ');
Father + ' ' + GrandFather;
es: ', FullName);

Writeln('Presione la tecla Enter para cerrar');


Readln;
end.

Advierta que en este ejemplo hemos aadido un espacio ('') entre los nombres (como YourName + ''
Father +) para hacer una separacin entre los nombres. El espacio es un carcter tambin.
Podemos hacer muchas operaciones sobre cadenas, como la bsqueda de subtexto en una cadena,
copiar una cadena a otra variable de cadena, o la conversin de caracteres de texto maysculas o
minsculas como los ejemplos siguientes:
Esta lnea convierte las letras en el valor de cadena FullName a maysculas:
FullName:= UpperCase(FullName);

Y esto la convierte a minsculas:


FullName:= LowerCase(FullName);

26

En el siguiente ejemplo, buscaremos la letra a en un nombre de usuario utilizando la funcin Pos.


La funcin Pos devuelve la primera aparicin (ndice) de una subcadena en una cadena, o devuelve
cero si el caracter o caracteres (subcadena) no existen en el texto buscado:
var
YourName: string;
begin
Write('Por favor ingrese su nombre : ');
Readln(YourName);
If Pos('a', YourName) > 0 then
Writeln('Su nombre tiene letra a')
else
Writeln('Su nombre no tiene letra a');
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Si el nombre contiene una A mayscula, entonces la funcin Pos no apuntar a la misma, debido a
que A es diferente de a como lo mencionamos anteriormente.
Para solucionar este problema podemos convertir todas las letras del nombre de usuario a
minsculas y entonces podemos hacer la bsqueda:
If Pos('a', LowerCase(YourName)) > 0 the

En la siguiente modificacin del cdigo, se mostrar la posicin de la letra a en un nombre de


usuario:
var
YourName: string;
begin
Write('Por favor ingrese su nombre : ');
Readln(YourName);
If Pos('a', LowerCase(YourName)) > 0 then
begin
Writeln('su nombre tiene letra a');
Writeln('La posicin de la primer letra a en su nombre es: ',
Pos('a', LowerCase(YourName)));
end
else
Writeln('su nombre no contiene letra a');
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Podr notar que si el nombre contiene ms de una letra a, la funcin Pos devuelve el ndice de la
primera aparicin de ella en el nombre de usuario.
Puede obtener el nmero de caracteres de una cadena mediante la funcin Length:
Writeln('Su nombre tiene ', Length(YourName), ' letters');

27

Y puede conseguir la primera letra / carcter de una cadena usando el nmero de su ndice:
Writeln('La primer letra de su nombre es ', YourName[1]);

Y el segundo caracter:
Writeln('La segunda letra de su nombre es ', YourName[2]);

El ltimo caracter:
Writeln('La ltima letra de su nombre es ', YourName[Length(YourName)]);

Tambin puede mostrar una variable tipo string caracter por caracter usando el ciclo for:
for i:= 1 to Length(YourName) do
Writeln(YourName[i]);

Funcin Copy
Podemos copiar parte de una cadena mediante la funcin copy. Por ejemplo, si tenemos que extraer
'world' de la palabra ''Hola mundo'' de la cadena, lo podemos hacer si conocemos la posicin de esa
parte, como lo hemos hecho en el siguiente ejemplo:
var
Line: string;
Part: string;
begin
Line:= 'Hola mundo';
Part:= Copy(Line, 7, 5);
Writeln(Part);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Tenga en cuenta que se ha utilizado la funcin copy con esta sintaxis:


Part:=Copy(Line,7,5);

He aqu una explicacin de la declaracin anterior:

28

Part:= Esta es la variable de tipo string en la cul se almacena el resultado de la funcin


(subcadena 'world')
Line Esta es la cadena origen, la que contiene la frase "Hola mundo".
7
Este es el punto de partida o el ndice de subcadena que hay que extraer, en este caso
se trata del carcter w.
5
Esta es la longitud de la parte extrada. En este caso, representa la longitud de la
palabra 'world'.

En el ejemplo siguiente, se le pedir al usuario que introduzca un nombre de mes, como febrero, el
programa escribir la versin corta de la misma, por ejemplo feb.
var
Month: string;
ShortName: string;
begin
Write('Por favor, introduzca el nombre del mes completo, por ejemplo, enero:
');
Readln(Month);
ShortName:= Copy(Month, 1, 3);
Writeln(Month, ' abreviado es : ', ShortName);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Procedimiento Insert
El procedimiento Insert, inserta una subcadena en una cadena. A diferencia del operador de
concatenacin de cadenas (+) que une dos subcadenas, Insert agrega la subcadena a partir del ndice
indicado en la otra cadena.
Por ejemplo, se puede insertar la palabra Pascal en la cadena 'Hola mundo', lo que resulta en "Hola
mundo Pascal", como en el siguiente ejemplo:
var
Line: string;
begin
Line:= 'Hola mundo';
Insert('Pascal ', Line, 7);
Writeln(Line);

29

Writeln('Presione la tecla Enter para cerrar');


Readln;
end.

Los parmetros del procedimiento Insert son:

'Pascal' Esta es la subcadena a insertar dentro de la cadena de destino.


Line
Esta es la cadena de destino que contiene el resultado de la operacin.
7
Esta es la posicin para comenzar la insercin en la cadena de destino. En este caso,
ser despus del sptimo carcter, que es el primer espacio de 'Hola mundo'.

Procedimiento Delete
Este procedimiento se utiliza para borrar un carcter o subcadena de una cadena. Es necesario
conocer la posicin de inicio y la longitud de la subcadena que debe ser eliminada.
Por ejemplo, si tenemos que eliminar los caracteres 'll' de la cadena 'Hola mundo' para que quede
'Heo World', podemos hacerlo as:
var
Line: string;
begin
Line:= 'Hola mundo';
Delete(Line, 3, 2);
Writeln(Line);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Funcin Trim
Esta funcin se utiliza para eliminar los espacios al comienzo y al final de las cadenas. Si tenemos
una cadena que contiene el texto '' Hola ' ser 'Hola despus de usar esta funcin. No podemos
mostrar espacios en una ventana de terminal a menos que pongamos caracteres entre ellos. Mire el
siguiente ejemplo:
program TrimStr;
{$mode objfpc}{$H+}
uses

30

{$IFDEF UNIX}{$IFDEF UseCThreads}


cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
Line: string;
begin
Line:= ' Hola ';
Writeln('<', Line, '>');
Line:= Trim(Line);
Writeln('<', Line, '>');
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

En el ejemplo anterior, hemos utilizado la unidad SysUtils, unidad que contiene la funcin Trim.
Hay otras dos funciones que eliminan los espacios de slo un lado de una cadena, antes o despus.
Estas funciones son: TrimRight, TrimLeft.

Funcin StringReplace
La funcin StringReplace reemplaza caracteres o subcadenas con otros caracteres o subcadenas en
la cadena deseada.
program
StrReplace;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
Line: string;
Line2: string;
begin
Line:= 'Esta es una prueba de reemplazo de cadena';
Line2:= StringReplace(Line, ' ', '-', [rfReplaceAll]);
Writeln(Line);
Writeln(Line2);
Write('Presione la tecla Enter para cerrar');
Readln;
end.

31

Los parametros de la funcin StringReplace son:


1.

Line: Es la cadena original que deseamos modificar.

2.

' ': Es la subcadena que deseamos substituir.

3.

'-': Esta es la subcadena alternativa que queremos sustituir por la anterior en la cadena
original.

4.

[rfReplaceAll]: Este es el tipo de sustitucin. En este caso especificamos que sustituya todos
los sucesos de la subcadena ' '.

Podemos usar slo una variable de cadena y desechar la variable Linea2 como muestra el ejemplo
modificado, pero vamos a perder el valor del texto original.
var
Line: string;
begin
Line:= 'Esta es una prueba de reemplazo de cadena';
Writeln(Line);
Line:= StringReplace(Line, ' ', '-', [rfReplaceAll]);
Writeln(Line);
Write('Presione la tecla Enter para cerrar');
Readln;
end.

32

Arreglos
Un arreglo es una cadena de variables del mismo tipo. Si tenemos que declarar un array de 10
variables Integer, podemos hacerlo as:
Numbers: array [1 .. 10] of Integer;

Podemos acceder a las variables simples en el arreglo mediante su ndice. Por ejemplo, para poner
un valor en la primera variable del arreglo se puede escribir como:
Numbers[1]:= 30;

Para poner un valor en la segunda variable use el ndice 2:


Numbers[2]:= 315;

En el siguiente ejemplo, le pediremos al usuario que ingrese 10 notas de estudiantes y las


pondremos en un arreglo. Luego vamos a ir a travs de ellos para extraer los resultados: aprueba y
desaprueba.
var
Marks: array [1 .. 10] of Integer;
i: Integer;
begin
for i:= 1 to 10 do
begin
Write('Ingrese la nota ', i, ' del estudiante: ');
Readln(Marks[i]);
end;
for i:= 1 to 10 do
begin
Write('La nota numero ', i, ' del estudiante es: ', Marks[i]);
if Marks[i] >= 40 then
Writeln(' Aprob')
else
Writeln(' Reprob');
end;
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Podemos modificar el cdigo anterior para obtener las notas mxima y mnima de los estudiantes:
var
Marks: array [1 .. 10] of Integer;
i: Integer;
Max, Min: Integer;
begin

33

for i:= 1 to 10 do
begin
Write('Ingrese la nota ', i, ' del estudiante: ');
Readln(Marks[i]);
end;
Max:= Marks[1];
Min:= Marks[1];
for i:= 1 to 10 do
begin
// Controlar si la nota actual es la mxima o no
if Marks[i] > Max then
Max:= Marks[i];
// Controlar si la nota actual es la mnima o no
if Marks[i] < Min then
Min:= Marks[i];
Write('La nota numero ', i, ' del estudiante es: ', Marks[i]);
if Marks[i] >= 40 then
Writeln(' Aprob')
else
Writeln(' Reprob');
end;
Writeln('La nota mxima es: ', Max);
Writeln('La nota mnima es: ', Min);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

Tenga en cuenta que se considera la primera nota (Marks[1]) como la nota mxima y mnima, y
luego vamos a compararlo con el resto de las notas.
Max:= Marks[1];
Min:= Marks[1];

Dentro del bucle se compara Max, Min con cada nota. Si nos encontramos con un nmero que es
mayor que Max, vamos a sustituir el valor mximo de la misma. Si nos encontramos con un nmero
que es menor que Min, entonces vamos a sustituir Min con l.
En el ejemplo previo hemos introducdo comentarios:
// Controlar si la nota actual es la mxima o no

Comenzamos la lnea con los caracteres / /, lo que significa que esta lnea es un comentario y no
afectar el cdigo y no ser compilada. Esta tcnica se utiliza para describir partes de cdigo a otros
programadores o al programador mismo.
/ / Se utiliza para comentarios cortos. Si necesitamos escribir comentarios multilnea se puede
rodear por {} o (**).
Ejemplo:

34

for i:= 1 to 10 do
begin
{ Comprobar si la nota actual es mayor que Marks[i],
si lo es, Marks[i] es el nuevo mximo }
if Marks[i] > Max then
Max:= Marks[i];
(* Comprobar si la nota actual es menor que Marks[i],
si lo es, Marks[i] es el nuevo mnimo *)
if Marks[i] < Min then
Min:= Marks[i];
Write('La nota numero ', i, ' del estudiante es: ', Marks[i]);
if Marks[i] >= 40 then
Writeln(' Aprob')
else
Writeln(' Reprob');
end;

Tambin puede desactivar parte del cdigo comentndolo:


Writeln('La nota mxima es: ', Max);
// Writeln('La nota mnima es: ', Min);
Writeln('Presione la tecla Enter para cerrar');
Readln;

En el cdigo anterior, queda desactivado el procedimiento que escribe la nota mnima de los
estudiantes.
Nota:
Podemos declarar un arreglo basado en ndice cero al igual que en el lenguaje C:
Marks: array [0 .. 9] of Integer;

Este puede contener 10 elementos tambin, pero al primer elemento se accede mediante el ndice 0:
Numbers[0]:= 30;

Segundo elemento:
Numbers[1]:= 315;

Ultimo elemento:
Numbers[9]:= 10;

o
Numbers[High(Numbers)]:= 10;

35

Registros
Mientras que los arreglos pueden contener muchas variables del mismo tipo, los registros pueden
contener variables de tipos diferentes, y estas variables se denominan "campos".
Este grupo de variables(campos) pueden ser tratados como una sola unidad o variable. Podemos
utilizar los registros para almacenar informacin que pertenecen a un mismo objeto, por ejemplo la
informacin de un automvil:
1. Car type: cadena de caracteres
2. Engine size: nmero real
3. Production year: nmero entero
Podemos recoger estos diferentes tipos en un registro que representa un coche como en el ejemplo
siguiente:
program Cars;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
type
TCar = record
ModelName: string;
Engine: Single;
ModelYear: Integer;
end;
var
Car: TCar;
begin
Write('Ingrese la marca del auto: ');
Readln(Car.ModelName);
Write('Ingrese el tamao de cilindrada: ');
Readln(Car.Engine);
Write('Ingrese el modelo(ao): ');
Readln(Car.ModelYear);
Writeln;
Writeln('Car information: ');
Writeln('Marca
: ', Car.ModelName);
Writeln('Cilindrada : ', Car.Engine);
Writeln('Modelo
: ', Car.ModelYear);
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

36

En este ejemplo definimos un nuevo tipo (Record) usando la palabra reservada 'type':
type
TCar = record
ModelName: string;
Engine: Single;
ModelYear: Integer;
end;

Hemos aadido la letra (T) a Car para indicar que se trata de un tipo y no una variable. Los
nombres de variables pueden ser como: Coche, hora, nombre de usuario, pero los nombres de tipo
debe ser como: TCar, thouse y TUserName. Esta es una convencin en el lenguaje Pascal.
Cuando necesitamos utilizar este nuevo tipo, entonces debemos declarar una variable de ese tipo,
por ejemplo:
var
Car: TCar;

Si necesita almacenar un valor en una de sus variables(campos), debemos acceder a l de esta


manera:
Car.ModelName
Losregistrosseutilizarnenlaseccindearchivosdeaccesoaleatoriode
estelibro.

Archivos
Los archivos son elementos importantes de los sistemas operativos y aplicaciones. Componentes del
sistema operativo son representados como archivos y la informacin y los datos estn representados
en archivos tambin, como fotos, libros, aplicaciones y archivos de texto simples
El sistema operativo controla la gestin de archivos tales como lectura, escritura, edicin y borrado.
Files are divided into many types according to many perspectives. We can group files into two
types: executable files, and data files. For example compiled binary Lazarus applications are
executable files, while Pascal source code (.pas) are data files. Also PDF books, JPEG pictures, are
data files.
Los archivos se dividen en varios tipos de acuerdo con muchas perspectivas. Podemos agrupar los
archivos en dos tipos: Los archivos ejecutables y archivos de datos. Por ejemplo los archivos
binarios generados por la compilacin de Lazarus son archivos ejecutables. Mientras que los
archivos de cdigo fuente (.pas) son archivos de datos, as como tambin los libros PDF, imgenes
JPEG.

37

Podemos dividir los archivos de datos en dos tipos de acuerdo con la representacin de su
contenido:
1. Archivos de texto: Son simples archivos de texto que pueden ser escritos o ledos usando
cualquier herramienta simple incluyendo lneas de comandos del sistema operativo como los
comandos cat y vi en Linux, o comandos como type o copy con en Windows.
2. Archivos de datos binarios: Estos son ms complejos y requieren aplicaciones especiales
para abrirlos. Por ejemplo, los archivos de imagen no se pueden abrir utilizando sencillas
herramientas de lnea de comandos, sino que debe abrirse con aplicaciones como GIMP,
Kolour Paint, MS Paint, etc Si abrimos una imagen o archivos de voz, tendremos caracteres
irreconocibles que no significan nada para el usuario. Ejemplos de archivos de datos
binarios son archivos de base de datos, que deben ser abiertos con la aplicacin adecuada.
Hay otra manera de clasificar los archivos, segn tipo de acceso:
1. Archivos de acceso secuencial: Un ejemplo de un archivo secuencial es un archivo de texto,
que no tiene ningn registro de tamao fijo. Cada lnea tiene su propia longitud, por lo que
no podemos saber la posicin (en caracteres) para el inicio de la tercera lnea, por ejemplo.
Por esa razn, hemos podido abrir el archivo de slo lectura o slo escritura, y tambin
podemos aadir texto slo al final del archivo. Si necesitamos insertar texto en medio de un
archivo, entonces debemos leer el contenido del archivo en la memoria, hacer las
modificaciones, borrar todo el archivo desde el disco, y luego sobreescribe el archivo con el
texto modificado
2. Archivos de acceso aleatorio: Este tipo de archivo tiene un registro de tamao fijo. Un
registro es la unidad ms pequea que se puede leer y escribir al mismo tiempo, y podra ser
Byte, Integer, String, o un registro definido por el usuario. Podemos leer y escribir al mismo
tiempo, por ejemplo, se poda leer el nmero de registro 3 y copiarlo en el nmero de
registro 10. En este caso, podemos saber exactamente la posicin de cada registro en el
archivo. Modificar registros es simple. En los archivos de acceso aleatorio, podemos
sustituir o sobrescribir cualquier archivo sin afectar al resto del archivo.

Archivos de texto
Los archivos de texto son los ms simples, pero debemos escribir en ellos en una sola direccin
(slo hacia adelante). No podemos volver al escribir en un archivo de texto. Tambin hay que
definir el modo de funcionamiento antes de abrir el archivo: Read (lectura), Write(escritura o
Append (agregar al final).
En este ejemplo, se muestra el contenido de un archivo de texto seleccionado por un usuario. Por
ejemplo, un usuario puede ingresar un nombre de archivo de texto como c:\test\first.pas en
Windows o
/home/usuario/first.pas en Linux:

38

Leer un archivo de texto


program ReadFile;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, sysUtils
{ usted puede agregar unidades despues de aqu };
var
FileName: string;
F: TextFile;
Line: string;
begin
Write('Introduzca un nombre de archivo de texto : ');
Readln(FileName);
if FileExists(FileName) then
begin
// Enlazar la variable F con el nombre fsico del archivo
AssignFile(F, FileName);
Reset(F); // Poner el archivo en modo lectura, el archivo debe existir
// Mientras el archivo tenga lineas para leer el bucle se ejecuta
while not Eof(F) do
begin
Readln(F, Line); // Leer una lnea del archivo de texto
Writeln(Line);
// Mostrar esa lnea en pantalla
end;
CloseFile(F); // Liberar F y la conexin con el nombre de archivo
end
else // sino, if FileExists..
Writeln('El archivo no existe');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

En Linux podemos ingresar estos nombres de archivo:


/etc/resolv.conf
or
/proc/meminfo
/proc/cpuinfo
Hemos utilizado nuevos tipos, funciones y procedimientos para manipular archivos de texto que
son:
1.
F: TextFile;

39

TextFile es un tipo que se utiliza para declarar una variable de archivo de texto. Esta variable se
puede vincular a un archivo de texto para su uso posterior.
2.

if FileExists(FileName) then

FileExists es una funcin contenida en la unidad SysUtils, comprueba la existencia de un archivo.


Devuelve verdadero (True) si el archivo existe en el soporte de almacenamiento.
3.
AssignFile(F, FileName);

Despus de haber comprobado la existencia de un fichero, podemos utilizar el procedimiento


AssignFile para vincular la variable de archivo (F) con el archivo fsico. Cualquier uso de la
variable F representar el archivo fsico.
4.

Reset(F); // Poner el archivo en modo lectura, el archivo debe existir

El procedimiento Reset, abre archivos de texto para lectura solamente, y coloca el puntero de
lectura en el primer carcter del archivo.
Si no hay permiso de lectura para ese archivo para el usuario actual, aparecer un mensaje de error,
de acceso denegado(access denied).
5.
Readln(F, Line); // Leer una lnea del archivo de texto

El procedimiento Readln se utiliza para leer una lnea completa del archivo y ponerlo en la variable
Linea. Antes de leer una lnea del archivo de texto, debemos asegurarnos de que el archivo no se ha
llegado al final. Podemos hacerlo con la siguiente funcin, Eof.
6.

while not Eof(F) do

La funcin EOF devuelve verdadero(True) si el archivo ha llegado a su fin. Se utiliza para indicar
que la operacin de lectura no podr usarse nuevamente y se ha ledo todo el contenido del archivo.
7.
CloseFile(F); // Liberar F y la conexin con el nombre de archivo

Despus de terminar la lectura o escritura en un archivo, hay que cerrarlo para liberar el archivo, ya
que el proceso de Reposicin se reserva el archivo en el sistema operativo y evita la escritura y
borrado por otra aplicacin mientras el archivo est abierto.
Debemos utilizar CloseFile slo cuando el procedimiento Reset logra abrir el archivo. Si Reset falla
por que el archivo no existe, o est siendo utilizado por otra aplicacin, etc, en ese caso no hay que
cerrar el archivo.

40

En el siguiente ejemplo vamos a crear un nuevo archivo de texto y poner algn texto en l:
Creando y escribiendo en un archivo de texto
var
FileName: string;
F: TextFile;
Line: string;
ReadyToCreate: Boolean;
Ans: Char;
i: Integer;
begin
Write('Ingrese un nuevo nombre de archivo: ');
Readln(FileName);
// Verificar si el archivo existe, avisar al usuario si es as
if FileExists(FileName) then
begin
Write('El archivo existe, desea sobreescribirlo ? (s/n)');
Readln(Ans);
if upcase(Ans) = 'S' then
ReadyToCreate:= True
else
ReadyToCreate:= False;
end
else // File does not exist
ReadyToCreate:= True;
if ReadyToCreate then
begin
// Enlazar la variable F con el nombre fsico del archivo
AssignFile(F, FileName);
Rewrite(F); // Crear un nuevo archivo para escritura
Writeln('Please input file contents line by line, '
, 'when you finish write % then press enter');
i:= 1;
repeat
Write('Line # ', i, ':');
Inc(i);
Readln(Line);
if Line <> '%' then
Writeln(F, Line); // Escribir una lnea en el archivo de texto
until Line = '%';
CloseFile(F); // Liberar F y la conexin con el nombre de archivo
end
else // El archivo existe y el usuario no desea sobreescibir
Writeln('Doing nothing');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

41

En este ejemplo hemos usado varias cosas importantes:


1. Boolean type:
ReadyToCreate: Boolean;

Este tipo slo puede tener uno de dos valores: True o False. Estos valores se pueden utilizar
directamente en una condicin if, bucle while o bucle repeat
En el ejemplo previo usamos la condicin if de este modo:
if Marks[i] > Max then

que puede tomar el valor True or False.


2. funcin UpCase:
if upcase(Ans) = 'Y' then

This statement is executed when the file exists. The program will warn the user about overwriting
an existing file. If he/she wants to continue, then he/she should enter a lowercase y or capital Y. The
UpCase function will convert the character into a capital letter if it is lowercase.Esta sentencia se
ejecuta cuando el archivo existe.
El programa avisar al usuario acerca de sobrescribir un archivo existente. Si desea continuar,
entonces podra introducir una 'y' minscula o mayscula . La funcin UpCase convertir el
carcter en mayscula si es minscula.
3. Procedimiento Rewrite:
Rewrite(F); // Crear un nuevo archivo para escritura

El procedimiento Rewrite se utiliza para crear un nuevo archivo vaco. Si el archivo ya existe, ser
borrado y sobreescrito Tambin abre el archivo para escritura slo en el caso de archivos de texto.
4. Procedimiento Writeln(F, ..) :
Writeln(F, Line); // Escribir una linea en el archivo

Este procedimiento se utiliza para escribir variables de cadena en archivos de texto, que las aade
con caracteres de fin de lnea retorno de carro y lnea abajo (CR / LF), representado como los
caracteres cuyo valor numrico es 13 y 10 respectivamente.
Estos caracteres no se puede mostrar en una ventana de la consola, sino que se mover el cursor de
pantalla a una nueva lnea.

42

5. Procedimiento Inc:
Inc(i);

Este procedimiento incrementa una variable de tipo entera en uno.


i:= i + 1;

6. Procedure CloseFile:
CloseFile(F); // Liberar F y la conexin con el nombre de archivo

Como mencionamos anteriormente, el procedimiento CloseFile libera un archivo en el sistema


operativo. Adems, tiene un trabajo adicional cuando se escribe en un archivo de texto,que es vaciar
el bfer de escritura.
El Buffering de archivos de texto es una caracterstica que hace el trato con archivos de texto sea
ms rpido. En lugar de escribir una sola lnea o carcter directamente en disco o cualquier otro
medio de almacenamiento (que es muy lento en comparacin con la escritura en la memoria), la
aplicacin escribe estas entradas en un buffer de memoria. Cuando la memoria intermedia alcanza
su tamao completo, que se vaciar forzado a escribir) dentro de medios de almacenamiento
permanentes como un disco duro. Esta operacin hace que se escriba ms rpido, pero se aade el
riesgo de perder algunos datos (en el buffer) si la energa se pierde repentinamente. Para minimizar
la prdida de datos, se debe cerrar el archivo inmediatamente despus de terminar la escritura en l,
o llamar al procedimiento Flush para vaciar el bfer de forma explcita.

Agregando en un archivo de texto


En este ejemplo, queremos abrir un archivo de texto existente para escribir al final del mismo, sin
eliminar su contenido original utilizando el procedimiento Append.

Programa agregando en un archivo de texto


var
FileName: string;
F: TextFile;
Line: string;
i: Integer;
begin
Write('Input an existed file name: ');
Readln(FileName);
if FileExists(FileName) then
begin
// Enlazar la variable F con el nombre fsico del archivo

43

AssignFile(F, FileName);
Append(F); // Abrir archivo para agregar
Writeln('Please input file contents line by line',
'when you finish write % then press enter');
i:= 1;
repeat
Write('Line # ', i, ' append :');
Inc(i);
Readln(Line);
if Line <> '%' then
Writeln(F, Line); // Escribir una lnea en el archivo de texto
until Line = '%';
CloseFile(F); // Release F and FileName connection, flush buffer
end
else
Writeln('File does not exist');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

Despus de ejecutar esta aplicacin y entrar en un archivo de texto existente, lo podemos ver con
los comandos cat / type, o haciendo doble clic en l en su directorio para ver los datos adjuntos.

Archivos de acceso aleatorio


As we mentioned earlier, the second type of file according to an access type perspective is Random
access , or direct access. This type of file has a fixed size record, so that we can jump to any record
for reading or writing at any time.
There are two types of random access files: typed files and untyped files.
Como mencionamos anteriormente, el segundo tipo de archivo de acuerdo desde el punto de vista
de tipo de acceso, es el acceso aleatorio o acceso directo. Este tipo de archivo tiene un registro de
tamao fijo, de modo que podemos ir a cualquier registro para leer o escribir en cualquier momento.
Hay dos tipos de archivos de acceso aleatorio: Con tipo y sin tipo.

Archivos con tipo


Typed files are used for files that contain the same type of data that has the same size of records, for
example, if a file contains records of Byte type, that means the record size = 1 byte. If the file
contains real numbers (Single), that means all record sizes are 4 bytes, etc.
Los archivos con tipo se utilizan para los archivos que contienen el mismo tipo de datos cuyos
registros tienen el mismo tamao, por ejemplo, si un archivo contiene registros de tipo Byte, eso
significa que el tamao del registro = 1 byte. Si el archivo contiene nmeros reales (Individual), eso
44

significa que todos los tamaos de registro son 4 bytes, etc


En el siguiente ejemplo, se muestra cmo utilizar un archivo de Byte:
Programa de notas
var
F: file of Byte;
Mark: Byte;
begin
AssignFile(F, 'marks.dat');
Rewrite(F); // Crear archivo
Writeln('Please input students marks, write 0 to exit');
repeat
Write('Input a mark: ');
Readln(Mark);
if Mark <> 0 then // No escribir el valor 0
Write(F, Mark);
until Mark = 0;
CloseFile(F);
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

En este ejemplo usamos esta sintxis para definir el archivo con tipo:
F: file of Byte;

Que quiere decir:: el archivo contiene un registro de tipo de datos Byte, que puede contener valores
de 0 a 255.
Creamos el archivo y lo abrimos para escritura usando el procedimiento Rewrite
Rewrite(F); // Crear archivo

Tambin se ha utilizado la funcin Write en lugar de Writeln para escribir registros en el archivo
proporcionado:
Write(F, Mark);

Writeln no es adecuado para los archivos de tipo, porque se aaden los caracteres CR / LF en cada
lnea del texto escrito, pero Write almacena el registro como es, sin ninguna adicin. En este caso, si
hemos entrado 10 registros (de Byte), el tamao del archivo ser de 10 bytes en el disco.
En el siguiente ejemplo, vamos a mostrar cmo se muestra el contenido del archivo anterior: :

45

Leyendo notas de estudiantes


program ReadMarks;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
F: file of Byte;
Mark: Byte;
begin
AssignFile(F, 'marks.dat');
if FileExists('marks.dat') then
begin
Reset(F); // Abrir archivo
while not Eof(F) do
begin
Read(F, Mark);
Writeln('Mark: ', Mark);
end;
CloseFile(F);
end
else
Writeln('Archivo (marks.dat) no encontrado');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

En el siguiente ejemplo, vamos a mostrar cmo aadir nuevos registros sin eliminar los datos
existentes:

Programa agregando notas de alumnos


program AppendMarks;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };

46

var
F: file of Byte;
Mark: Byte;
begin
AssignFile(F, 'marks.dat');
if FileExists('marks.dat') then
begin
FileMode:= 2; // Poner en modo lectura/escritura
Reset(F); // Abrir archivo
Seek(F, FileSize(F)); // Ir hasta el ltimo registro
Writeln('Por favor ingrese la nota de estudiante, escriba 0 para salir');
repeat
Write('Ingrese nota: ');
Readln(Mark);
if Mark <> 0 then // No escribir valor 0 en el archivo
Write(F, Mark);
until Mark = 0;
CloseFile(F);
end
else
Writeln('Archivo (marks.dat) no encontrado');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

Despus de ejecutar este programa y entrar en nuevos registros, podemos ejecutarlo de nuevo para
ver los datos agregados.
Tenga en cuenta que hemos utilizado Reset para abrir el archivo para escribir en lugar del
procedimiento Rewrite. Rewrite borra todos los datos de los archivos existentes, y crea un archivo
vaco si el archivo no existe, mientras Reset abre un archivo existente sin borrar su contenido.
Tambin hemos asignado 2 a la variable FileMode para indicar que hay que abrir el archivo para
acceso de lectura/escritura. 0 en FileMode significa slo lectura, 1 significa slo escritura y 2 (por
defecto) significa lectura/escritura.
FileMode:= 2; // Poner en modo lectura/escritura
Reset(F); // Abrir archivo

Reset coloca el puntero de lectura/escritura en el primer registro, y por esa razn si empezamos a
escribir los registros inmediatamente, vamos a sobrescribir los archivos antiguos, por lo que hemos
utilizado el procedimiento Seek para mover el puntero de lectura/ escritura al final del archivo .
Seek slo se puede utilizar con archivos de acceso aleatorio.
Si se intenta acceder a una posicin de registro que no existe con el procedimiento Seek (por
ejemplo, nmero de registro 100, mientras que slo existen 50 registros), obtendremos un error.
Tambin hemos usado la funcin FileSize que devuelve el nmero de registros actuales en el
archivo. Se utiliza en combinacin con el procedimiento Seek para saltar al final del archivo:
Seek(F, FileSize(F)); // Ir hasta el ltimo registro

47

Note that this example can be used if the Student marks file already exists; if not, then we should
run the first program (Storing Student Marks) because it uses Rewrite which can create new files.
Tenga en cuenta que este ejemplo se puede utilizar si el archivo de notas de alumnos ya existe. Si
no, debemos ejecutar previamenteel primer programa (Programa de notas ), ya que utiliza Rewrite
y puede crear un nuevo archivo.
Podemos combinar los dos mtodos (Reset y Rewrite) en funcin de si el archivo existe, como lo
hemos hecho en el ejemplo siguiente:

Programa crear y agregar notas de alumnos


program ReadWriteMarks;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
F: file of Byte;
Mark: Byte;
begin
AssignFile(F, 'marks.dat');
if FileExists('marks.dat') then
begin
FileMode:= 2; // Poner en modo lectura/escritura
Reset(F); // Abrir archivo
Writeln('File already exist, opened for append');
// Mostrar registros del archivo
while not Eof(F) do
begin
Read(F, Mark);
Writeln('Mark: ', Mark);
end
end
else // Archivo no encontrado, crearlo
begin
Rewrite(F);
Writeln('El archivo no exista, ha sido creado');
end;
Writeln('Por favor ingrese la nota de estudiante, escriba 0 para salir');
Writeln('Puntero de archivo apuntando al registro # ', FilePos(f));
repeat
Write('Ingrese una nota: ');
Readln(Mark);
if Mark <> 0 then // No escribir valor 0
Write(F, Mark);

48

until Mark = 0;
CloseFile(F);
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

Observe que en este ejemplo, no utilizamos el procedimiento Seek, en cambio, lemos todo el
contenido de notas de alumnos primero. Esta operacin (leer todo el archivo) mueve el puntero al
final del mismo.
En el siguiente ejemplo, vamos a utilizar un archivo de registros para almacenar la informacin de
Automviles
Programa base de datos de automoviles
program CarRecords;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
type
TCar = record
ModelName: string[20];
Engine: Single;
ModelYear: Integer;
end;
var
F: file of TCar;
Car: TCar;
begin
AssignFile(F, 'cars.dat');
if FileExists('cars.dat') then
begin
FileMode:= 2; // Poner en modo lectura/escritura
Reset(F); // Abrir archivo
Writeln('Archivo existente, abierto para agregar');
// Mostrar registros del archivo
while not Eof(F) do
begin
Read(F, Car);
Writeln;
Writeln('Car # ', FilePos(F), ' --------------------------');
Writeln('Model : ', Car.ModelName);
Writeln('Year : ', Car.ModelYear);
Writeln('Engine: ', Car.Engine);
end
end

49

else // Archivo no encontrado, crearlo


begin
Rewrite(F);
Writeln('El archivo no exista, ha sido creado');
end;
Writeln('Por favor ingrese la informacin del auto, ',
'escriba x en el nombre de modelo para salir');
Writeln('Puntero de archivo apuntando al registro # ', FilePos(f));
repeat
Writeln('--------------------------');
Write('Ingrese marca del auto : ');
Readln(car.ModelName);
if Car.ModelName <> 'x' then
begin
Write('Ingrese el modelo(ao) : ');
Readln(car.ModelYear);
Write('Ingrese el tamao de cilindrada: ');
Readln(car.Engine);
Write(F, Car);
end;
until Car.ModelName = 'x';
CloseFile(F);
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

En el ejemplo anterior, declaramos el tipo TCar para definir la informacin del coche. El primer
campo (ModelName) es una variable de cadena, pero limitamos su longitud mxima a 20
caracteres:
ModelName: string[20];

Debemos utilizar esta declaracin para variables de cadena antes de usarlos en los archivos, ya que
las variables estndar ANSI cadena tiene un tipo diferente e ilimitado de almacenamiento en
memoria, pero para los archivos con tipo, el tamao de cada tipo de dato debe definirse.

Copiando archivos
Todos los tipos de archivos, tales como archivos de texto, archivos binarios, se basan en unidades
de byte, que es la ms pequea representacin de datos en la memoria del ordenador y en el disco.
Cada archivo debe contener un byte, dos bytes, etc, o ningn byte en absoluto . Cada byte podra
contener un nmero entero o un cdigo de caracteres 0 a 255. Podemos abrir todo tipo de archivos
utilizando un archivo de tipo Byte o de tipo Char.
Podemos copiar cualquier archivo a otro usando de archivos de Byte, y el resultado ser un nuevo
archivo que es idntico al contenido del archivo de origen.

50

Copiar archivos usando file of byte


program FilesCopy;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
SourceName, DestName: string;
SourceF, DestF: file of Byte;
Block: Byte;
begin
Writeln('Copiar archivos');
Write('Igrese el nombre del archivo orgen: ');
Readln(SourceName);
Write('Ingrese el nombre del archivo destino: ');
Readln(DestName);
if FileExists(SourceName) then
begin
AssignFile(SourceF, SourceName);
AssignFile(DestF, DestName);
FileMode:= 0;
// Modo solo lectura
Reset(SourceF); // Abrir archivo origen
Rewrite(DestF); // Crear archivo destino
// Comenzar la copia
Writeln('Copiando..');
while not Eof(SourceF) do
begin
Read(SourceF, Block); // Leer un Byte desde archivo origen
Write(DestF, Block); // Escribir ese Byte en archivo destino
end;
CloseFile(SourceF);
CloseFile(DestF);
end
else // Archivo origen no encontrado
Writeln('El archivo de orgen no existe');
Write('Copia de archivo finalizada, Presione la tecla Enter para cerrar.');
Readln;
end.

Despus de ejecutar el ejemplo anterior, podrn ingresar en el archivo origen existente y en el nuevo
archivo destino. En Linux podemos introducir nombres de archivos como estos:
Input source file name: /home/motaz/quran/mishari/32.mp3
51

Input destination file name: /home/motaz/Alsajda.mp3


En Windows podramos ingresar algo como esto:
Input source file name: c:\photos\mypphoto.jpg
Input destination file name: c:\temp\copy.jpg
Si el archivo origen existe en el mismo directorio que el programa FileCopy, podramos introducir
slo el nombre del archivo de la siguiente manera:
Input source file name: test.pas
Input destination file name: testcopy.pas
Si usamos este mtodo para copiar archivos de gran tamao, tomar un tiempo muy largo en
comparacin con los procedimientos de copia del sistema. Eso significa que el sistema operativo
utiliza una tcnica diferente para copiar archivos. Si desea copiar un archivo de 1 megabyte, esto
significa que el bucle while se repetir alrededor de 1 milln de veces, lo que significa un milln de
operaciones de lectura y un milln de operaciones de escritura. Si se reemplaza el archivo file of
Byte por file of Word, se reducir a alrededor de 500.000 ciclos de lectura y escritura, pero esto slo
funcionar para los archivos cuyo tamao es par. Tendr xito si el archivo contiene 1420 bytes,
pero se producir un error con un archivo de 1.423 bytes.
Para copiar un archivo de cualquier tipo utilizando un mtodo ms rpido, debemos utilizar
archivos sin tipo.

52

Archivos sin tipo


Los archivos sin tipo son archivos de acceso aleatorio, que tienen una longitud de registro fija, pero
no estn vinculados a ningn tipo de datos. En su lugar, tratar los datos (registros) como un arreglo
de bytes o caracteres.
Programa copiar archivos usando archivos sin tipo
program FilesCopy2;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
SourceName, DestName: string;
SourceF, DestF: file;
Block: array [0 .. 1023] of Byte;
NumRead: Integer;
begin
Writeln('Copiar archivos');
Write('Igrese el nombre del archivo orgen: ');
Readln(SourceName);
Write('Ingrese el nombre del archivo destino: ');
Readln(DestName);
if FileExists(SourceName) then
begin
AssignFile(SourceF, SourceName);
AssignFile(DestF, DestName);
FileMode:= 0;
// Modo solo lectura
Reset(SourceF, 1); // Abrir archivo orgen
Rewrite(DestF, 1); // Crear archivo destino
// Comenzar copia
Writeln('Copiando...');
while not Eof(SourceF) do
begin
// Leer Byte desde archivo origen
BlockRead(SourceF, Block, SizeOf(Block), NumRead);
// Escribir ese Byte en archivo destino
BlockWrite(DestF, Block, NumRead);
end;
CloseFile(SourceF);
CloseFile(DestF);

53

end
else // Archivo origen inexistente
Writeln('El archivo orgen no existe');
Write('Copia de archivo finalizada, Presione la tecla Enter para cerrar.');
Readln;
end.

Las cosas nuevas en el ejemplo anterior son las siguientes:


1. Declaracin del tipo de archivo:
SourceF, DestF: file;

2. Variable de lectura/escritura (Buffer)


Block: array [0 .. 1023] of Byte;

Hemos usado un arreglo de bytes (1 KByte y puede ser modificado) para leer y copiar bloques de
archivo.
3. Abrir un archivo sin tipo requiere un parmetro adicional:
Reset(SourceF, 1); // Abrir archivo origen
Rewrite(DestF, 1); // Crear archivo destino

El parmetro adicional es el tamao de registro, que es el elemento mnimo que se puede


leer/escribir en un momento. Puesto que lo necesitamos para copiar cualquier tipo de archivo,
significa que debe ser un byte, debido a que puede ser utilizado con cualquier tamao de archivo.
4. Procedimiento de lectura:
BlockRead(SourceF, Block, SizeOf(Block), NumRead);

El procedimiento BlockRead se utiliza con archivos sin tipo. Se leen un montn de datos a la vez.
Los parmetros del procedimiento BlockRead son:

SourceF: Es la variable de archivo de origen que tenemos que copiar .

Block : Es la variable o arreglo que almacenar los datos actualmente ledos y escritos.

SizeOf(Block): Este es el nmero deseado de registros que hay que leer de una sola vez. Por
ejemplo, si introducimos 100 que significa que tenemos que leer 100 registros (bytes en este
caso). Si utilizamos la funcin SizeOf, significa que tenemos que leer el nmero de registros
del tamao del contenedor (arreglo de bytes).

NumRead: Le hemos dicho a la funcin BlockRead que lea un nmero especfico de


registros (1024), y algunas veces tiene xito en la lectura de toda esa cantidad, y a veces lee
54

slo una parte de ella. Por ejemplo, supongamos que tenemos que leer un archivo que
contiene slo 100 bytes, significa que BlockRead podra leer slo 100 bytes. Leer menos
registros que los deseados sucede tambin en el ltimo bloque del archivo. Si el archivo
contiene 1034 bytes, por ejemplo, eso significa que en el primer bucle, llegaremos 1024,
pero en el siguiente bucle obtendremos slo 10 bytes a la izquierda, y la funcin EOF
devuelve True. Necesitamos el valor NumRead para usar con el procedimiento BlockWrite.

5. Escribiendo en archivos sin tipo:


BlockWrite(DestF, Block, NumRead);

Este es el procedimiento de escritura, y es similar al procedimiento BlockRead, pero tiene algunas


diferencias: 1. En lugar de utilizar el procedimiento SizeOf, hemos utilizado NumRead, porque
NumRead contiene el tamao de lectura real de bloque. 2. El cuarto parmetro NumWritten (que no
se utiliza en este ejemplo) no es importante, porque siempre tenemos registros escritos como
deseamos, a menos que el disco est lleno.
Despus de ejecutar esta aplicacin, observe la velocidad de copia de archivos de gran tamao. Si el
archivo contiene un Megabyte,significa que slo necesita alrededor de un millar de ciclos de de
lectura/escritura ciclos para copiar todo el archivo.
En el siguiente ejemplo, vamos a utilizar archivos sin tipo para leer cualquier archivo y mostrarlo
como se almacena en la memoria o en el disco. Como sabemos, los archivos son lista de bytes.

Programa mostrar contenido de archivo


program ReadContents;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
FileName: string;
F: file;
Block: array [0 .. 1023] of Byte;
i, NumRead: Integer;
begin
Write('Ingrese nombre de archivo origen: ');
Readln(FileName);
if FileExists(FileName) then

55

begin
AssignFile(F, FileName);
FileMode:= 0;
Reset(F, 1);

// Modo solo lectura


// Abrir archivo orgen

while not Eof(F) do


begin
BlockRead(F, Block, SizeOf(Block), NumRead);
// Mostrar contenido en pantalla
for i:= 0 to NumRead - 1 do
Writeln(Block[i], ':', Chr(Block[i]));
end;
CloseFile(F);
end
else // Archivo no existe
Writeln('El archivo orgen no existe');
Write('Presione la tecla Enter para cerrar..');
Readln;
end.

Despus de ejecutar este ejemplo e introducir un nombre de archivo de texto, por ejemplo, vamos a
ver por primera vez CR / LF valores (13/10), porque nos muestra cada cdigo de carcter (ASCII).
En Linux encontraremos solo salto de lnea (LF), que tiene un valor de 10 en decimal. Este es un
delimitador de lnea en archivos de texto.
Podemos mostrar otros tipos de archivos, como imgenes, ejecutables, para ver cmo se ven desde
el interior.
Hemos utilizado la funcin Chr en este ejemplo para obtener el valor numrico de caracteres, por
ejemplo, la letra a se almacena en la memoria en un byte como 97, y la ltra A mayscula se
almacena como 65.

Fecha y Hora
La fecha y hora son dos de los temas ms importantes en la programacin. Es importante para las
aplicaciones que almacenan transacciones o cualquier informacin de una operacin, como
compras, facturas de pago, etc, estas necesitan almacenar la fecha y hora de la transaccin. Ms
tarde se podr determinar las transacciones y operaciones que tuvieron lugar durante el mes pasado
o el mes en curso, por ejemplo.
Un registro de solicitudes es una operacin que depende de la fecha / tiempo de grabacin. Tenemos
que saber cuando alguna aplicacin se inicia, se detiene, se genera un error, o se bloquea.
TDateTime es el tipo en Object Pascal que podemos utilizar para almacenar la fecha/hora. Es un
nmero de doble precisin de punto flotante que ocupa 8 bytes en la memoria. La parte fraccionaria
de este tipo representa el tiempo, y la parte integral representa el nmero de das que han pasado
desde el 30/Dic/1899.
56

En el siguiente ejemplo, vamos a mostrar cmo mostrar la fecha/hora actual valor de la funcin
Now .
program DateTime;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes , SysUtils
{ usted puede agregar unidades despues de aqu };
begin
Writeln('Fecha y hora actuales: ', DateTimeToStr(Now));
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Hemos utilizado la funcin DateTimeToStr contenido en la unidad SysUtils para convertir un tipo
TDateTime devuelto por la funcin Now en una representacin de cadena legible fecha/hora.
Si no utilizamos esta conversin, vamos a tener un valor fecha/hora codificada como un nmero
real:
Writeln('Fecha y hora actuales: ', Now);

Tambin hay dos funciones de conversin de fecha/hora que muestran la parte fecha y la parte hora:
Writeln('La fecha actual es ', DateToStr(Now));
Writeln('La hora actua es ', TimeToStr(Now));

La funcin Date devuelve slo la parte fecha de hoy, y la funcin Time devuelve la hora actual
solamente:
Writeln('La fecha actual es ', DateToStr(Date));
Writeln('La hora actua es ', TimeToStr(Time));

Estas dos funciones ponen ceros en la otra parte, por ejemplo, la funcin Date devuelve el da actual
y pone cero en parte hora (cero en la hora significa 12:00 am). La funcin Time devuelve la hora
actual del sistema, y pone a cero la parte de fecha (cero en la fecha significa 30/12/1899).
Podemos comprobar esto utilizando la funcin DateTimeToStr:
Writeln('La fecha actual es ', DateTimeToStr(Date));
Writeln('La hora actual es ', DateTimeToStr(Time));

57

DateTimeToStr muestra la fecha/hora de acuerdo a la fecha configurada en la computadora. Su


resultado puede variar entre dos computadoras, pero la funcin FormatDateTime mostrar la fecha
y la hora en el formato escrito por el programador, independientemente de la configuracin del
equipo:
Writeln('La fecha actual es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Date));
Writeln('La hora actual es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Time));

En el siguiente ejemplo, vamos a tratar fecha/hora como un nmero real, sumando y restando los
valores de la misma:
begin
Writeln('La fecha y hora actual es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now));
Writeln('La hora de ayer es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now - 1));
Writeln('La hora de maana es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now + 1));
Writeln('Hoy + 12 horas es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now + 1/2));
Writeln('Hoy + 6 horas es ',
FormatDateTime('yyyy-mm-dd hh:nn:ss', Now + 1/4));
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Si aadimos uno o restamos uno de una fecha, se sumar/restar un da completo. Si por


ejemplo,sumamos o 0,5, esto aade un medio da (12 horas).
En el siguiente ejemplo, vamos a generar un valor de fecha con un ao especfico, mes y da:

var
ADate: TDateTime;
begin
ADate:= EncodeDate(1975, 11, 16);
Writeln('Mi fecha de cumpleaos es: ', FormatDateTime('yyyy-mm-dd', ADate));
Write('Presione la tecla Enter para cerrar');
Readln;
end.

La funcin EncodeDate acepta ao, mes y da como entrada, y devuelve ao, mes y da en una
variable de tipo TDateTime.
La funcin EncodeTime acepta hora, minuto, segundo y milisegundo como entrada y devuelve los
valores de tiempo como un valor TDateTime:

58

var
ATime: TDateTime;
begin
ATime:= EncodeTime(19, 22, 50, 0);
Writeln('Almughrib prayer time is: ', FormatDateTime('hh:nn:ss', ATime));
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Comparacin Fecha/Hora
Puede comparar dos variables fecha/hora del mismo modo que la comparacin de nmeros reales.
Por ejemplo, en nmeros reales: 9,3 es mayor que 5,1, lo mismo sucede para los valores
TDateTime. Actual + 1, que representa maana, es mayor que ahora (Now), y Now + 1.24 que
significa una hora despus de Now es mayor que Now - 2/24 que significa dos horas antes de ahora.
En el siguiente ejemplo, vamos a poner la fecha 1/Ene/2012 en una variable, compararla con la
fecha actual y comprobar si esta fecha ya ha pasado o no.
var
Year2012: TDateTime;
begin
Year2012:= EncodeDate(2012, 1, 1);
if Now < Year2012 then
Writeln('El ao 2012 no ha llegado todava')
else
Writeln('El ao 2012 ya ha pasado');
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Podemos aadir nuevas funciones a este ejemplo, para que muestre los das que faltan o los das
pasados a/desde esa fecha:
var
Year2012: TDateTime;
Diff: Double;
begin
Year2012:= EncodeDate(2012, 1, 1);
Diff:= Abs(Now - Year2012);
if Now < Year2012 then
Writeln('El ao 2012 no ha llegado an, faltan ',
Format('%0.2f', [Diff]), ' das ')
else
Writeln('El primer da de enero de 2012 fue pasado por ',
Format('%0.2f', [Diff]), ' das');
Write('Presione la tecla Enter para cerrar');
Readln;
end.

59

Diff es una variable de nmero real que contendr la diferencia entre la fecha actual y la fecha de
2012. Tambin utilizamos la funcin Abs, que devuelve el valor absoluto de un nmero (el nmero
sin el signo negativo).

Programa grabador de noticias

En este ejemplo, vamos a utilizar archivos de texto para almacenar ttulos de las noticias y, adems,
vamos a almacenar la fecha y la hora tambin.
Despus de cerrar y abrir de nuevo la aplicacin, mostrar el ttulo de las noticias introducidas
anteriormente con su fecha/hora:
program news;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
Title: string;
F: TextFile;
begin
AssignFile(F, 'news.txt');
if FileExists('news.txt') then
begin
// Mostrar noticias antiguas
Reset(F);
while not Eof(F) do
begin
Readln(F, Title);
Writeln(Title);
end;
CloseFile(F); // Lectura desde F finalizada
Append(F);
// Abrir nuevamente archivo para agregar
end
else
Rewrite(F);
Write('Ingrese hora actual ttulo noticias: ');
Readln(Title);
Writeln(F, DateTimeToStr(Now), ', ', Title);
CloseFile(F);
Write('Presione Enter para cerrar');
Readln;
end.

60

Constantes
Las constantes son similares a las variables. Tienen nombres y puede almacenar valores, pero
difieren de las variables para modificar dicho valor. Los valores constantes no pueden ser
modificados durante la ejecucin de la aplicacin, y sus valores se deben determinar antes de
compilar la aplicacin.
Hemos utilizado las constantes de una forma diferente antes, sin nombrarlos, as como un valor
entero o de cadena como en este ejemplo:
Writeln(5);
Writeln('Hola');

El valor 5 nunca va a cambiar despus de ejecutar la aplicacin. 'Hola' es tambin una constante de
cadena.
Podemos definir constantes usando la palabra reservada Const despus de la clusula uses clause
como en el siguiente ejemplo:

Programa consumo de combustible


program FuelConsumption;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
const GallonPrice = 6.5;
var
Payment: Integer;
Consumption: Integer;
Kilos: Single;
begin
Write('Cunto pag por el combustible de su automvil ?: ');
Readln(Payment);
Write('Cul es el consumo de su automvil? (Km/Galn): ');
Readln(Consumption);
Kilos:= (Payment / GallonPrice) * Consumption;

61

Writeln('Este combustible mantendr su vehculo funcionando durante : ',


Format('%0.1f', [Kilos]), ' Kilometros');
Write('Presione Enter');
Readln;
end.

En el ejemplo anterior, se calculan los kilmetros que el coche podra recorrer con el combustible
actual de acuerdo a los siguientes hechos:
1. Consumption: Se ha utilizado la variable Consumption para almacenar kilmetros por galn
para el coche actual
2. Payment: Hemos utilizado la variable Payment para almacenar la cantidad de dinero que
pagamos por el combustible actual
3. GallonPrice: Hemos usado la constante GallonPrice para almacenar el precio de un galn de
combustible para el pas actual. Este valor no debe ser introducida por el usuario, sino que
debe ser definido por el programador.
Las constantes se recomiendan cuando se utiliza el mismo valor muchas veces en la aplicacin. Si
tuvieramos que cambiar este valor, podemos hacerlo de una vez en la cabecera de cdigo.

Tipos ordinales
Los tipos ordinales son valores enteros que utilizan indicaciones literales en lugar de nmeros. Por
ejemplo, si tenemos que definir fecha/hora en (rabe / Ingls / Francs) podemos usar el valor 1
para idioma rabe, 2 para Ingls, y 3 para el francs. Otros programadores no conocern el
significado de los valores de 1, 2 y 3, a menos que encuentren comentarios. Ser ms fcil de leer si
lo hacemos con los tipos ordinales, como en el siguiente ejemplo:
program OrdinalTypes;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
type
TLanguageType = (ltArabic, ltEnglish);
var
Lang: TLanguageType;
AName: string;
Selection: Byte;
begin

62

Write('Por favor seleccione el lenguaje: 1 (Arabe), 2 (Ingles)');


Readln(Selection);
if Selection = 1 then
Lang:= ltArabic
else
if selection = 2 then
Lang:= ltEnglish
else
Writeln('Ingreso errneo');
if Lang = ltArabic then
Write(' : ')
else
if Lang = ltEnglish then
Write('Cul es su nombre: ');
Readln(AName);
if Lang = ltArabic then
begin
' , AName);
Writeln('
Write(';)'
end
else
if Lang = ltEnglish then
begin
Writeln('Hola ', AName);
Write('Presione la tecla Enter para cerrar');
end;
Readln;
end.

Los tipos Integer, Char y Boolean son tipos ordinales, mientras que los nmeros reales y las
cadenas no lo son.

Conjuntos (Sets)
Los tipos Set pueden contener varias propiedades o caractersticas de una variable. Los conjuntos se
utilizan slo con valores ordinales.
Por ejemplo, si tenemos que definir el apoyo del sistema operativo para las aplicaciones, podemos
hacerlo como sigue:
1. Definir el tipo ordinal que representa los sistemas operativos : TApplicationEnv:
TApplicationEnv = (aeLinux, aeMac, aeWindows);

2. Definir la aplicacin como conjunto de TApplicationEnv por ejemplo:

63

FireFox: set of TApplicationEnv;

3. Poner los valores del sistema operativo en la variable de conjunto de aplicacin:


FireFox:= [aeLinux, aeWindows];
program Sets;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
type
TApplicationEnv = (aeLinux, aeMac, aeWindows);
var
FireFox: set of TApplicationEnv;
SuperTux: set of TApplicationEnv;
Delphi: set of TApplicationEnv;
Lazarus: set of TApplicationEnv;
begin
FireFox:= [aeLinux, aeWindows];
SuperTux:= [aeLinux];
Delphi:= [aeWindows];
Lazarus:= [aeLinux, aeMac, aeWindows];
if aeLinux in Lazarus then
Writeln('Esta es una versin de Lazarus para Linux')
else
Writeln('Esta no es una version de Lazarus para Linux ');
if aeLinux in SuperTux then
Writeln('Esta es una versin de SuperTux para Linux')
else
Writeln('Esta no es una versin de SuperTux para Linux');
if aeMac in SuperTux then
Writeln(' Esta es una versin de SuperTux para Mac')
else
Writeln(' Esta no es una versin de SuperTux para Mac');
Readln;
end.

Tambin podemos utilizar la sintaxis para establecer otros tipos ordinales, como nmeros enteros:
if Month in [1, 3, 5, 7, 8, 10, 12] then
Writeln('Este mes contiene 31 das');

O caracteres:
64

if Char in ['a', 'A'] then


Writeln('Esta letra es A');

65

Manejo de excepciones
Hay dos tipos de errores: errores de compilacin como el uso de una variable sin definir en la
seccin de Var, o escribir instrucciones con sintaxis incorrecta. Los primeros impedirn la
compilacion de la aplicacin y el compilador mostrar un mensaje apropiado y apunta a la lnea que
contiene el error.
El segundo tipo es el error de tiempo de ejecucin. Este tipo de error se produce mientras se ejecuta
la aplicacin, por ejemplo, la divisin por cero, en una lnea como esta:
x:= y / z;

Esta es una sintaxis vlida, pero en tiempo de ejecucin un usuario podra introducir 0 en la variable
Z, y luego la aplicacin se bloquear y mostrar un mensaje de error divisin por cero.
Tratar de abrir un archivo que no existe generar un error en tiempo de ejecucin (Archivo no
encontrado), o tambin cuando se intenta crear un archivo en un directorio de slo lectura.
El compilador no puede detectar errores de este tipo, que slo se producen despus de ejecutar la
aplicacin.
Para crear una aplicacin fiable que no se colgar con los errores de ejecucin, debemos utilizar el
control de excepciones.
Existen diferentes mtodos de tratamiento de excepciones en Object Pascal:

Declaracion Try except


Sintxis:
try
// Start of protected code
CallProc1;
CallProc2;
// End of protected code
except
on e: exception do // Exception handling
begin
Writeln('Error: ' + e.message);
end;
end;

Ejemplo para divisin:


program ExceptionHandling;

66

{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, sysutils
{ usted puede agregar unidades despues de aqu };
var
x, y: Integer;
Res: Double;
begin
try
Write('Ingrese x: ');
Readln(x);
Write('Ingrese y: ');
Readln(y);
Res:= x / y;
Writeln('x / y = ', Res);
except
on e: exception do
begin
Writeln('Un error ha ocurrido: ', e.message);
end;
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Hay dos secciones de la declaracin try. El primero es el bloque que hay que proteger, que reside
entre try ... except. La otra parte existe entre except .. end.
Si algo va mal en la primera seccin (try except), la solicitud pasar a la seccin de excepcin
(except.. end) y no se bloquear, sino que se mostrar el mensaje de error apropiado y continuar la
ejecucin.
Esta es la lnea que podra elevar la excepcin si el valor de y es cero:
Res:= x / y;

Si no hay una excepcin, la parte except .. end no ser ejecutada.

Try finally
Sintxis:

67

try
// Start of protected code
CallProc1;
CallProc2;
// End of protected code
finally
Writeln('Esta lnea ser impresa en pantalla con seguridad');
end;

Programa de divisin usando el mtodo try finally:


program ExceptionHandling;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despues de aqu };
var
x, y: Integer;
Res: Double;
begin
try
Write('Input x: ');
Readln(x);
Write('Input y: ');
Readln(y);
Res:= x / y;
Writeln('x / y = ', Res);
finally
Write('Presione la tecla Enter para cerrar');
Readln;
end;
end.

Esta vez, la parte finally .. end se ejecuta en todos los casos, independientemente de si hay un
error. .

Elevando una excepcin


A veces necesitamos generar/elevar una excepcin para evitar un error lgico. Por ejemplo, si el
usuario introduce el valor 13 para la variable mes, podramos lanzar una excepcin dicindole que
ha violado el rango de meses.

68

Ejemplo:
program RaiseExcept;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despues de aqu };
var
x: Integer;
begin
Write('Por favor ingrese un nmero entre 1 y 10: ');
Readln(X);
try
if (x < 1) or (x > 10) then // elevar excepcin
raise exception.Create('Nmero fuera de rango');
Writeln(' X * 10 = ', x * 10);
except
on e: exception do // capturar mi excepcin
begin
Writeln('Error: ' + e.Message);
end;
end;
Write('Presione Enter para cerrar');
Readln;
end.

Si el usuario introduce un valor fuera del rango de 1 al 10, una excepcin se genera (X est fuera de
rango), y si no hay manejo de excepciones para esta parte, la aplicacin se colgar. Pero debido a
que try except envuelve el cdigo que contiene la palabra clave raise, la aplicacin no se bloquear,
sino que se mostrar el mensaje de error.

69

Captulo Dos
Programacin
Estructurada

70

Introduccin
El trmino programacin estructurada naci luego de que los programas se empezaran a
expandir. El cdigo fuente de una aplicacin grande se hace ilegible (e inmanejable) cuando se usa
cdigo no estructurado en un nico archivo. Antes de la programacin estructurada se utilizaba
mucho la sentencia GOTO (que permite el salto incondicional de una parte a otra dentro del
cdigo de un programa), lo que resultaba en programas muy difciles de seguir; este cdigo enorme
con el uso (y abuso) de la sentencia GOTO dentro de un enorme archivo se conoca como cdigo
espagueti, y puede convertirse en una pesadilla para mantener (encontrar errores, introducir
mejoras, entender el funcionamiento). A la metodologa de programacin estructurada tambin se la
conoce como Programacin sin goto.
En la programacin estructurada, nosotros podemos dividir el cdigo fuente de una aplicacin en
partes ms pequeas, llamadas procedimientos y funciones, y tambin podemos agrupar
procedimientos y funciones relacionados con una tarea en particular dentro del programa, en
archivos de cdigo fuente separados llamados unidades.
Beneficios de la programacin estructurada:
1. Divisin del cdigo de una aplicacin para hacerlo ms legible.
2. Reutilizacin de cdigo: los procedimientos y las funciones pueden ser utilizados desde
distintas partes del programa muchas veces sin necesidad de tener que reescribir (y duplicar)
cdigo.
3. Varios programadores pueden compartir cdigo y participar en un mismo proyecto al
mismo tiempo. Cada programador puede escribir sus propios procedimientos y funciones en
una unidad separada, y entonces integrar esas unidades en el proyecto.
4. El mantenimiento y las mejoras a la aplicacin se simplifican: es ms fcil encontrar
errores en el cdigo del programa (llamados bugs) si este est dividido, y se facilita el
poder mejorar los procedimientos (y funciones), el agregado de nuevas unidades, etc.
5. Posibilidad de dividir la lgica de la aplicacin en mdulos y capas: por ejemplo podemos
escribir una unidad que contenga procedimientos para lectura/escritura de datos desde/hacia
archivos, otra que contenga una capa con reglas de validacin, y otra ms que se encargue
de la interaccin con el usuario (capa de interfaz con el usuario).

Procedimientos
En captulos anteriores hemos usado algunos procedimientos, como Writeln, Readln, Reset, etc,
pero es momento de que aprendamos a escribir nuestros propios procedimientos que puedan ser
usados por nuestras propias aplicaciones.
71

En el siguiente ejemplo nosotros escribiremos dos procedimientos: SayHello (decir hola) and
SayGoodbye (decir adis):
program Estructurado;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} Classes
{ usted puede agregar unidades despus de aqu };
procedure SayHello;
begin
Writeln('Hola a todos !!!');
end;
procedure SayGoodbye;
begin
Writeln('Adis');
end;
begin // Aqu comienza el cdigo principal de la aplicacin
Writeln('Se est ejecutando el cdigo principal de la aplicacin');
SayHello;
Writeln('Esta aplicacin utiliza programacin estructurada');
SayGoodbye;
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.

Podemos observar que un procedimiento tiene el aspecto de un pequeo programa, con su propio
bloque begin---end, y el mismo puede ser llamado desde el cdigo principal de la aplicacin.

Parmetros
En el siguiente ejemplo, veremos cmo usar los parmetros, que son valores que se envan al
procedimiento cuando se lo llama (en este ejemplo x e y son dos parmetros):
procedure WriteSumm(x, y: Integer);
begin
Writeln('El resultado de la suma es: ', x, ' + ', y, ' = ', x + y)
end;
begin
WriteSumm(2, 7);
Write('Presione la tecla Enter para finalizar el programa');
Readln;
end.

Dentro del cdigo principal de la aplicacin, nosotros llamamos al procedimiento WriteSumm


pasndole los valores numricos 2 y 7, y el procedimiento los recibe dentro de las variables enteras
72

x, y para luego mostrar como resultado el valor de la suma de ambas variables.


En el siguiente ejemplo, nosotros reescribiremos la aplicacin de restaurante usando
procedimientos:

73

Programa de restaurante usando procedimientos


procedure Menu;
begin
Writeln('Bienvenido al Restaurante Pascal. Por favor, seleccione su orden');
Writeln('1 - Pollo
(10$)');
Writeln('2 - Pescado
(7$)');
Writeln('3 - Carne
(8$)');
Writeln('4 Ensalada
(2$)');
Writeln('5 - Jugo de naranja (1$)');
Writeln('6 - Leche
(1$)');
Writeln;
end;
procedure GetOrder(AName: string; minutos: Integer);
begin
Writeln('Ud. ha ordenado : ', AName, ', esto tardar ',
minutos, ' minutos');
end;
// Cdigo principal de la aplicacin
var
Meal: Byte;
begin
Menu;
Write('Por favor ingrese su seleccin: ');
Readln(Meal);
case Meal of
1: GetOrder('Pollo', 15);
2: GetOrder('Pescado', 12);
3: GetOrder('Carne', 18);
4: GetOrder('Ensalada', 5);
5: GetOrder('Jugo de naranja', 2);
6: GetOrder('Leche', 1);
else
Writeln('Seleccin incorrecta');
end;
Write('Presione la tecla Enter para cerrar');
Readln;
end.

Ahora el cdigo del programa principal se hizo ms pequeo y ms legible. Los detalles de las otras
partes del programa fueron separados en procedimientos, como get order (tomar pedido) y display
menu (mostrar el men de pedidos).

74

Funciones
Las funciones son similares a los procedimientos, pero tienen una caracterstica adicional, que es la
de retornar un valor. En captulos anteriores usamos funciones como por ejemplo UpperCase ,que
convierte un texto a maysculas, o Abs que devuelve el valor absoluto de un nmero.
En el ejemplo siguiente escribiremos la funcin GetSumm ,que recibe dos valores numricos enteros
y retorna como resultado la suma de ambos:
function GetSumm(x, y: Integer): Integer;
begin
Result:= x + y;
end;
var
Sum: Integer;
begin
Sum:= GetSumm(2, 7);
Writeln('La suma 2 + 7 es igual a ', Sum);
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.

Observemos que declaramos a la funcin para que devuelva un valor de tipo integer (entero), y
dentro de la misma usamos la palabra clave (keyword) Result que representa el valor de salida de la
funcin.
En el cdigo principal de la aplicacin usamos la variable Sum, que es donde se recibir el valor
devuelto por la funcin, aunque tambin se podra eliminar esta variable intermediaria Sum y
llamar a la funcin GetSum directamente dentro del procedimiento Writeln. Justamente esta es una
diferencia entre las funciones y los procedimientos: podemos llamar funciones como parmetros de
entrada en otros procedimientos (o funciones), pero no podemos llamar a procedimientos como
parmetros de otras funciones y procedimientos. Mejor verlo con un ejemplo, donde eliminaremos
la variable Sum usada en el ejemplo anterior, lo que resulta en un programa ms simple todava:
function GetSumm(x, y: Integer): Integer;
begin
Result:= x + y;
end;
begin
Writeln('La suma de 2 y 7 es ', GetSumm(2, 7));
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.

Tip: Una funcin tambin puede ejecutarse como si fuera un procedimiento, en ese caso se ignora
el valor devuelto. En algunas ocasiones esto puede resultar de utilidad.

75

En el ejemplo que sigue a continuacin reescribiremos el programa Restaurante para usar funciones,
lo que lo simplificar ms an.

Usando funciones en el programa Restaurante


procedure Menu;
begin
Writeln('Bienvenido al Restaurante Pascal. Por favor, seleccione su orden');
Writeln('1 - Pollo
(10$)');
Writeln('2 - Pescado
(7$)');
Writeln('3 - Carne
(8$)');
Writeln('4 Ensalada
(2$)');
Writeln('5 - Jugo de naranja (1$)');
Writeln('6 - Leche
(1$)');
Writeln('X no deseo ordenar nada');
Writeln;
end;
function GetOrder(AName: string; minutos, Price: Integer): Integer;
begin
Writeln('Ud. ha ordenado: ', AName, ' esto tardar ', minutos, ' minutos');
Result:= Price;
end;
var
Selection: Char;
Price: Integer;
Total: Integer;
begin
Total:= 0;
repeat
Menu;
Write('Por favor ingrese su seleccin: ');
Readln(Selection);
case Selection of
'1': Price:= GetOrder('Pollo', 15, 10);
'2': Price:= GetOrder('Pescado', 12, 7);
'3': Price:= GetOrder('Carne', 18, 8);
'4': Price:= GetOrder('Ensalada', 5, 2);
'5': Price:= GetOrder('Jugo de naranja', 2, 1);
'6': Price:= GetOrder('Leche', 1, 1);
'x', 'X': Writeln('Muchas gracias');
else
begin
Writeln('Seleccin incorrecta');
Price:= 0;
end;
end;
Total:= Total + Price;

76

until (Selection = 'x') or (Selection = 'X');


Writeln('Precio total
= ', Total);
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.

Variables locales
Podemos definir variables (llamadas locales) dentro de un procedimiento o funcin. Estas
variables sern usadas nicamente dentro de este cdigo y no sern accesibles fuera del
procedimiento (o funcin) donde estn escritas.
Ejemplo:
procedure Loop(Counter: Integer);
var
i: Integer;
Sum: Integer;
begin
Sum:= 0;
for i:= 1 to Counter do
Sum:= Sum + i;
Writeln('La suma de ', Counter, ' nmeros es: ', Sum);
end;
begin
// Cdigo principal del programa
Loop(5);
Write('Presione la tecla Enter para terminar el programa');
Readln;
end.

En el procedimiento Loop , usamos dos variables locales llamadas I y Sum. Las variables locales se
almacenan en la pila (stack), un rea de memoria temporal que almacena variables hasta que la
ejecucin del procedimiento (o la funcin) termine. Por este motivo, estas variables locales no
estarn accesibles fuera del procedimiento, e incluso el rea de memoria que ocupaban podr ser
sobreescrita luego, por ejemplo en el momento en que dentro del programa se ejecuta la siguiente
lnea de cdigo:
Write('Presione la tecla Enter para terminal el programa');

Las variables globales son accesibles desde el cdigo principal del programa y tambin dentro de
los procedimientos (y funciones). Los valores almacenados por este tipo de variables se mantienen
durante todo el tiempo en que el programa est activo, pero tiene el inconveniente de que en caso de
errores puede ser difcil de encontrarlos, ya que pueden ser modificados desde cualquier lugar del
programa, incluyendo procedimientos (y funciones). Por este motivo deberan tratar de evitarse las
variables de tipo global en la medida de lo posible (adems es algo que atenta contra la filosofa de
la programacin estructurada, donde el interior de cada procedimiento (o funcin) se mantiene (o se
debera mantener) aislado del resto del programa.
Al definir variables de tipo local garantizamos su privacidad, garantizando que los
77

procedimientos o funciones puedan ser portados a otros programas o llamados desde cualquier
lugar sin preocuparnos por los valores de las variables globales.

78

Aplicacin: base de datos de noticias (News database)

En este ejemplo tenemos tres procedimientos y una funcin: Add News title (agregar nueva
noticia), display all News (mostrar todas las noticias), searching (bsqueda), and displaying menu
(mostrar men de opciones), permitiendo al usuario seleccionar la funcin que desea ejecutar:
program news;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ usted puede agregar unidades despus de aqu };
type
TNews = record
ATime: TdateTime;
Title: string[100];
end;

// Fecha y hora
// Titular de la noticia (mximo 100 caracteres)

procedure AddTitle; // Agregar titular de noticia


var
F: file of TNews;
News: TNews;
begin
AssignFile(F, 'noticias.dat');
Write('Ingrese el titular de la noticia: ');
Readln(News.Title);
News.ATime:= Now;
if FileExists('noticias.dat') then
begin
FileMode:= 2; // Lectura/escritura
Reset(F);
Seek(F, System.FileSize(F)); //Ir al final para agregar un registro
end
else
Rewrite(F);
Write(F, News);
CloseFile(F);
end;
procedure ReadAllNews; // Leer todos los titulares
var
F: file of TNews;
News: TNews;
begin
AssignFile(F, 'noticias.dat');
if FileExists('noticias.dat') then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, News);

79

Writeln('------------------------------------------');
Writeln('Titular: ', News.Title);
Writeln('Fecha y hora: ', DateTimeToStr(News.ATime));
end;
CloseFile(F);
end
else
Writeln('Base de datos vaca');
end;
procedure Search; // Bsqueda de una noticia en la base de datos
var
F: file of TNews;
News: TNews;
Keyword: string;
Found: Boolean;
begin
AssignFile(F, 'noticias.dat');
Write('Ingrese la palabra (o parte de la misma) que desee buscar: ');
Readln(Keyword);
Found:= False;
if FileExists('noticias.dat') then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, News);
if Pos(LowerCase(Keyword), LowerCase(News.Title)) > 0 then
begin
Found:= True;
Writeln('------------------------------------------');
Writeln('Titular: ', News.Title);
Writeln('Fecha y hora: ', DateTimeToStr(News.ATime));
end;
end;
CloseFile(F);
if not Found then
Writeln(Keyword, ' No se encontr un titular que coincida');
end
else
Writeln('Base de datos vaca');
end;
function Menu: char;
begin
Writeln;
Writeln('...........Base de datos de titulares de noticias..........');
Writeln('1. Agregar un titular nuevo');
Writeln('2. Mostrar todos los titulares');
Writeln('3. Bsqueda de un titular');
Writeln('x. Finalizar');
Write('Por favor ingrese su seleccin : ');
Readln(Result);
end;
// Cdigo principal de la aplicacin
var

80

Selection: Char;
begin
repeat
Selection:= Menu;
case Selection of
'1': AddTitle;
'2': ReadAllNews;
'3': Search;
end;
until LowerCase(Selection) = 'x';
end.

Este programa al estar dividido en funciones y procedimientos (adems no no usar variables


globales) es fcil de leer. El cdigo fuente del cdigo principal queda bien compacto: es muy fcil
agregar nuevas caractersticas a cualquiera de los procedimientos sin afectar o tener que modificar
otras partes del programa.

81

Funciones como parmetros de entrada


Como hemos visto anteriormente, podemos llamar a una funcin como un parmetro de entrada de
procedimiento / funcin, ya que podemos tratarlo como si fuera un valor.
Esto se muestra en el siguiente ejemplo:
function DoubleNumber(x: Integer): Integer;
begin
Result:= x * 2;
end;
// Cdigo principal
begin
Writeln('El doble de 5 es : ', DoubleNumber(5));
Readln;
end.

Observemos que hemos llamado a la funcin DoubleNumber desde el interior del procedimiento
Writeln.
Tambin podemos modificar de nuevo el ejemplo, para usar una variable intermedia MyNum para
almacenar el resultado de la funcin, y luego mostrar el valor de esta variable dentro del
procedimiento WriteLn (que recibir esta variable como parmetro de entrada):
function DoubleNumber(x: Integer): Integer;
begin
Result:= x * 2;
end;
// Cdigo principal
var
MyNum: Integer;
begin
MyNum:= DoubleNumber(5);
Writeln('El doble de 5 es : ', MyNum);
Readln;
end.

Como podemos observar, estamos agregando una variable intermedia para hacer exactamente lo
mismo. Dentro de los entornos integrados de desarrollo (IDE, Integrated Development
Environment) como Lazarus, existe la posibilidad de modificar automticamente el cdigo para
agregar (o para suprimir) estas variables intermedias, lo que puede ayudar a clarificar/simplificar el
cdigo. Este tipo de modificaciones semi-automticas realizadas en el cdigo fuente (las
posibilidades son muchsimas y exceden por mucho el alcance de esta documentacin de carcter
introductorio) por el IDE se conocen como Refactorizacin del cdigo.
Tambin podemos llamar a funciones dentro de condiciones if o dentro de bucles:
function DoubleNumber(x: Integer): Integer;
begin

82

Result:= x * 2;
end;
// Cdigo principal
begin
if DoubleNumber(5) > 10 then
Writeln('Este nmero es mayor que 10')
else
Writeln('Este nmero es igual o menor que 10');
Readln;
end.

Paramtros de salida en procedimientos o funciones


En la pgina anterior vimos que slo se est retornando una nica variable como salida de una
funcin, pero... cmo podemos retornar ms de una variable como salida de una funcin o
procedimiento ?.
Hagamos este experimento:
procedure DoSomething(x: Integer);
begin
x:= x * 2;
Writeln('El valor desde dentro del procedimiento: x = ', x);
end;
// Cdigo principal
var
MyNumber: Integer;
begin
MyNumber:= 5;
DoSomething(MyNumber);
Writeln('Desde la parte principal del programa, MyNumber = ', MyNumber);
Writeln('Presione la tecla Enter para finalizar');
Readln;
end.

En este ejemplo, el procedimiento doSomething (hacer algo) recibe un valor entero en la variable
x, entonces lo multiplica por dos, y finalmente lo muestra.
En la parte principal del programa, declaramos la variable MyNumber como un entero, le asignamos
el valor 5 y se la pasamos como parmetro al procedimiento DoSomething. En este caso, el valor de
la variable MyNumber (5) es copiado en la variable x.
Despus de que se llama a la funcin, el valor de x ser 10, pero cuando mostramos por pantalla el
valor de MyNumber despus del procedimiento encontramos de que mantiene el valor 5. De ah
podemos deducir que las dos variables MyNumber y x tienen dos ubicaciones diferentes en la
memoria, algo que es lo normal.

83

Esta forma de pasar un parmetro a un procedimiento (o funcin) se conoce como paso de


parmetro(s) por valor, ya que de esta forma no se afecta el valor del parmetro original
MyNumber. Al pasar parmetros por valor tambin podemos usar constantes, por ejemplo:
DoSomething(5);

84

Paso de parmetros por referencia


Si agregamos la palabra reservada (keyword) var en la declaracin de los parmetros del
procedimiento DoSomething, las cosas ahora sern diferentes:
procedure DoSomething(var x: Integer); // Agregamos la palabra reservada var
begin
x:= x * 2;
Writeln('El valor desde dentro del procedimiento: x = ', x);
end;
// Cdigo principal
var
MyNumber: Integer;
begin
MyNumber:= 5;
DoSomething(MyNumber);
Writeln('Desde la parte principal del programa, MyNumber = ', MyNumber);
Writeln('Presione la tecla Enter para finalizar');
Readln;
end.

Esta vez el valor de la variable MyNumber cambi y dentro del procedimiento tom el valor de la
variable x ,por lo que se deduce que ahora ambas variables comparten la misma ubicacin en la
memoria.
El pasaje de parmetros por referencia requiere que el parmetro sea una variable del mismo tipo: si
el parmetro declarado es de tipo byte, entonces MyNumber debe ser declarado como Byte, si es de
tipo Integer (entero), entonces MyNumber debe ser una variable entero (Integer).
Importante: No se puede pasar una constante a un procedimiento (o funcin) cuyo parmetro espere
que se le pase un valor por referencia. El siguiente ejemplo genera un error cuando se llama al
procedimiento DoSomething, porque se espera una variable y no una constante.
DoSomething(5);

En el paso de parmetro(s) por valor s se puede usar el ejemplo mostrado, pero siempre se debe
tener en cuenta que al pasar un parmetro por referencia el valor de la variable pasada puede
cambiar (de hecho, la idea de pasar por referencia es que dentro del procedimiento o funcin se
cambie el valor de la(s) variable(s).
En el siguiente ejemplo el procedimiento SwapNumbers (intercambiar nmeros) recibe dos
variables A y B (pasadas por referencia) e intercambia sus valores:
procedure SwapNumbers(var x, y: Integer);
var
Temp: Integer;
begin
Temp:= x;

85

x:= y;
y:= Temp;
end;
// Cdigo principal
var
A, B: Integer;
begin
Write('Por favor ingrese el valor para A: ');
Readln(A);
Write('Por favor ingrese el valor para B: ');
Readln(B);
SwapNumbers(A, B);
Writeln('A = ', A, ', and B = ', B);
Writeln('Presione la tecla Enter para cerrar');
Readln;
end.

86

Unidades
Una unidad en Pascal es una biblioteca (un archivo separado del cdigo principal del programa) que
contiene procedimientos, funciones, constantes, variables y tipos definidos por el usuario; la misma
unidad puede ser usada desde muchas aplicaciones.
El propsito del uso de unidades es el siguiente:
1. Reutilizar cdigo: Almacenar procedimientos y funciones que son usados con frecuencia por
las aplicaciones en archivos externos. De esta forma se logra la reusabilidad (volver a
aprovechar lo que ya est escrito) de cdigo fuente en el desarrollo de software.
2. Agrupar procedimientos y funciones que realizan una determinada tarea dentro de una
biblioteca. En lugar de ocupar el cdigo fuente principal de la aplicacin con procedimientos
(y funciones) sin relacin entre s, es mejor agruparlas siguiendo una lgica dentro de
archivos separados usando unidades. Por ejemplo una unidad podra contener el cdigo
correspondiente a clculos, otra a acceso a base de datos, otra unidad se encargara de
imprimir, etc. Un cdigo organizado de esta forma (divide y vencers) es mucho ms fcil
de leer (y de mantener).
Para crear una unidad nueva, se usa la opcin Nueva unidad dentro del tem del men Archivo
de Lazarus. Esto crear una nueva unidad con un aspecto como el siguiente:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
implementation
end.

Una vez creada la unidad, esta se debe guardar usando un nombre a eleccin del programador, por
ejemplo test . De esa forma, el archivo que se guardar se llamar test.pas , pero el nombre de la
unidad se seguir llamado test dentro de nuestra aplicacin.
Dentro de la unidad podemos escribir procedimientos, funciones y cualquier otro cdigo fuente que
queremos que sea reusable:
unit Test;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;

87

const
GallonPrice = 6.5; // Precio del combustible
function GetKilometers(Payment, Consumption: Integer): Single;
implementation
function GetKilometers(Payment, Consumption: Integer): Single;
begin
Result:= (Payment / GallonPrice) * Consumption;
end;
end.

La constante GallonPrice (el precio del combustible) y la funcin GetKilometers sern accesibles
desde cualquier programa (o desde otras unidades).
Hemos colocado tambin el encabezado de la funcin dentro de una seccin de la unidad llamada
Interface ,que permita que esa funcin (junto con las constantes, tipos o variables) sean visibles
desde fuera de la unidad (desde el cdigo principal del programa o bien desde otras unidades). Por
el contrario, el cdigo dentro de la seccin implementation slo ser visible desde dentro de la
propia unidad.
Para usar esta unidad, creamos un nuevo programa en el mismo directorio donde se almacena la
misma (Test.pas), y dentro del cdigo fuente agregamos el nombre de la unidad dentro de la
clusula uses como se ve en el siguiente ejemplo:
program PetrolConsumption;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils,
{ puede agregar unidades despus de aqu }
Test; // Usamos la unidad test.pas
var
Payment: Integer;
Consumption: Integer;
Kilos: Single;
begin
Write('Ingrese el importe que pag por cargar gasolina: ');
Readln(Payment);
Write('Ingrese el consumo de gasolina (kilmetro por litro): ');
Readln(Consumption);
Kilos:= GetKilometers(Payment , Consumption);
Writeln('Esta cantidad de combustible puede mantener el vehculo en marcha
por: ',Format('%0.1f', [Kilos]), ' kilmetros');
Write('Presione Enter para cerrar');

88

Readln;
end.

Si necesita ir al cdigo fuente de la funcin GetKilometers desde el cdigo del programa, esto se
logra presionando la tecla Ctrl y haciendo clic con el ratn sobre el nombre de la funcin: esto
mostrar el cdigo fuente de la unidad con el cursor ubicado en la funcin.
Otra alternativa para acceder rpidamente al cdigo fuente de la unidad Test es colocar el cursor
sobre el nombre de la unidad (Test) y presionando la combinacin de teclas Alt + Enter.
Podemos acceder a las unidades desde nuestros programas bajo las siguientes condiciones:
1. El archivo de la unidad tienen que estar en el mismo directorio que la aplicacin, como
vimos en el ejemplo anterior.
2. Agregando la unidad al proyecto: Esto se hace abriendo el archivo de la unidad dentro de
Lazarus y luego incorporndola a los archivos que componen el programa desde el
Inspector de proyecto (a travs de la opcin Proyecto del men principal). Dentro de la
ventana del Inspector de proyecto se utiliza el botn Aadir y as incorporamos la
unidad abierta al proyecto.
3. Agregando el trayecto donde est ubicado el archivo de la unidad dentro de las opciones del
compilador: Proyecto/Opciones para el proyecto Opciones del compilador/Rutas y
agregndolas en la opcin Otros archivos de unidad.
A continuacin se muestra el aspecto que tienen en Lazarus las ventanas Inspector de Proyecto y
Opciones para el proyecto. En este caso los ejemplos son de Lazarus ejecutndose bajo el sistema
operativo Gnu/Linux.

89

Aspecto del Inspector de Proyecto en Lazarus

90

Aspecto de la ventana Opciones para el Proyecto en Lazarus

Unidades en Lazarus y Free Pascal


Las Unidades son una de las partes ms importantes en Lazarus y Free Pascal. Encontramos que los
recursos de que dispone el programador (procedimientos, funciones, tipos de datos, variables,
constantes, clases y componentes) estn en unidades.
Free Pascal tiene includa de serie una coleccin de unidades muy completa, con las
funcionalidades necesarias para crear diferentes tipos de aplicaciones. Al ser software libre,
podemos acceder (para ver o modificar) a todo el cdigo fuente de estas unidades. Estas razones
permiten que gracias a Free Pascal y Lazarus se puedan desarrollar aplicaciones con facilidad y
rpidamente.
SysUtils y Classes en Free Pascal / Lazarus son dos ejemplos de unidades que contienen
procedimientos y funciones de uso general.

Unidades escritas por el programador

91

Los programadores pueden utilizar las unidades provistas por Free Pascal / Lazarus y pueden
escribir sus propias unidades. Las unidades creadas por el programador son para satisfacer
requerimientos especiales de sus programas. Por ejemplo, si se est escribiendo un programa para
un garage de autos (cochera), entonces es probable que se cree una unidad que contenga cdigo
para agregado de datos de un nuevo automvil, bsqueda en la base de datos a travs de la patente,
etc.
El colocar procedimientos y funciones dentro de las unidades hace al programa ms legible,
facilitando que se pueda realizar un trabajo colaborativo entre varios desarrolladores, ya que cada
uno puede centrarse en una (o ms unidades), pudiendo verificar el funcionamiento de cada una en
forma independiente, para luego integrar estas unidades juntas en un proyecto.

92

Calendario Islmico Hejri

El calendario islmico Hejri (tambin conocido como calendario musulmn) est basado en meses
lunares. En este ejemplo vamos a crear una unidad para ayudar a convertir el calendario Gregoriano
al calendario lunar Hejri basndonos en las siguientes reglas:
1. El primer da del calendario Hejri es el 16 de julio del ao 622 en el calendario gregoriano.
2. En el calendario Hejri el ao contiene 354.367056 das.
3. Un mes del calendario Hejri contiene 29.530588 das.
Ms informacin: http://es.wikipedia.org/wiki/Calendario_musulmn
La unidad Hejri de ejemplo puede usarse para obtener la fase actual de la luna.
Este es el cdigo fuente de la unidad Hejri:
{
********************************************************************************
HejriUtils:
Author:
email:
Home page:
License:
Created on:
Last modifie:

Hejri Calnder converter, for FreePascal and Delphi


Motaz Abdel Azeem
motaz@code.sd
http://motaz.freevar.com/
LGPL
26.Sept.2009
26.Sept.2009

*******************************************************************************
}
unit HejriUtils;
{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ENDIF}
interface
uses
Classes, SysUtils;
const
HejriMonthsEn: array [1 .. 12] of string = ('Moharram', 'Safar', 'Rabie Awal',
'Rabie Thani', 'Jumada Awal', 'Jumada Thani', 'Rajab', 'Shaban', 'Ramadan',
'Shawal', 'Thi-Alqaida', 'Thi-Elhajah');
HejriMonthsAr: array [1 .. 12] of string = (' ' ,' ', '',
' ',' ',' ',' ' ,' ' ,'' ,
'' ,' ' ,';)'
HejriYearDays = 354.367056;
HejriMonthDays = 29.530588;

93

procedure DateToHejri(ADateTime: TDateTime; var Year, Month, Day: Word);


function HejriToDate(Year, Month, Day: Word): TDateTime;
procedure HejriDifference(Year1, Month1, Day1, Year2, Month2, Day2: Word;
var YearD, MonthD, DayD: Word);
implementation
var
HejriStart : TDateTime;
procedure DateToHejri(ADateTime: TDateTime; var Year, Month, Day: Word);
var
HejriY: Double;
Days: Double;
HejriMonth: Double;
RDay: Double;
begin
HejriY:= ((Trunc(ADateTime) - HejriStart - 1) / HejriYearDays);
Days:= Frac(HejriY);
Year:= Trunc(HejriY) + 1;
HejriMonth:= ((Days * HejriYearDays) / HejriMonthDays);
Month:= Trunc(HejriMonth) + 1;
RDay:= (Frac(HejriMonth) * HejriMonthDays) + 1;
Day:= Trunc(RDay);
end;
function HejriToDate(Year, Month, Day: Word): TDateTime;
begin
Result:= (Year - 1) * HejriYearDays + (HejriStart - 0) +
(Month - 1) * HejriMonthDays + Day + 1;
end;
procedure HejriDifference(Year1, Month1, Day1, Year2, Month2, Day2: Word; var
YearD, MonthD, DayD: Word);
var
Days1: Double;
Days2: Double;
DDays: Double;
RYear, RMonth: Double;
begin
Days1:= Year1 * HejriYearDays + (Month1 - 1) * HejriMonthDays + Day1 - 1;
Days2:= Year2 * HejriYearDays + (Month2 - 1) * HejriMonthDays + Day2 - 1;
DDays:= Abs(Days2 - Days1);
RYear:= DDays / HejriYearDays;
RMonth:= (Frac(RYear) * HejriYearDays) / HejriMonthDays;
DayD:= Round(Frac(RMonth) * HejriMonthDays);
YearD:= Trunc(RYear);
MonthD:= Trunc(RMonth);
end;
initialization
HejriStart:= EncodeDate(622, 7, 16);

94

end.

La unidad HejriUtils contiene los siguientes procedimientos y funciones:


1. DateToHejri: Este procedimiento convierte una fecha del calendario gregoriano a una fecha
del calendario Hejri, como se muestra en el siguiente ejemplo:
program Project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes , HejriUtils, SysUtils
{ usted puede agregar unidades despus de aqu };
var
Year, Month, Day: Word;
begin
DateToHejri(Now, Year, Month, Day);
Writeln('Fecha actual Hejri: ', Day, '-', HejriMonthsEn[Month],
'-', Year);
Readln;
end.

2.
3.

HejriToDate: Esta funcin convierte una fecha Hejri a una fecha en del calendario
gregoriano (valor TdateTime).
HejriDifference: Este procedimiento calcula la diferencia en aos, das y meses entre dos
fechas del calendario Hejri.

95

Sobrecarga (overloading) de procedimientos y funciones


La sobrecarga (overloading) de procedimientos y funciones permite escribir dos o ms
procedimientos/funciones con el mismo nombre pero diferentes parmetros. Con diferentes
parmetros nos refermos a diferentes tipos de parmetros o bien diferente cantidad de parmetros.
Por ejemplo, podemos necesitar escribir dos versiones de la misma funcin Sum, donde la primera
versin acepta y retorna nmeros enteros, pero la segunda versin necesitamos que acepte (y
retorne) nmeros reales:
program sum;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despus de aqu };
function Sum(x, y: Integer): Integer; overload;
begin
Result:= x + y;
end;
function Sum(x, y: Double): Double; overload;
begin
Result:= x + y;
end;
var
j, i: Integer;
h, g: Double;
begin
j:= 15;
i:= 20;
Writeln(J, ' + ', I, ' = ', Sum(j, i) );
h:= 2.5;
g:= 7.12;
Writeln(H, ' + ', G, ' = ', Sum(h, g) );
Write('Presione la tecla Enter para terminar');
Readln;
end.

Hemos usado la palabra reservada overload, para indicar que se usar una sobrecarga (overloading)
de funciones.

96

Valores por defecto para los parmetros


En los procedimientos y funciones, podemos colocar valores por defecto en los parmetros. En
estos casos se puede ignorar el envo de estos parmetros, ya que en lugar de eso se usarn los
valores por defecto.
Esto se ve en el ejemplo siguiente:
program defaultparam;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads} cthreads,{$ENDIF}{$ENDIF}Classes
{ usted puede agregar unidades despus de aqu };
function SumAll(a, b: Integer; c: Integer = 0; d: Integer = 0): Integer;
begin
result:= a + b + c + d;
end;
begin
Writeln(SumAll(1, 2));
Writeln(SumAll(1, 2, 3));
Writeln(SumAll(1, 2, 3, 4));
Write('Presione la tecla Enter para finalizar');
Readln;
end.

En este ejemplo, invocamos a la funcin SumAll tres veces: la primera vez usando dos valores, la
segunda vez usando tres y la ltima vez usamos cuatro valores. a y b son paramtros obligatorios
porque no les especificamos valores por defecto, entonces siempre deben especificarse al invocar la
funcin.
Podemos ignorar el envo de valores a los parmetros de la funcin desde la izquierda hacia la
derecha, por ejemplo, si no especificamos el parmetro c, entonces tampoco podemos enviar un
parmetro a d. De esta manera, si invocamos a la funcin como se ve a continuacin obtendremos
un mensaje de error:
Writeln(SumAll(1, 2, , 4));

Los valores por defecto para parmetros deben comenzar desde izquierda a derecha. No podemos
declarar un parmetro con valor por defecto y luego declarar otro a continuacin que no tenga un
valor por defecto, como se muestra a continuacin:
function ErrorParameters(a: Integer; b: Integer = 10; c: Integer; x: string);

En la declaracin de parmetros para procedimientos y funciones, debemos colocar los ms


importantes a la izquierda, y los menos importantes (que puedan ser ignorados) del lado derecho.

97

Ordenando datos (data sorting)


Nos introduciremos (en forma muy superficial) en el ordenamiento de datos, que forma parte dentro
del rea de estructuras de datos. Veremos cmo implementarlo a travs de procedimientos y
funciones.
El ordenamiento siempre se utiliza con matrices (una matriz array de una dimensin se llama
tambin vector) y listas. Supongamos que tenemos una lista de nmeros enteros y necesitamos
clasificarlos en orden ascendente o descendente. Para esto podemos usar diferentes mtodos:

Algoritmo de ordenacin por burbuja


Este algoritmo es uno de los ms sencillos (y tambin de los ms ineficientes en trminos de
velocidad si se desea ordenar una lista muy grande). Su funcionamiento es muy simple: Se compara
el primer tem del vector con el segundo, en caso de que se desee ordenarlos en forma ascendente se
pueden intercambiar de posicin mutuamente, dejando en el primer lugar el mayor (o el menor si se
desea ordenar la lista de menor a mayor). Luego se repite el proceso de comparacin entre el tem
de la posicin dos y el de la posicin tres, intercambindolos de posiciones entre s en el caso de
que fuera necesario. El proceso de comparacin-intercambio se repite con los siguientes tems hasta
llegar al ltimo. Entonces se vuelve a repetir el proceso desde el inicio: cuando no existan ms
tems que intercambiar entonces la lista estar ordenada.
Supongamos que tenemos un vector con 6 tems que almacenan los siguientes valores:
7

10

Observando los nmeros, vemos que har falta ms de una pasada (o ciclo) para ordenarlos.
Primera pasada: El primer nmero (7) se compara con el segundo (10) y si es mayor se
intercambian entre s, entonces el segundo se compara con el tercero (2) y as sucesivamente hasta
que el quinto nmero se compara con el sexto.
Despus de esta primera pasada (primer ciclo) los valores quedarn como se muestra a
continuacin:
7

10

Luego de una segunda pasada:


2

10

10

Tercera pasada:
2

Cuarta pasada:
98

10

Luego de la cuarta pasada ya tenemos a los nmeros ordenados, ya que no se necesitan ms


intercambiarlos de posicin. Entonces necesitamos (en este ejemplo) cuatro ciclos de intercambio
de valores (cuatro pasadas) para que la lista quede ordenada, y el ciclo nmero cinco es para
verificar que no existan ms tems para intercambiar.
El algoritmo se llama de burbuja porque los valores ms pequeos flotan como burbujas sobre
los valores ms grandes.
A continuacin veremos el cdigo fuente para el algoritmo de ordenacin por burbuja:
program BubbleSortProj;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
procedure BubbleSort(var X: array of Integer);
var
Temp: Integer;
i: Integer;
Changed: Boolean;
begin
repeat // Outer loop
Changed:= False;
for i:= 0 to High(X) - 1 do // Recorrido por los elementos
if X[i] > X[i + 1] then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;
until not Changed; // Repetir el bucle hasta que no existan intercambios
end;
var
Numbers: array [0 .. 9] of Integer;
i: Integer;
begin
Writeln('Por favor ingrese 10 nmeros al azar');
for i:= 0 to High(Numbers) do
begin
Write('#', i + 1, ': ');
Readln(Numbers[i]);
end;
BubbleSort(Numbers);
Writeln;
Writeln('Lista de nmeros ordenados: ');

99

for i:= 0 to High(Numbers) do


begin
Writeln(Numbers[i]);
end;
Write('Presione la tecla Enter para finalizar');
Readln;
end.

Se puede modificar el cdigo para que el ordenamiento de los nmeros ingresados se haga en forma
descendente, simplemente cambiando el operador mayor que (>) por menor que (<) en la siguiente
lnea:
if X[i] < X[i + 1] then

En el ejemplo siguiente, ordenaremos una lista de estudiantes a partir de sus calificaciones (notas),
colocando en primer lugar los que tuvieron mejores calificaciones, y los de peores calificaciones al
final de la lista:
Ordenando la lista de estudiantes por sus calificaciones
program smSort;

// Ordenando a los estudiantes segn sus calificaciones

{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes
{ usted puede agregar unidades despus de aqu };
type
TStudent = record
StudentName: string; // Nombre
Mark: Byte;
// Calificacin (nota)
end;
procedure BubbleSort(var X: array of TStudent);
var
Temp: TStudent;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i].Mark < X[i + 1].Mark then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;

100

until not Changed;


end;
var
Students: array [0 .. 9] of TStudent;
i: Integer;
begin
Writeln('Ingrese los datos de 10 estudiantes (nombre y calificacin):');
for i:= 0 to High(Students) do
begin
Write('Estudiante #', i + 1, '
nombre : ');
Readln(Students[i].StudentName);
Write('Estudiante #', i + 1, ' calificacin : ');
Readln(Students[i].Mark);
Writeln;
end;
BubbleSort(Students);
Writeln;
Writeln('Listado ordenado por calificacin: ');
Writeln('---------------------------------');
for i:= 0 to High(Students) do
begin
Writeln('# ', i + 1, ' ', Students[i].StudentName,
' con la calificacin (', Students[i].Mark, ')');
end;
Write('Presione la tecla Enter para finalizar');
Readln;
end.

El algoritmo de ordenacin por burbuja es muy simple y los programadores hasta pueden conocerlo
de memoria. Es apropiado para ordenar pequeas cantidades de datos. Si la cantidad de elementos a
ordenar es muy extensa, es ms recomendable optar por otro algoritmo ms eficiente.

Algoritmo de ordenacin por seleccin

Este algoritmo es similar al de burbuja, pero es ms veloz con grandes cantidades de datos. Este
algoritmo contiene dos bucles anidados (uno dentro de otro): el intercambio se realiza en el
buble interno, mientras que las comparaciones se hacen en el buble interno: se realizan muchas ms
comparaciones que intercambios. Observemos el siguiente cdigo donde se ve el funcionamiento de
este algoritmo:
program SelectionSort;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}

101

Classes
{ usted puede agregar unidades despus de aqu };
procedure SelectSort(var X: array of Integer);
var
i: Integer;
j: Integer;
SmallPos: Integer;
Smallest: Integer;
begin
for i:= 0 to High(X) -1 do // Buble externo
begin
SmallPos:= i;
Smallest:= X[SmallPos];
for j:= i + 1 to High(X) do // Buble interno
if X[j] < Smallest then
begin
SmallPos:= j;
Smallest:= X[SmallPos];
end;
X[SmallPos]:= X[i];
X[i]:= Smallest;
end;
end;
// Cdigo principal
var
Numbers: array [0 .. 9] of Integer;
i: Integer;
begin
Writeln('Por favor ingrese 10 nmeros al azar');
for i:= 0 to High(Numbers) do
begin
Write('#', i + 1, ': ');
Readln(Numbers[i]);
end;
SelectSort(Numbers);
Writeln;
Writeln('Lista de nmeros ordenada: ');
for i:= 0 to High(Numbers) do
begin
Writeln(Numbers[i]);
end;
Write('Presione la tecla Enter para finalizar');
Readln;
end.

En general el algoritmo de ordenacin por seleccin es ms eficiente que el de burbuja, pero el de


burbuja puede ser ms veloz si los elementos estn semiordenados (o completamente ordenandos,
en este caso no hay intercambio mutuo de elementos), mientras que el algoritmo de ordenacin por
seleccin tiene realiza el mismo nmero de ciclos independientemente del orden inicial de los datos.

102

Algoritmo de ordenacin Shell

Se trata de un algoritmo muy eficiente para grandes cantidades de datos; su comportamiento es


similar al algoritmo de burbuja si losdatos se encuentran semi-ordenados; como contrapartida el
cdigo es ms complejo que los dos algoritmos vistos anteriormente. El nombre deriva de su
creador, Donald Shell.
program ShellSort;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} Classes;
procedure ShellS(var X: array of Integer);
var
Done: Boolean;
Jump, j, i: Integer;
Temp: Integer;
begin
Jump:= High(X);
while (Jump > 0) do // bucle exteno
begin
Jump:= Jump div 2;
repeat
// bucle intermedio
Done:= True;
for j:= 0 to High(X) - Jump do // buble interno
begin
i:= j + Jump;
if X[j] > X[i] then // Intercambiar
begin
Temp:= X[i];
X[i]:= X[j];
X[j]:= Temp;
Done:= False;
end;
end;
// fin del bucle interno
until Done; // fin del bucle intermedio
end;
// fin del bucle externo
end;
var
Numbers: array [0..9] of Integer;
i: Integer;
begin
Writeln('Por favor ingrese 10 nmeros al azar');
for i:= 0 to High(Numbers) do
begin
Write('#', i + 1, ': ');
Readln(Numbers[i]);
end;

103

ShellS(Numbers);
Writeln;
Writeln('Lista de nmeros ordenada por el algoritmo Shell: ');
for i:= 0 to High(Numbers) do
begin
Writeln(Numbers[i]);
end;
Write('Presione la tecla Enter para finalizar');
Readln;
end.

104

Ordenando cadenas (strings)


Si necesitamos ordenar cadenas (strings) tales como nombres, direcciones, etc. podemos usar los
mismos operadores de comparacin (> y <) que usamos para ordenar nmeros.
En este caso, la comparacin se realiza desde los caracteres de la izquierda hacia la derecha, por
ejemplo la letra A se considera menor que la B, y el nombre 'Ahmed' es menor que 'Badr'. Si dos
cadenas tienen la misma letra inicial, la comparacin se har con el carcter siguiente. Por ejemplo
al comparar las cadenas 'Ali' y 'Ahmed', vemos que en este caso el carcter h se considera menor que
la l.
Ordenando a los estudiantes por nombre
program smSort;

// Ordenando a los estudiantes por su nombre

{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes;
type
TStudent = record
StudentName: string;
Mark: Byte;
end;
procedure BubbleSort(var X: array of TStudent);
var
Temp: TStudent;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i].StudentName > X[i + 1].StudentName then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;
until not Changed;
end;
var
Students: array [0 .. 9] of TStudent;
i: Integer;

105

begin
Writeln('Ingrese los datos de 10 estudiantes (nombre y calificacin)');
for i:= 0 to High(Students) do
begin
Write('Estudiante #', i + 1, ' nombre : ');
Readln(Students[i].StudentName);
Write('Estudiante #', i + 1, ' calificacin : ');
Readln(Students[i].Mark);
Writeln;
end;
BubbleSort(Students);
Writeln;
Writeln('Lista ordenada: ');
Writeln('--------------');
for i:= 0 to High(Students) do
begin
Writeln('# ', i + 1, ' ', Students[i].StudentName,
' calificacin (', Students[i].Mark, ')');
end;
Write('Precione la tecla Enter para finalizar');
Readln;
end.

Comparando los algoritmos de ordenacin


En el ejemplo siguiente compararemos la eficiencia de los tres algoritmos de ordenacin vistos en
este captulo, usando una gran lista de nmeros enteros y cronometrando el tiempo que demora cada
uno de los lagoritmos en ordenar la lista.
program SortComparison;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF}
Classes, SysUtils;
procedure BubbleSort(var X: array of Integer); // Ordenacin por burbuja
var
Temp: Integer;
i: Integer;
Changed: Boolean;
begin
repeat
Changed:= False;
for i:= 0 to High(X) - 1 do
if X[i] > X[i + 1] then
begin
Temp:= X[i];
X[i]:= X[i + 1];
X[i + 1]:= Temp;
Changed:= True;
end;

106

until not Changed;


end;
procedure SelectionSort(var X: array of Integer); // Ordenacin por seleccin
var
i: Integer;
j: Integer;
SmallPos: Integer;
Smallest: Integer;
begin
for i:= 0 to High(X) -1 do // Buble externo
begin
SmallPos:= i;
Smallest:= X[SmallPos];
for j:= i + 1 to High(X) do // Buble interno
if X[j] < Smallest then
begin
SmallPos:= j;
Smallest:= X[SmallPos];
end;
X[SmallPos]:= X[i];
X[i]:= Smallest;
end;
end;
procedure ShellSort(var X: array of Integer); // Ordenacin Shell
var
Done: Boolean;
Jump, j, i: Integer;
Temp: Integer;
begin
Jump:= High(X);
while (Jump > 0) do // Buble externo
begin
Jump:= Jump div 2;
repeat
// Buble intermedio
Done:= True;
for j:= 0 to High(X) - Jump do // Buble interno
begin
i:= j + Jump;
if X[j] > X[i] then // Intercambiar
begin
Temp:= X[i];
X[i]:= X[j];
X[j]:= Temp;
Done:= False;
end;
end; // fin del buble interno
until Done; // fin del buble intermedio
end; // fin del buble externo
end;
// Generar una lista de nmeros al azar
procedure RandomizeData(var X: array of Integer);
var
i: Integer;
begin

107

Randomize;
for i:= 0 to High(X) do
X[i]:= Random(10000000);
end;
var
Numbers: array [0 .. 1000000] of Integer;
i: Integer;
StartTime: TDateTime;
begin
Writeln('--- Lista generada completamente al azar ---');
RandomizeData(Numbers);
StartTime:= Now;
Writeln('Ordenando por el algoritmo de burbuja');
BubbleSort(Numbers);
Writeln('Lista ordenada en: (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
RandomizeData(Numbers);
Writeln('Ordenando por el algoritmo de seleccin');
StartTime:= Now;
SelectionSort(Numbers);
Writeln('Lista ordenada en: (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
RandomizeData(Numbers);
Writeln('Ordenando por el algoritmo Shell');
StartTime:= Now;
ShellSort(Numbers);
Writeln('Lista ordenada en: (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Writeln('--- Lista parcialmente ordenada ---');
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
StartTime:= Now;
Writeln('Ordenando por el algoritmo de burbuja');
BubbleSort(Numbers);
Writeln('Lista ordenada en (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
Writeln('Ordenando por el algoritmo de seleccin');
StartTime:= Now;
SelectionSort(Numbers);
Writeln('Lista ordenada en (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Writeln;
Numbers[0]:= Random(10000);
Numbers[High(Numbers)]:= Random(10000);
Writeln('Ordenando por el algoritmo Shell');

108

StartTime:= Now;
ShellSort(Numbers);
Writeln('Lista ordenada en (mm:ss): ',
FormatDateTime('nn:ss', Now - StartTime));
Write('Presione la tecla Enter para finalizar');
Readln;
end.

109

Captulo 3
La interfaz grfica

110

Introduccin
La interfaz grfica de usuario (GUI) es la nueva alternativa a la interfaz de consola. Contiene
formularios, botones, mensajes, mens y otros componentes grficos. Es ms sencillo para los
usuarios usar aplicaciones GUI que las aplicaciones de consola.
El GUI se usa para aplicaciones empresariales, sistemas operativos, juegos y desarrollo de
herramientas como Lazarus y muchas otras.

La primera aplicacin GUI.


Para crear una nueva aplicacin GUI hay que hacer click en men::
Project/New project/Application (Proyecto/Nuevo proyecto/Aplicacin)
Ahora guarda el proyecto haciendo click en:
File/Save All (Archivo/Guardar todo)
Ahora podemos crear una nueva carpeta, como primergui, donde guardar los archivos de nuestro
proyecto. Ahora guardaremos la unidad principal, por ejemplo, main.pas, y finalmente escogeremos
un nombre para nuestro proyecto primergui.lpi.
En la unidad principal podemos presionar F12 para ver el formulario asociado a la unidad principal,
que se ver algo parecido a esto:

Si lanzamos la aplicacin veremos una ventana como esta:

111

Ahora podemos cerrar la aplicacin y volver al entorno de diseo.


A continuacin, soltaremos un botn (button) de la pestaa de componentes standard en el
formulario:

Coloca el botn en cualquier lugar del formulario como en la imagen:

Podemos mostrar las propiedades del botn tales como Texto, nombre, anchura (caption, name,
112

width, etc) en el Inspector de objetos. Si este no aparece en las ventanas de Lazarus, podremos
mostrarlo haciendo click en Ventana/Inspector de objetos (Window/Object Inspector) del men
principal o presionando F11. Obtendremos una ventana como esta:

Debemos asegurarnos de que hemos seleccionado el Botn y no el Formulario antes de hacer


ninguna modificacin en sus propiedades. Ntese que el inspector de objetos tiene pestaas, la
primera muestra las Propiedades y en la segunda encontramos los Eventos. Cada pestaa mostrar
su propia pgina.
Ahora podemos cambiar el texto que se muestra en el botn modificando su propiedad (caption).
Despus seleccione la pestaa de Eventos en el inspector de objetos para mostrar la pgina de
Eventos y haga doble click en el evento (OnClick), se crear la siguiente plantilla de cdigo en la
unidad principal:
procedure TForm1.Button1Click(Sender: TObject);
begin
end;

Ahora escriba esta lnea en la plantilla del evento OnClick que Lazarus ha creado por nosotros:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Hola mundo, esta es mi primera GUI');
end;

113

Al hacer esto, cuando iniciemos la aplicacin, se mostrar una ventana de dialogo conteniendo el
mensaje deseado al hacer click en el botn con el ratn.
En Linux, encontraremos primergui como un archivo ejecutable en la misma carpeta del proyecto, y
firstgui.exe si estamos usando Windows. Estos son los archivos ejecutables que se pueden copiar a
otro ordenador y ejecutar sin necesidad de tener instalado Lazarus.
En el ejemplo anterior hay algunas cuestiones importantes:
1. Archivo principal de aplicacin: Se encuentra en primergui.lpi en el ejemplo. Podremos
verlo haciendo click en Project/Source. Veremos este cdigo:
program primergui;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms
{ usted puede agregar unidades despues de aqu }, main;
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

Deberemos modificar este cdigo en algunos casos segn nuestras necesidades, pero normalmente
podremos dejarlo tal como est y permitir a Lazarus manejarlo automticamente.
2. Unidad principal: Esta unidad es la que contiene las definiciones del formulario que aparece
automticamente cuando iniciamos la aplicacin.
A continuacin est el cdigo completo de la unidad principal con el evento OnClick.

unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls;

114

type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Hola mundo, esta es mi primera aplicacin GUI');
end;
initialization
{$I main.lrs}
end.

En la cabecera de la unidad encontramos la declaracin Tform1, que es similar a un tipo record,


pero esta es una Clase. Hablaremos acerca de las clases en el siguiente captulo: Programacin
orienta a objetos. Button1 est declarado en la clase TForm1.
Podremos ver el cdigo de esta unidad presionando Ctrl-F12 y seleccionando unidad principal.
3. Inspector de objetos/Propiedades: En esta pgina del inspector de objetos podemos ver y
modificar las propiedades de los objetos, como el texto de un botn o su localizacin, el
color del formulario, la fuente de una etiqueta. .
4. Inspector de objetos/Eventos: Esta pgina del inspector de objetos contiene los eventos de
los objetos que podemos recibir, como OnClick en un botn, Key Press en un cuadro de
texto, double click en una etiqueta, etc. Cuando se hace click en el evento de un
componente, Lazarus crea un nuevo procedimiento por nosotros para que introduzcamos el
cdigo que se desea ejecutar al producirse el evento. Escribiremos cdigo PASCAL como en
el ejemplo a continuacin para un evento OnClick de un botn:

procedure TForm1.Button1Click(Sender: TObject);


begin
ShowMessage('Hola mundo, esta es mi primera aplicacin GUI');
end;

115

Este procedimiento ser llamado cuando se haga click en el botn. El procedimiento recibe el
nombre de (handler).

116

Segunda aplicacin GUI


En este ejemplo se permitir al usuario introducir su nombre en un cuadro de texto Tedit y entonces,
al hacer click en el botn se mostrar un mensaje de felicitacin en una etiqueta (Tlabel).
Para escribir esta aplicacin siga estos pasos:
Cree una nueva aplicacin y gurdela con el nombre inputform. Guarde la unidad principal como
main.pas, ahora coloque los siguientes componentes en el formulario desde la pestaa de
componentes Standard.
2 Labels (Tlabel)
Edit box (Tedit)
Button (Tbutton)
Ahora modifique sus propiedades como se muestra a continuacin:
Form1:
Name: fmMain
Caption: Input form application
Label1:
Caption: Por favor ingrese su nombre
Label2:
Name: laYourName
Edit1:
Name: edName
Text:
Button1:
Caption: Click
Coloque los objetos en el formulario como se muestra en la imagen siguiente:

117

Escriba este cdigo en el evento OnClick del botn:


procedure TfmMain.Button1Click(Sender: TObject);
begin
laYourName.Caption:= 'Hola ' + edName.Text;
end;

Ahora podemos iniciar la aplicacin, escribir nuestro nombre en la caja de texto y hacer click en el
botn.
En el ejemplo anterior se ha utilizado la propiedad Text de la caja de texto edName para leer lo que
el usuario ha escrito. Esta es la alternativa grfica para el procedimiento Readln usado en las
aplicaciones de consola para recibir datos del usuario.
Tambin hemos utilizado la propiedad Caption del label laYourName para mostrar el mensaje. Este
es uno de los mtodos alternativos a Writeln en aplicaciones GUI.

Aplicacin Lista de objetos


En el siguiente ejemplo, necesitaremos aadir textos a un list box, borrarlos, o limpiar totalmente la
lista. Para hacer esto siga los siguientes pasos:
Cree una nueva aplicacin y coloque 4 botones (TButton), una caja de texto (TEdit), y un list
box (TListBox) en el formulario principal.
Cambie los nombres de los botones por los siguientes:
btAdd, btClear, btDelete, btClose
Ahora cambie el Caption de los botones acorde a su nombre y site los objetos en el
118

formulario como se muestra a continuacin:

- Escriba el siguiente cdigo en los eventos OnClick de los botones:


procedure TForm1.btAddClick(Sender: TObject);
begin
ListBox1.Items.Add(Edit1.Text);
end;
procedure TForm1.btClearClick(Sender: TObject);
begin
ListBox1.Clear;
end;
procedure TForm1.btDeleteClick(Sender: TObject);
var
Index: Integer;
begin
Index:= ListBox1.ItemIndex;
if Index <> -1 then
ListBox1.Items.Delete(Index);
end;
procedure TForm1.btCloseClick(Sender: TObject);
begin
Close;
end;

Al hacer click en el botn Add se aadir el texto de la caja de texto al listado. El botn Delete
borrar el objeto que actualmente est seleccionado. El botn clear borrar completamente la lista.
Finalmente el botn Close finalizar la aplicacin.

Aplicacin de edicin de texto


En este ejemplo se mostrar como crear un sencillo editor de texto.
Siga los siguientes pasos:

119

Comience una nueva aplicacin y coloque los siguientes objetos en el formulario principal:
- TMainMenu
- TMemo: cambie la propiedad align a alClient y ScrollBars a ssBoth
- TOpenDialog y TSaveDialog de la paleta de componentes Dialogs.

Haga doble Click en el componente MainMenu1 y aada el texto File (Archivo) a este hay
que crearle un submen que contenga las opciones Abrir, Guardar y cerrar como objetos de
men.

El formulario se ver algo as:

En el evento OnClick del objeto de men Abrir escriba el siguiente cdigo:

if OpenDialog1.Execute then
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);

Para Guardar introduzca este cdigo:

if SaveDialog1.Execute then
Memo1.Lines.SaveToFile(SaveDialog1.FileName);

Para cerrar escriba esto:

Close;

Despus de iniciar la aplicacin, podremos escribir texto y guardarlo en disco. Tambin es posible
abrir archivos existentes como los .pas.

120

121

Aplicacin de noticias
Esta vez escribiremos una aplicacin para almacenar ttulos de noticias, siga estos pasos:

Cree una nueva aplicacin y llamela gnews


Aada dos botones de tipo TButton
Aada dos cajas de texto(TEdit)
Aada un memo (TMemo)
Modifique las propiedades de los componentes de acuerdo con los siguientes valores.:

Button1
Caption: Aadir ttulo
Button2
Caption: Guardar
Anchors: Left=False, Right=True
Edit1:
Text=
Memo1
ScrollBars: ssBoth
ReadOnly: True
Anchors: Top=True, Left=Ture, Right=True, Bottom=Ture
Tendr un formulario similar a este:

Para el evento OnClick del botn Aadir ttulo escriba este cdigo:
Memo1.Lines.Insert(0,
FormatDateTime('yyyy-mm-dd hh:nn', Now) + ': ' + Edit1.Text);

122

Para el evento OnClick del botn Guardar escriba:


Memo1.Lines.SaveToFile('news.txt');

En el evento OnClose del formulario principal escriba lo siguiente para se guarden las
noticias:
Memo1.Lines.SaveToFile('news.txt');

En el evento OnCreate del formulario principal escriba este cdigo para cargar los ttulos de
noticias que haban sido previamente guardados.
if FileExists('news.txt') then
Memo1.Lines.LoadFromFile('news.txt');

Aplicacin con un segundo formulario


En los ejemplos GUI anteriores , se ha utilizado solamente un formulario, pero en las aplicaciones
reales necesitaremos utilizar varios.
Para escribir una aplicacin GUI de mltiples formularios siga estos pasos:
1. Cree una nueva aplicacin y gurdela en una nueva carpeta como secondform.
2. Guarda la unidad principal como main.pas, y renombre el formulario principal como
fmMain. Guarde el proyecto como secondform.lpi.
3. Aada un nuevo formulario haciendo click en Archivo/Nuevo formulario (File / New Form)
Guarde esta unidad como second.pas y nombre su formulario como fmSecond.
4. Aadir una etiqueta (Tlabel) en el segundo formulario y escribir en su propiedad Caption
'Segundo formulario'. Aumente el tamao de la letra cambiando la propiedad Font.Size.
5. Regrese al formulario principal y coloque en el un botn
6. aada esta lnea de cdigo al apartado implementation:
uses second;

7. Ahora en el evento OnClick del botn escriba este cdigo:


fmSecond.Show;

Ya puede iniciar la aplicacin y hacer click en el botn para mostrar el segundo formulario.

123

Captulo 4
Programacin
Orientada a Objetos

124

Introduccin
En la Programacin Orientada a Objetos, describimos las entidades de una aplicacin como objetos.
Por ejemplo, podemos representar informacin de automviles como un objeto que contiene
nombre del modelo, ao del modelo, precio, y ese objeto tiene la capacidad de guardar estos datos
en un archivo.
El objeto contiene:
1. Propiedades que almacenan informacin de estado. Estos valores pueden ser guardados en
variables.
2. Procedimientos y funciones que son llamados Mtodos. Estos mtodos representan las
acciones que pueden ser realizadas en el objeto.
3. Eventos: Sucesos que pueden ser recibidos por el objeto, como el cursor de ratn
movindose sobre el objeto, un clic de ratn, etc.
4. Manejadores de eventos: Estos son los procedimientos que sern ejecutados si un evento
ocurre.
Las propiedades y mtodos que estn relacionados entre s pueden ser representados como un
objeto:

Objeto = Cdigo + Datos


Un ejemplo de Programacin Orientada a Objetos es la GUI (Interfaz de Usuario Grfica) que
hemos utilizado en el captulo anterior. En ese captulo empleamos una gran cantidad de objetos,
como botones, etiquetas y formularios. Cada objeto contiene propiedades como Caption, Width, y
tiene mtodos como Show, Hide, Close, etc. Tambin poseen eventos como OnClick, OnCreate,
OnClose, etc. El cdigo que es escrito por el programador para responder a eventos especficos,
como OnClick, representa manejadores de eventos.

Primer ejemplo: Fecha y Hora


Hemos escrito un objeto que contiene fecha y hora con acciones que trabajan sobre fecha y hora.
Hemos creado una nueva unidad de nombre DateTimeUnit, y hemos creado una clase dentro de sta
llamada TMyDateTime.
Class es el tipo de un objeto. Si necesitamos usar esa clase, debemos declarar una instancia de ella.
Esta instancia es llamada objeto. As como ya hicimos con tipos Integer y String (I, J, Address,
etc.), declaramos instancias de clases como variables a fin de utilizarlas.
Este es el cdigo de la unidad:
unit DateTimeUnit;
{$mode objfpc}{$H+}
interface

125

uses
Classes, SysUtils;
type
{ TMyDateTime }
TMyDateTime = class
private
fDateTime: TDateTime;
public
function GetDateTime: TDateTime;
procedure SetDateTime(ADateTime: TDateTime);
procedure AddDays(Days: Integer);
procedure AddHours(Hours: Single);
function GetDateTimeAsString: string;
function GetTimeAsString: string;
function GetDateAsString: string;
constructor Create(ADateTime: TDateTime);
destructor Destroy; override;
end;
implementation
{ TMyDateTime }
function TMyDateTime.GetDateTime: TDateTime;
begin
Result:= fDateTime;
end;
procedure TMyDateTime.SetDateTime(ADateTime: TDateTime);
begin
fDateTime:= ADateTime;
end;
procedure TMyDateTime.AddDays(Days: Integer);
begin
fDateTime:= fDateTime + Days;
end;
procedure TMyDateTime.AddHours(Hours: Single);
begin
fDateTime:= fDateTime + Hours / 24;
end;
function TMyDateTime.GetDateTimeAsString: string;
begin
Result:= DateTimeToStr(fDateTime);
end;
function TMyDateTime.GetTimeAsString: string;
begin
Result:= TimeToStr(fDateTime);
end;
function TMyDateTime.GetDateAsString: string;
begin
Result:= DateToStr(fDateTime);
end;

126

constructor TMyDateTime.Create(ADateTime: TDateTime);


begin
fDateTime:= ADateTime;
end;
destructor TMyDateTime.Destroy;
begin
inherited Destroy;
end;
end.

Hemos puesto cinco botones sobre el formulario principal, tal como se muestra:

Hemos escrito el siguiente cdigo en el evento OnClick de cada botn:


unit Main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, DateTimeUnit;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;

127

Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
MyDT: TMyDateTime;
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
MyDT := TMyDateTime.Create(Now);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(MyDT.GetDateTimeAsString);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage(MyDT.GetDateAsString);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage(MyDT.GetTimeAsString);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
MyDT.AddHours(1);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
MyDT.AddDays(1);
end;
initialization
{$I main.lrs}
end.

En este ejemplo, son de notar los siguientes puntos importantes:


128

Unidad DateTimeUnit.1. Se define TMyDateTime como class, que es la palabra reservada para definir nuevas classes.
2. Se introduce el mtodo Constructor: Create. Este es un procedimiento especial que es
usado para crear objetos en memoria e inicializarlos.
3. Se introduce el mtodo Destructor: Destroy. Este es un procedimiento especial que es
llamado para liberar la memoria del objeto despus de terminar de usarlo.
4. Hay dos secciones en esa clase: private, la cual contiene propiedades y mtodos que no
pueden ser accedidas desde fuera de la unidad de la clase. La otra seccin es public, la cual
contiene propiedades y mtodos que pueden ser accedidos desde fuera de la unidad. Si una
clase no contiene una seccin pblica, significa que no puede utilizarse en absoluto.
Unidad Main:
1. Hemos agregado DateTimeUnit en la clusula Uses del formulario principal para acceder a
su clase.
2. Hemos declarado el objeto MyDT dentro de la unidad: MyDT:
3.

TMyDateTime;

4. Hemos creado el objeto e inicializado este en el evento OnCreate del formulario principal.
5.
MyDT := TMyDateTime.Create(Now);

Esta es la manera de crear objetos en el lenguaje Object Pascal.

129

Aplicacin de noticias en Pascal Orientado a Objetos

En este ejemplo, nosotros deseamos reescribir la aplicacin de noticias usando mtodos orientados a
objetos. Tambin tenemos que clasificar las noticias en archivos separados.
Hemos creado una nueva aplicacin GUI y le dimos el nombre oonews.
El siguiente ejemplo es una nueva unidad que contiene la clase TNews, la cual tiene funcionalidad
para noticias.
unit news;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
TNewsRec = record
ATime: TDateTime;
Title: string[100];
end;
{ TNews }
TNews = class
private
F: file of TNewsRec;
fFileName: string;
public
constructor Create(FileName: string);
destructor Destroy; override;
procedure Add(ATitle: string);
procedure ReadAll(var NewsList: TStringList);
function Find(Keyword: string;
var ResultList: TStringList): Boolean;
end;
implementation
{ TNews }
constructor TNews.Create(FileName: string);
begin
fFileName:= FileName;
end;
destructor TNews.Destroy;
begin
inherited Destroy;
end;
procedure TNews.Add(ATitle: string);
var

130

Rec: TNewsRec;
begin
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
FileMode:= 2; // Read/write access
Reset(F);
Seek(F, FileSize(F));
end
else
Rewrite(F);
Rec.ATime:= Now;
Rec.Title:= ATitle;
Write(F, Rec);
CloseFile(F);
end;
procedure TNews.ReadAll(var NewsList: TStringList);
var
Rec: TNewsRec;
begin
NewsList.Clear;
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, Rec);
NewsList.Add(DateTimeToStr(Rec.ATime) + ' : ' + Rec.Title);
end;
CloseFile(F);
end;
end;
function TNews.Find(Keyword: string; var ResultList: TStringList): Boolean;
var
Rec: TNewsRec;
begin
ResultList.Clear;
Result:= False;
AssignFile(F, fFileName);
if FileExists(fFileName) then
begin
Reset(F);
while not Eof(F) do
begin
Read(F, Rec);
if Pos(LowerCase(Keyword), LowerCase(Rec.Title)) > 0 then
begin
ResultList.Add(DateTimeToStr(Rec.ATime) + ' : ' + Rec.Title);
Result:= True;
end;
end;
CloseFile(F);

131

end;
end;
end.

En el formulario principal, hemos agregado varios componentes: un cuadro de texto (Edit), un


cuadro combinado (ComboBox), tres botones, un cuadro de texto Memo y dos etiquetas (Label):

En la unidad principal, hemos escrito este cdigo:


unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics,
Dialogs, News, StdCtrls;
type
{ TForm1 }

132

TForm1 = class(TForm)
btAdd: TButton;
btShowAll: TButton;
btSearch: TButton;
cbType: TComboBox;
edTitle: TEdit;
Label1: TLabel;
Label2: TLabel;
Memo1: TMemo;
procedure btAddClick(Sender: TObject);
procedure btSearchClick(Sender: TObject);
procedure btShowAllClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
NewsObj: array of TNews;
{ public declarations }
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
SetLength(NewsObj, cbType.Items.Count);
for i:= 0 to High(NewsObj) do
NewsObj[i]:= TNews.Create(cbType.Items[i] + '.news');
end;
procedure TForm1.btAddClick(Sender: TObject);
begin
NewsObj[cbType.ItemIndex].Add(edTitle.Text);
end;
procedure TForm1.btSearchClick(Sender: TObject);
var
SearchStr: string;
ResultList: TStringList;
begin
ResultList:= TStringList.Create;
if InputQuery('Search News', 'Please input keyword', SearchStr) then
if NewsObj[cbType.ItemIndex].Find(SearchStr, ResultList) then
begin
Memo1.Lines.Clear;
Memo1.Lines.Add(cbType.Text + ' News');
Memo1.Lines.Add('--------------------------------------------------');
Memo1.Lines.Add(ResultList.Text);
end
else
Memo1.Lines.Text:= SearchStr + ' not found in ' +
cbType.Text + ' news';

133

ResultList.Free;
end;
procedure TForm1.btShowAllClick(Sender: TObject);
var
List: TStringList;
begin
List:= TStringList.Create;
NewsObj[cbType.ItemIndex].ReadAll(List);
Memo1.Lines.Clear;
Memo1.Lines.Add(cbType.Text + ' News');
Memo1.Lines.Add('-----------------------------------------------------------');
Memo1.Lines.Add(List.Text);
List.Free;
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
i: Integer;
begin
for i:= 0 to High(NewsObj) do
NewsObj[i].Free;
NewsObj:= nil;
end;
initialization
{$I main.lrs}
end.

Del ejemplo anterior, se destacan los siguientes puntos:


1. Hemos usado una matriz dinmica, la cual es una matriz que puede ser asignada, expandida,
reducida y desechada en tiempo de ejecucin de acuerdo con su uso. Nosotros declaramos una
matriz dinmica de objetos noticias:
NewsObj: array of TNews;

En tiempo de ejecucin y antes de hacer uso de ella, debemos inicializarla empleando el


procedimiento SetLength:
SetLength(NewsObj, 10);

Lo cual significa que prepare espacio para 10 elementos en esa matriz. Esto es similar a la
declaracin de una matriz normal:
NewsObj: array [0 .. 9] of TNews;

El tamao de una matriz normal permanecer constante durante el tiempo que una aplicacin est
corriendo, pero el tamao de una matriz dinmica puede ser aumentado y disminuido.

134

En este ejemplo, hemos inicializado la matriz de acuerdo a las categoras que existen en el cuadro
combinado.
SetLength(NewsObj, cbType.Items.Count);

Si nosotros agregamos ms categoras en ComboBox.Items (cbType.Items), el tamao de la matriz


dinmica aumentar en consecuencia.
2. El tipo TNews es una clase, y no podemos usarla directamente. Tenemos que declarar una
instancia de objeto de esa clase, como NewsObj.
3. Al final de la aplicacin, hemos liberado los objetos y entonces la matriz dinmica:
for i:= 0 to High(NewsObj) do
NewsObj[i].Free;
NewsObj:= nil;

135

Aplicacin Cola

Una cola es un ejemplo de tipo de estructura de datos. Esta es utilizada para insertar y guardar
elementos de forma secuencial y eliminarlos en el orden en el cual fueron insertados. Su regla se
llama primero en entrar, primero en salir.
En el siguiente ejemplo, hemos escrito una unidad llamada Queue (en ingls, cola), la cual contiene
la clase TQueue. La clase TQueue puede ser utilizada para guardar datos como nombres, y
obtenerlos de forma secuencial. Obtener datos de una cola elimina esos datos. Por ejemplo, si la
cola contiene 10 elementos, y nosotros obtenemos y leemos tres, siete elementos se quedarn en la
cola.
Unidad Queue:
unit queue;
// This unit contains TQueue class,
// which is suitable for any string queue
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
{ TQueue }
TQueue = class
private
fArray: array of string;
fTop: Integer;
public
constructor Create;
destructor Destroy; override;
function Put(AValue: string): Integer;
function Get(var AValue: string): Boolean;
function Count: Integer;
function ReOrganize: Boolean;
end;
implementation
{ TQueue }
constructor TQueue.Create;
begin
fTop:= 0;
end;
destructor TQueue.Destroy;
begin
SetLength(fArray, 0); // Erase queue array from memory
inherited Destroy;
end;

136

function TQueue.Put(AValue: string): Integer;


begin
if fTop >= 100 then
ReOrganize;
SetLength(fArray, Length(fArray) + 1);
fArray[High(fArray)]:= AValue;
Result:= High(fArray) - fTop;
end;
function TQueue.Get(var AValue: string): Boolean;
begin
AValue:= '';
if fTop <= High(fArray) then
begin
AValue:= fArray[fTop];
Inc(fTop);
Result:= True;
end
else // empty
begin
Result:= False;
// Erase array
SetLength(fArray, 0);
fTop:= 0;
end;
end;
function TQueue.Count: Integer;
begin
Result:= Length(fArray) - fTop;
end;
function TQueue.ReOrganize: Boolean;
var
i: Integer;
PCount: Integer;
begin
if fTop > 0 then
begin
PCount:= Count;
for i:= fTop to High(fArray) do
fArray[i - fTop]:= fArray[i];
// Truncate unused data
SetLength(fArray, PCount);
fTop:= 0;
Result:= True; // Re Organize is done
end
else
Result:= False; // nothing done
end;
end.

137

El formulario principal para la aplicacin Cola:

El cdigo de la unidad principal:


unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics,
Dialogs, Queue, StdCtrls;
type
{ TfmMain }
TfmMain = class(TForm)
bbAdd: TButton;
bbCount: TButton;
bbGet: TButton;
edCustomer: TEdit;
Label1: TLabel;
Memo1: TMemo;
procedure bbAddClick(Sender: TObject);
procedure bbCountClick(Sender: TObject);
procedure bbGetClick(Sender: TObject);
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
MyQueue: TQueue;
{ public declarations }

138

end;
var
fmMain: TfmMain;
implementation
{ TfmMain }
procedure TfmMain.FormCreate(Sender: TObject);
begin
MyQueue:= TQueue.Create;
end;
procedure TfmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
MyQueue.Free;
end;
procedure TfmMain.bbCountClick(Sender: TObject);
begin
Memo1.Lines.Add('Queue length is: ' + IntToStr(MyQueue.Count));
end;
procedure TfmMain.bbAddClick(Sender: TObject);
var
APosition: Integer;
begin
APosition:= MyQueue.Put(edCustomer.Text);
Memo1.Lines.Add(edCustomer.Text + ' has been added as # ' +
IntToStr(APosition + 1));
end;
procedure TfmMain.bbGetClick(Sender: TObject);
var
ACustomer: string;
begin
if MyQueue.Get(ACustomer) then
begin
Memo1.Lines.Add('Got: ' + ACustomer + ' from the queue');
end
else
Memo1.Lines.Add('Queue is empty');
end;
initialization
{$I main.lrs}
end.

En la clase TQueue, hemos empleado el mtodo Put para insertar un nuevo elemento expandiendo
la matriz dinmica fArray, y poner el nuevo elemento en la nueva ltima posicin de la matriz.
Cuando se llama al mtodo Get para quitar el elemento que est al inicio de la cola, el apuntador
fTop se mueve al siguiente elemento de la cola.

139

Sacar elementos del comienzo de la matriz dinmica, causar que se mueva el apuntador fTop, pero
las casillas de la matriz dinmica permanecern en memoria y seguirn ocupando espacio, ya que
slo podemos eliminar esas casillas desde el fondo (extremo final) de la matriz dinmica. Por esta
razn, si el nmero de elementos extrados alcanza 100, ser llamado el mtodo ReOrganize para
mover los elementos al inicio de la matriz dinmica y suprimir el espacio que ya no usa.
Este es el cdigo que mueve los elementos de la cola al comienzo de la matriz dinmica:
for i:= fTop to High(fArray) do
fArray[i - fTop]:= fArray[i];

Y este es el cdigo para cortar la matriz dinmica de la parte inferior (extremo final).
// Truncate unused data
SetLength(fArray, PCount);
fTop:= 0;

En este ejemplo, hemos encontrado que la programacin orientada a objetos introduce informacin
oculta. Es negado el acceso a datos sensibles, como ciertos campos ("variables") de la clase. En su
lugar, podemos usar mtodos especficos que no provocarn un comportamiento raro en el objeto.
Los datos y mtodos sensibles son colocados en la seccin privada de la declaracin de la clase:
private
fArray: array of string;
fTop: Integer;

Los programadores que usen esta clase no podrn acceder directamente a estos campos. Si fueran
capaces de acceder a ellos, entonces podran corromper la cola modificando fTop o fArray por
accidente. Por ejemplo, suponga que fTop ha sido cambiado a 1000 cuando la cola contiene slo 10
elementos; eso provocara un error de violacin de acceso en tiempo de ejecucin.
Como alternativa al uso directo de campos de la clase, hemos implementado los mtodos Put y Get
para agregar y remover elementos de la matriz de forma segura. Este mecanismo es como usar
puertas para controlar los elementos interiores. Se trata de una caracterstica de la POO llamada
encapsulamiento.

Archivo orientado a objetos


En el primer captulo, usamos diferentes tipos de archivos y los manipulamos usando programacin
estructurada (procedimientos y funciones). Esta vez accederemos a los archivos utilizando un
objeto archivo.
Una de las clases archivo de Pascal Orientado a Objetos es TFileStream, el cual contiene mtodos y
propiedades para manipular archivos.
Trabajar as hace las cosas ms estndares y predecibles para los programadores. Por ejemplo, para
abrir e inicializar un archivo, usaremos el constructor Create, como con cualquier otro objeto en
Pascal, pero en la manera estructurada la inicializacin es hecha por los procedimientos AssignFile,
140

Rewrite, Reset y Append.

Copiar archivos usando TFileStream


En este ejemplo, copiaremos archivos usando el tipo TFileStream.
Para hacer esto, cree una nueva aplicacin y ponga los siguientes componentes en el formulario
principal: TButton, TOpenDialog, TSaveDialog.
Para el evento OnClick del botn, escriba este cdigo:
procedure TfmMain.Button1Click(Sender: TObject);
var
SourceF, DestF: TFileStream;
Buf: array [0 .. 1023] of Byte;
NumRead: Integer;
begin
if OpenDialog1.Execute and SaveDialog1.Execute then
begin
SourceF:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
DestF:= TFileStream.Create(SaveDialog1.FileName, fmCreate);
while SourceF.Position < SourceF.Size do
begin
NumRead:= SourceF.Read(Buf, SizeOf(Buf));
DestF.Write(Buf, NumRead);
end;
SourceF.Free;
DestF.Free;
ShowMessage('Copy finished');
end;
end;

Este mecanismo es muy similar a usar archivos sin tipo, excepto que se emplea un archivo
orientado a objetos.
Tambin podemos usar una forma ms simple de copiar archivos:
procedure TfmMain.Button1Click(Sender: TObject);
var
SourceF, DestF: TFileStream;
begin
if OpenDialog1.Execute and SaveDialog1.Execute then
begin
SourceF:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
DestF:= TFileStream.Create(SaveDialog1.FileName, fmCreate);
DestF.CopyFrom(SourceF, SourceF.Size);
SourceF.Free;
DestF.Free;
ShowMessage('Copy finished');
end;
end;

141

El mtodo CopyForm copia el contenido total del archivo al archivo destino porque dimos a ste el
tamao del archivo origen: SourceF.Size.

Herencia
La herencia en Programacin Orientada a Objetos significa crear una nueva clase a partir de una
existente, heredando sus mtodos y propiedades. Despus de heredar propiedades y mtodos
existentes, podemos agregar nuevos mtodos y propiedades a la nueva clase.
Como ejemplo de herencia, deseamos crear una nueva clase cola Integer a partir de nuestra vieja
clase cola String. En vez de escribir la cola Integer a partir de cero, podemos heredar de la cola
String.
Para heredar de la cola String, aada una nueva unidad y ponga la unidad de la cola String en su
clusula Uses. Entonces declare la nueva cola Integer as:
TIntQueue = class(TQueue)

El nombre de la nueva unidad es IntQueue, y hemos introducido dos nuevos mtodos: PutInt y
GetInt.
El cdigo completo de la unidad que contiene la case TIntQueue es:
unit IntQueue;
// This unit contains TIntQueue class, which is inherits TQueue
// class and adds PutInt, GetInt methods to be used with
// Integer queue
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Queue;
type
{ TIntQueue }
TIntQueue = class(TQueue)
public
function PutInt(AValue: Integer): Integer;
function GetInt(var AValue: Integer): Boolean;
end;
implementation
{ TIntQueue }
function TIntQueue.PutInt(AValue: Integer): Integer;
begin
Result:= Put(IntToStr(AValue));
end;

142

function TIntQueue.GetInt(var AValue: Integer): Boolean;


var
StrValue: string;
begin
Result:= Get(StrValue);
if Result then
AValue:= StrToInt(StrValue);
end;
end.

Vea que no escribimos nuevos mtodos Create, Destroy y Count, dado que estos ya existen en la
clase padre TQueue.
Para usar la nueva clase cola Integer, hemos creado una nueva aplicacin y agregado estos
componentes:

El cdigo de la unidad es:


unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics,
Dialogs, IntQueue, StdCtrls;
type
{ TfmMain }
TfmMain = class(TForm)

143

bbAdd: TButton;
bbCount: TButton;
bbGet: TButton;
edCustomerID: TEdit;
Label1: TLabel;
Memo1: TMemo;
procedure bbAddClick(Sender: TObject);
procedure bbCountClick(Sender: TObject);
procedure bbGetClick(Sender: TObject);
procedure FormClose(Sender: TObject;
var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
MyQueue: TIntQueue;
{ public declarations }
end;
var
fmMain: TfmMain;
implementation
{ TfmMain }
procedure TfmMain.FormCreate(Sender: TObject);
begin
MyQueue:= TIntQueue.Create;
end;
procedure TfmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
MyQueue.Free;
end;
procedure TfmMain.bbCountClick(Sender: TObject);
begin
Memo1.Lines.Add('Queue length is: ' + IntToStr(MyQueue.Count));
end;
procedure TfmMain.bbAddClick(Sender: TObject);
var
APosition: Integer;
begin
APosition:= MyQueue.PutInt(StrToInt(edCustomerID.Text));
Memo1.Lines.Add(edCustomerID.Text + ' has been added as # '
+ IntToStr(APosition + 1));
end;
procedure TfmMain.bbGetClick(Sender: TObject);
var
ACustomerID: Integer;
begin
if MyQueue.GetInt(ACustomerID) then
begin
Memo1.Lines.Add('Got: Customer ID : ' + IntToStr(ACustomerID) +
' from the queue');
end

144

else
Memo1.Lines.Add('Queue is empty');
end;
initialization
{$I main.lrs}
end.

Observe que hemos utilizado las propiedades y mtodos de TQueue adems de las propiedades y
mtodos de TIntQueue.
En este caso, llamamos a la clase original TQueue la clase base o ancestro, y llamamos a la nueva
clase descendiente.
En lugar de crear una nueva clase, podramos modificar la unidad de la cola String y agregarle
PutInt y GetInt para manejar enteros, pero hemos creado la nueva clase TIntQueue para ilustrar la
herencia. Hay tambin otra razn: Suponga que no tenemos el cdigo fuente original de TQueue,
sino solamente el archivo de unidad compilada (.ppu en Lazarus or .dcu en Delphi). En un caso as
no podramos ver el cdigo fuente, y desde luego no podramos modificarlo. La herencia sera la
nica manera de agregar ms funcionalidad a esta cola.

El fin

Code.sd

145

You might also like