Você está na página 1de 302

Delphi 5 bsico

Lic. Jack Daz Iglesias.


Lic. Franklin Prez Gonzlez.

Introduccin................................................... 9
1.1. Introduccin ........................................... 10
1.2. Consideraciones previas .................................. 10
1.2.1. Versiones de Delphi 5 .............................. 10
1.2.2. Requerimientos de Delphi 5 ......................... 11
1.3. Instalacin de Delphi 5 .................................. 11
2. El entorno................................................. 15
2.1. Introduccin ............................................ 15
2.2. Elementos iniciales ...................................... 15
2.2.1. Ventana principal .................................. 15
2.2.2. La Paleta de componentes ........................... 17
2.2.3. El formulario ...................................... 19
2.2.4. El Inspector de objetos ............................ 19
2.2.5. El men principal .................................. 20
2.3. El Depsito de objetos ................................... 20
2.4. Obtener ayuda ........................................... 21
2.5. Creacin de la interfaz de un programa .................... 21
2.5.1. La ventana del programa ............................ 22
2.5.2. La rejilla de puntos ............................... 23
2.5.3. Insercin de componentes ........................... 24
2.5.4. Manipulacin de los componentes .................... 25
2.5.5. Modificacin de propiedades ........................ 26
2.5.6. Uso de los eventos ................................. 27
2.5.7. Edicin de cdigo .................................. 28
2.5.8. Ejecucin de un programa ........................... 31
3. Proyectos.................................................. 32
3.1. Introduccin ............................................ 32
3.2. Gestin del proyecto ..................................... 32
3.2.1. El proyecto por defecto ............................ 32
3.2.2. Uso del Gestor de proyectos ........................ 33
3.2.3. Proyectos predefinidos ............................. 35
3.3. El archivo de proyecto ................................... 36
3.4. Archivos de formulario ................................... 37
3.5. Mdulos de cdigo ........................................ 38
3.6. Grupos de proyectos ...................................... 38
3.7. Otros elementos de un proyecto ............................ 39
4. Fundamentos de Object Pascal............................... 40
4.1. Introduccin ............................................ 40
4.2. Estructura general ....................................... 40
4.2.1. El punto y el punto y coma ......................... 41
4.2.2. Mdulos y la clusula Uses ......................... 41
4.3.2. Tipos .............................................. 42
4.3.3. Declaracin de variables ........................... 44
4.3.4. Matrices ........................................... 44
4.3.5. Definir nuevos tipos ............................... 46
4.3.6. Constantes y literales ............................. 51

4.4. mbito de los identificadores ............................. 53

4.4.1. Identificadores locales ............................


4.4.2. Identificadores globales ...........................
4.4.3. Problemas de accesibilidad .........................
4.5. Expresiones .............................................
4.5.1. Operadores aritmticos .............................
4.5.2. Operadores relacinales ............................
4.5.3. Operadores lgicos ...................................
4.5.4. Otros operadores ...................................
4.5.5. Orden de prioridad .................................
4.6. Estructuras de control ...................................
4.6.1. Condicionales ......................................
4.6.2. Bucles .............................................
4.7. Procedimientos y funciones ...............................
4.7.1. Definicin .........................................
4.7.2. Parmetros de entrada ..............................
4.7.3. Parmetros de salida ...............................
5. Fundamentos de la Programacin Orientada a Objeto 5.1
Introduccin..................................................
5.2 Tipos de datos abstractos. ..............................
5.3 Clases. .................................................
5.4 Objetos .................................................
5.5 Mensajes ................................................
5.6 Relaciones ..............................................
5.7 Herencia ................................................
5.8 Asignacin dinmica de memoria. .........................
5.8 Polimorfismo ............................................
6. Manipulacin de componentes................................
6.1. Introduccin ............................................
6.3. Instalacin de un componente ..............................
6.4. Propiedades .............................................
6.4.1. Acceso a los miembros de un objeto .................
6.4.2. Posicin y dimensiones del componente ..............
6.4.3. Ttulos, colores y tipos de letra ..................
6.4.4. Estado visual y de acceso ..........................
6.4.5. Orden de acceso a los controles ....................
6.4.6. Contenedores y contenidos acoplables ...............
6.5. Eventos .................................................
6.5.1. El evento OnClick ..................................
6.5.2. Eventos de ratn ...................................
6.5.3. Eventos de teclado .................................
6.5.4. Otros eventos ......................................
6.6. Mtodos .................................................
7. Componentes ms habituales.................................
7.1. Introduccin ............................................
7.2.Trabajar con el formulario ..............................
7.2.1. Aspectos visuales del formulario ...................

53
54
55
56
56
57
58
59
63
64
64
67
69
69
71
73
74
74
76
76
77
77
78
80
81
84
84
84
85
86
87
88
89
90
91
91
92
92
93
93
94
95
95
95
95

7.2.2. Eventos de un formulario ........................... 99


7.2.3. Mtodos de un formulario .......................... 101
7.2.4. En la prctica .................................... 101
7.3. Botones ................................................ 103
7.3.1. Tecla de acceso rpido ............................ 104
7.3.2. El evento de pulsacin ............................ 104
7.3.3. Botn por defecto y de cancelacin ................ 104
7.3.4. En la prctica .................................... 105
7.4. Etiquetas de texto ...................................... 107
7.4.1. Tamao del control ................................ 107
7.4.2. Alineacin del texto .............................. 108
7.4.3. Otras propiedades de TLabel ....................... 108
7.4.4. En la prctica .................................... 109
7.5. Peticin de datos ....................................... 110
7.5.1. Longitud del texto ................................ 110
7.5.2. Seleccin de texto ................................ 110
7.5.3. Texto de slo lectura y oculto .................... 111
7.5.4. Otras propiedades de TEdit ........................ 112
7.5.5. Control de la entrada ............................. 112
7.5.6. En la prctica .................................... 113
7.6. Entrada de texto ........................................ 114
7.6.1. Barras de desplazamiento .......................... 115
7.6.2. Trabajando con lneas de texto .................... 116
7.6.3. Otras propiedades de TMemo ........................ 116
7.6.4. En la prctica .................................... 117
7.7. Seleccin de opciones ................................... 119
7.7.1. En la prctica .................................... 120
7.8. Seleccin de opciones exclusivas ......................... 121
7.8.1. En la prctica .................................... 122
7.9. Grupos de opciones exclusivas ............................ 123
7.9.1. Opciones existentes y opcin activa ............... 123
7.9.2. En la prctica .................................... 124
7.10. Listas de elementos .................................. 125
7.10.1. Contenido de la lista ............................ 125
7.10.2. Elementos seleccionados .......................... 126
7.10.3. Otras propiedades de TListBox .................... 127
7.10.4. En la prctica ................................... 127
7.11. Listas desplegables .................................. 130
7.11.1 En la prctica .................................... 130
7.12. Controles contenedores ............................... 132
7.12.1. Alineacin del contenedor ........................ 133
7.12.2. Elementos de realce .............................. 133
7.12.3. En la prctica ................................... 134
7.13. Barras de desplazamiento ............................. 136
7.13.1. Lmites y posicin de la barra ................... 136
7.13.2. Incrementos grandes y pequeos ................... 136
7.13.3. En la prctica ................................... 137

7.14. Elementos grficos ...................................


7.14.1. Figura a dibujar .................................
7.14.2. Brocha y lpiz ...................................
7.14.3. En la prctica ...................................
7.15. Imgenes de mapas de bits ............................
7.15.1. Mostrar imgenes contenidas en archivos ..........
7.15.2. La superficie de dibujo ..........................
7.15.3. En la prctica ...................................
7.16. Listas de unidades, carpetas y archivos ..............
7.16.1. Una lista de unidades ............................
7.16.2. Una lista de carpetas ............................
7.16.3. Una lista de archivos ............................
7.16.4. En la prctica ...................................
7.17. Eventos peridicos ...................................
7.17.1. En la prctica ...................................
7.18.1. Diseo de un men principal ......................
7.18.2. Construccin de un men emergente ................
7.18.3. En la prctica ...................................
8. Depuracin y excepciones..................................
8.1. Introduccin ..........................................
8.2. Proceso de depuracin .................................
8.2.1. Estado de ejecucin ...............................
8.2.2. Ejecucin paso a paso .............................
8.2.3. Puntos de parada ..................................
8.2.4. Inspeccin de valores y evaluacin de expresiones .
8.2.5. Pila de llamadas ..................................
8.3. Control de excepciones ..................................
8.3.1. La construccin Try/Except ........................
8.3.2. Clases de excepciones .............................
8.3.3. En la prctica ....................................
9. Uso de mltiples ventanas.................................
9.1. Introduccin ..........................................
9.2.Trabajo con mltiples formularios ......................
9.2.1. El formulario principal del programa ..............
9.2.2. Formularios creados automticamente y formularios
disponibles ..............................................
9.2.3. Visualizacin de un formulario ....................
9.2.4. MDI ...............................................
9.3. Cuadros de dilogo de uso comn .......................
9.3.1. Abrir y guardar archivos ..........................
9.3.2. Tipos y atributos de letra ........................
9.3.3. Seleccin de colores ..............................
9.3.4. Opciones de impresin y configuracin de impresora
9.3.5. Bsquedas y sustituciones .........................
9.4. En la prctica .........................................
9.4.1. Diseo del formulario principal ...................
9.4.2. Diseo del formulario hijo ........................

139
139
140
141
142
142
143
144
146
146
147
147
148
149
149
150
151
152
153
153
153
154
154
156
158
160
161
161
162
162
165
165
165
166
166
168
169
170
170
172
174
175
178
180
180
181

9.4.3. El cdigo del formulario principal ................


9.4.4. El cdigo del formulario hijo .....................
9.4.5. Probando el programa ..............................
10. Trabajo con base de datos................................
10.1. Introduccin ..........................................
10.2. Gestin de alias .......................................
10.2.1. Creacin de un nuevo alias .......................
10.2.2 Modificacin y eliminacin de alias ...............
10.3. Creacin de una tabla ..................................
10.3.1. Definicin de los campos de la tabla .............
10.3.2. Propiedades de la tabla ..........................
10.3.3. ndices ..........................................
10.3.4. Guardar la tabla .................................
10.4. Modificar la estructura de una tabla ....................
10.5. Editar el contenido de una tabla ........................
10.5.1. Edicin de datos .................................
10.5.2. Columnas no accesibles ...........................
10.6. Consultas ............................................
10.6.1. Construccin de una consulta QBE .................
10.6.2. Construccin de una consulta SQL .................
11. Componentes enlazados a datos............................
11.1. Introduccin .........................................
11.2. Edicin de una tabla .................................
11.2.1. Establecer un enlace con la tabla ................
11.2.2. El editor de campos de TTable ....................
11.2.3. Insercin de los controles de edicin ............
11.2.4. Navegacin por los datos .........................
11.3.Tablas y consultas ....................................
11.3.1. El componente TTabIe .............................
11.3.2. El componente TQuery .............................
11.3.3. El componente TDataSource ........................
11.4. Controles enlazados a datos ..........................
11.4.1.Mostrar y editar datos ............................
11.4.2. Datos lgicos y botones de radio .................
11.4.3. Textos extensos e imgenes .......................
11.4.4. Listas y listas combinadas .......................
11.4.5. Rejillas de datos ................................
11.4.6. Rejillas de controles ............................
11.5. Acceso programtico a los datos ......................
11.5.1. El objeto TField .................................
11.5.2. Mtodos de TTable ................................
12. Creacin de Informes.....................................
12.1. Introduccin .........................................
12.2. Funcionamiento general de QuickReport ................
12.3. El componente TQuickReport ...........................
12.3.1. Seleccin de los datos a imprimir ................
12.3.2. Formato del informe ..............................

182
186
188
188
188
189
191
191
192
192
193
195
196
197
198
199
200
200
200
201
203
203
203
203
204
205
205
206
206
207
208
208
209
209
210
210
211
212
214
215
217
221
221
221
222
223
223

12.3.3. Informacin durante la ejecucin .................


12.3.4. Visualizacin e impresin del informe ............
12.4. El componente TQRBand ................................
12.4.1. Aspecto de la seccin en el informe ..............
12.4.2. El componente TQRExpr ............................
12.4.3. El componente TQRSysData .........................
12.4.4. El componente TQRShape ...........................
12.4.5. Imgenes en el informe ...........................
12.4.6. Un ejemplo .......................................
13. Componentes avanzados....................................
13.1. Introduccin .........................................
13.2. Valores discretos y rangos ...........................
13.2.1. Marcas de posicin ...............................
13.2.2. Seleccin de rangos ..............................
13.2.3. En la prctica ...................................
13.3. Curso de un proceso ..................................
13.3.1. En la prctica ...................................
13.4. Incrementar y decrementar valores ....................
13.4.1. Otras propiedades de TUpDown .....................
13.4.2. En la prctica ...................................
13.5. Cabeceras redimensionables ...........................
13.5.1. Propiedades de un objeto THeaderSection ..........
13.5.2. Edicin de la propiedad Sections .................
13.5.3. Eventos de THeaderControl ........................
13.5.4. En la prctica ...................................
13.6. Barras de estado .....................................
13.6.1. El objeto TStatusPanel ...........................
13.6.2. Otras propiedades de TStatusBar ..................
13.6.3. Eventos de TStatusBar ............................
13.6.4. Edicin de la propiedad Panels ...................
13.6.5. En la prctica ...................................
13.7. Ventanas multipgina .................................
13.7.1. Gestin de las pginas en la etapa de diseo .....
13.7.2. Propiedades de TPageControl ......................
13.7.3. Propiedades de TTabSheet .........................
13.7.4. Gestin de las pginas durante la ejecucin ......
13.7.5. En la prctica. ..................................
13.8. Almacenes de imgenes ................................
13.8.1. Asignacin de imgenes durante el diseo .........
13.8.2. Asignacin de imgenes mediante cdigo ...........
13.8.3. Obtener imgenes de un TImageList ................
13.8.4. En la prctica ...................................
13.9. Listas jerrquicas ...................................
13.9.1. Definir elementos en la fase de diseo ...........
13.9.2. Definir elementos durante la ejecucin ...........
13.9.3. Propiedades de TTreeView .........................
13.9.4. Propiedades de TTreeNode .........................

223
224
226
227
228
228
228
229
229
233
233
233
234
235
235
237
238
240
240
241
241
241
242
242
243
246
246
247
247
248
248
248
249
249
250
250
251
251
251
252
253
253
253
254
254
254
255

13.9.5. Mtodos de TTreeView ............................. 256


13.9.6. Mtodos de TTreeNode ............................. 257
13.9.7. En la prctica ................................... 258
13.10. El control TListView ................................ 265
13.10.1. Propiedades de TListView ........................ 265
13.10.2. Propiedades de TListItem ........................ 266
13.10.3. Mtodos de TListView ............................ 267
13.10.4. Mtodos de TListItem ............................ 267
13.10.5. Definicin de columnas .......................... 267
13.10.6. En la prctica .................................. 268
13.11. Texto con formato ................................... 271
13.11.1. Atributos por defecto y de seleccin ............ 272
13.11.2. Atributos de prrafo ............................ 272
13.11.3. Mtodos de TRichEdit ............................ 273
13.11.4. En la prctica .................................. 273
13.12. Barras de botones ................................... 275
13.12.1. Insercin de botones ............................ 275
13.12.2. Propiedades de TToolBar ......................... 276
13.12.3. Propiedades de TToolButton ...................... 277
13.12.4. Uso de una barra de botones ..................... 277
14.1. Introduccin ......................................... 278
14.2. Listas de acciones ................................... 278
14.2.1. El componente TActionList ........................ 278
14.2.2. Propiedades del objeto TAction ................... 279
14.2.3. La propiedad Action .............................. 280
14.2.4. Uso de una lista de acciones ..................... 280
14.3. Componentes compuestos ............................... 282
14.3.1. Creacin de un nuevo marco ....................... 283
14.3.2. Reutilizar el marco en el mismo proyecto ......... 284
14.3.3. Reutilizar el marco en otros proyectos ........... 285
14.3.4. Un ejemplo ....................................... 285
15. Creacin de componentes.................................. 287
15.1 Introduccin ........................................... 287
15.2. Niveles de acceso a los componentes ..................... 287
15.3 Creando un componente. ................................ 287
15.4 Creando un componente visual. ......................... 290
15.5 Creando un componente no visual. ...................... 291
15.6 Creando un bitmap para el componente. ................. 292
15.7 Instalando componentes creados. ....................... 293
15.8 Introduccin a los editores de propiedades. ........... 293
15.9 Responsabilidades de un editor de propiedades. ........ 294
15.10 Pasos necesarios para escribir un editor de propiedades.
........................................................... 294
15.11 Un editor de propiedades para nmeros binarios. ...... 295
15.12 Registro de un editor de propiedades. ................ 298
15.13 Ubicacin de un editor de propiedades. ............... 300

Introduccin
Todo comenz con el oscuro y difcil mundo del lenguaje de mquina y
luego el ensamblador. Por entonces la programacin de las computadoras
era privativa
de especialistas y cientficos. Era tan complicado
programar y tan difcil acceder a una computadora que solo unos pocos
podan hacerlo. Un programa que resolviese un problema medianamente
complejo requera de la escritura de muchas lneas de cdigo lo que
haca que fuese difcil no solo crearlo sino tambin el mantenerlo y
mejorarlo. Como suele suceder, la evolucin, no se detuvo y se fueron
mejorando los lenguajes, aparecieron los llamados entornos de
desarrollo integrado que incluyen editor, compilador o interprete y
debugger. Ya hoy contamos con los llamados entornos visuales de
programacin que se clasifican dentro de la cuarta generacin y que
permiten al programador una mayor concentracin en la resolucin de
los problemas que se le plantean y una menor perdida de tiempo en el
diseo de las interfaces para el acceso de los usuarios y la escritura
de cientos de lneas de cdigo. Estos nuevos entornos de programacin
le permiten a los programadores crear aplicaciones utilizando tcnicas
como la de arrastrar y soltar, aadiendo iconos que representan
objetos, modificando sus propiedades y escribiendo algo de cdigo. La
posibilidad de reusar componentes realizados previamente as como la
de usar los fabricados por otros son una expresin de los niveles de
reusabilidad que redundan en un acortamiento del ciclo de desarrollo.
Delphi califica como uno de estos nuevos lenguajes visuales y sin
dudas lo hace muy bien permitiendo el desarrollo rpido de
aplicaciones de alta complejidad con una interface grfica funcional y
de un calidad grfica importante. Disponible inicialmente para las
plataformas Windows y recientemente, con el proyecto Kylix, tambin
para las del tipo Linux. Basado en un compilador de indudable calidad
es ahora posible desarrollar aplicaciones multiplataforma pues el
cdigo, siempre que no utilice funciones especficas de la API de
windows, puede ser compilado y ejecutado bajo plataforma linux. La
versin 5.0 que es en la que se basa este libro nos permite crear
aplicaciones
para
Internet
e
Intranets,
servicios
locales
y
distribuidos, y acceso a una amplia gama de Bases de Datos personales
o del tipo Cliente/Servidor. En fin si usted decide crear aplicaciones
de calidad que no simplemente funcionen sino que saquen partido a su
sistema operativo, Delphi 5.0 es la herramienta adecuada y en este
libro podr encontrar los fundamentos necesarios para ponerse en
marcha.

1. Instalacin
1.1. Introduccin
El formato de distribucin en el que se encuentra Delphi 5 es el CD,
soporte que permite almacenar, por ejemplo, los ms de 400 megabytes
que ocupa la versin Enterprise, en la cual se incluye Delphi 5,
Interbase Server, InstalIShield, TeamSource, los archivos imagen que
permiten ejecutar todo ello desde el propio CD y mltiples archivos
con informacin diversa. La ocupacin real en nuestro disco no ser
tan elevada, ya que no tenemos por qu instalar todas las opciones;
podemos dejar las partes que nos interesen en el CD, sin instalarlas
en nuestro sistema.

1.2. Consideraciones previas


Antes de proceder a describir el proceso de instalacin de Delphi 5,
no est de ms que conozcamos las versiones existentes de este
producto, as como los requerimientos que habr de cumplir nuestro
sistema.

1.2.1. Versiones de Delphi 5


Delphi es un producto nico, basado en un entorno de desarrollo visual
y un lenguaje orientado a objetos. Sin embargo existen tres ediciones
distintas, que cuentan con elementos que difieren entre ellas.
La versin ms bsica, denominada Standard, incluye los elementos
comunes a las tres versiones. Se compone del entorno de desarrollo
visual Delphi 5, el Borland Database Engine de 32 bits y todos los
componentes Delphi necesarios para la creacin de programas en Windows
95/98 y NT/2000 y el diseo de informes.
El nivel intermedio de Delphi lo ocupa la versin Profesional, que
adems de contar con los elementos ya mencionados tambin incorpora el
servidor local de Interbase, el cdigo fuente de los componentes
Delphi, algunos controles ActiveX de ejemplo y algunos componentes
adicionales para el trabajo con bases de datos y creacin de
aplicaciones Internet.
A la versin superior de Delphi 5 se le conoce como Enterprise y,
adems de incorporar todo lo descrito en los dos puntos anteriores,
tambin se acompaa de una licencia de InterBase Server, un
controlador de versiones de cdigo fuente, controladores SQL para
Oracle, Sybase, Informix, etc., y las herramientas SQL Explorer y SQL
Monitor. Tambin permite la creacin de servidores Web y aplicaciones
distribuidas usando DCOM, CORBA, etc. Como puede ver, esta versin
est especialmente enfocada al desarrollo de aplicaciones para trabajo

en entornos cliente/servidor, facilitando incluso un servidor de bases


de datos para Windows, lo cual nos puede facilitar mucho el trabajo.

1.2.2. Requerimientos de Delphi 5


Como se ha comentado anteriormente, el contenido del CD en el que se
distribuye Delphi 5 ocupa un volumen considerable de espacio, pero es
cierto tambin que algunos elementos no tienen por qu ser copiados a
nuestro sistema, como los manuales, que pueden visualizarse desde el
propio CD, o el cdigo fuente de la VCL y los ejemplos.
La ocupacin en disco oscilar entre los 80 megabytes, para una
instalacin tpica de la versin Standard, y los alrededor de 200 para
una instalacin de la versin Enterprise.
La instalacin mnima que copiara al disco tan solo lo necesario,
dejando el resto de archivos en el CD, tiene el inconveniente de que
cada vez que necesitemos una de las herramientas no instaladas, el CD
deber encontrarse en la unidad.
Tambin
tenemos
la
posibilidad
de
realizar
una
instalacin
personalizada, seleccionando los elementos a copiar a nuestro disco y
controlando la ocupacin final.
Los requerimientos de memoria de Delphi 5 son los propios de una
herramienta de este tipo, siendo el mnimo de 32 megabytes. Este
mnimo, sin embargo, es poco realista, ya que con esa cantidad de
memoria los accesos a disco durante procesos como la compilacin sern
continuos y el funcionamiento de Delphi resultar algo lento. En la
prctica 64 megabytes de memoria es una configuracin adecuada para
el correcto funcionamiento de Delphi 5.
El software necesario ser Windows 95/98 o NT 4.0/2000. Si usamos NT
4.0, deberemos tener instalado los ltimos Serviec Pack.

1.3. Instalacin de Delphi 5


Conociendo ya los aspectos bsicos tratados en los puntos anteriores,
vamos a iniciar la instalacin de Delphi 5 en nuestro sistema. Para
ello bastar con insertar el CD-ROM en nuestro lector, lo que causar
la autoejecucin del programa de instalacin. En caso de que tenga
desactivada esta caracterstica de Windows, tendr que ejecutar el
programa INSTALL que se encuentra en el directorio raz del CD, lo que
puede hacer cmodamente desde el Explorador de Windows o bien pulsando
sobre el icono "Mi PC" y abriendo la carpeta correspondiente al lector
de CD-ROM.
Dependiendo de la versin que estemos instalando aparecer una ventana
con ms o menos opciones. En la figura 1.1 puede ver el aspecto que
muestra la ventana de instalacin de la versin Enterprise.

Pulse el botn correspondiente a la instalacin de Delphi. Tras unos


instantes, que se emplearn en la preparacin de la informacin
necesaria para llevar a cabo la instalacin, ver aparecer una
pantalla de bienvenida en la que se aconseja que no existan otras
aplicaciones
ejecutndose
mientras
se
realiza
el
proceso
de
instalacin, invitndonos a cerrar las que estn abiertas en ese
momento.
Tras pulsar el botn Next, tendr que introducir el nmero de serie y
la clave de activacin del producto, datos que encontrar en la propia
caja del CD. Una nueva pulsacin del botn Next y se visualizar el
acuerdo de licencia del producto, que habr que aceptar pulsando el
botn Yes. A continuacin aparecer el archivo con notas informativas
de ltima hora. Tras leerlo pulse de nuevo el botn Next, lo que le
llevar a la ventana que se muestra en la figura 1.2, en la que podr
elegir entre una instalacin tpica, completa o a medida.

Figura 1.1. Ventana inicial del programa de instalacin


La primera opcin, instalacin tpica, copiar en nuestro sistema
todos los archivos que necesita Delphi y las herramientas ms
habituales que le acompaan para funcionar de una forma independiente,
sin necesidad de disponer del CD. La instalacin compacta copiar en
nuestro disco lo mnimo para poder funcionar. Por ltimo tenemos la
instalacin a medida, que nos permite seleccionar los elementos a
instalar. Al seleccionar este tipo de instalacin aparecer una
ventana con unos apartados principales.
Seleccionando uno de estos apartados y pulsando el botn Change,
accederemos a una segunda ventana en la que individualmente podremos
indicar qu partes se instalarn. En la figura 1.3 puede ver cmo se
ha abierto la ventana de componentes Program Files," habindose
seleccionado para instalacin los archivos de programa principales, el
editor de imgenes, etc., dejando en el CD los programas de ejemplo.

Figura 1.2. Seleccin del tipo de instalacin

Figura 1.3. Seleccin de los elementos a instalar


Independientemente del mtodo de instalacin que se haya elegido, en
la siguiente ventana que aparece, tras pulsar una vez ms el botn
Next, indicaremos si queremos o no instalar el cliente InterBase, que
nos servir para hacer pruebas locales de desarrollo con bases de
datos InterBase. Previamente, si la versin que se instala es la
Enterprise, deberemos elegir los controladores SQL que deseamos
instalar.
A continuacin podremos seleccionar el camino de destino de la
instalacin.
Mediante
el
botn
Browse
podemos
especificar
un
directorio raz a partir del cual se crear uno para cada elemento a
instalar.
El ltimo paso en el que intervendremos en la configuracin de la
instalacin ser en la seleccin del nombre de grupo o carpeta. En

esta carpeta encontraremos un icono para iniciar Delphi 5, como es


lgico, y otros adicionales para acceder a archivos de ayuda y
herramientas que acompaan a Delphi.
Una pulsacin ms del botn Next nos llevar a una ventana en la que
podremos ver una lista con todas las opciones de configuracin,
teniendo opcin a volver hacia atrs y realizar modificaciones,
pulsando el botn Back, o bien a iniciar el proceso de instalacin,
mediante el botn Install. Dicho proceso consistir en la copia de
todos los archivos seleccionados al camino de destino, as como la
creacin de los apartados necesarios en el archivo de registro de
Windows, modificacin de algunos parmetros de configuracin y
creacin de la carpeta.
La duracin del trabajo de instalacin depender principalmente de la
velocidad de nuestro lector de CD-ROM, as como de la cantidad de
elementos que se hayan seleccionado. En cualquier caso, y tal como se
muestra en la figura 1.4, el Programa de instalacin nos ira indicando
en todo momento el curso del proceso.
Cuando la instalacin haya llegado a su fin, ver aparecer en pantalla
una ventana en la que se indica que es necesario reiniciar el
ordenador. Hgalo antes de intentar ejecutar Delphi, ya que de lo
contrario no todos los componentes estarn adecuadamente configurados.
En la figura 1.5 puede ver el aspecto del men de Delphi 5 una vez
terminada la instalacin y reiniciado el sistema. Ya puede ejecutar
Delphi, simplemente eligiendo la opcin apropiada.

Figura 1.4. Proceso de copia de archivos al camino de destino

Figura 1.5. Men correspondiente a Delphi 5


2. El entorno
2.1. Introduccin
El primer paso que tendremos que dar, para poder trabajar con Delphi
5, ser familiarizarnos con su entorno. En este entorno existen
mltiples ventanas, conteniendo opciones, botones, propiedades, etc.
Estas ventanas pueden ser redimensionadas, cerradas y cambiadas de
posicin como cualquier otra ventana Windows.
En este captulo vamos a adquirir las nociones necesarias para poder
trabajar en el entorno de Delphi 5. Para ello haremos un recorrido por
los elementos ms importantes, aprenderemos a insertar componentes en
un formulario, etc.
2.2. Elementos iniciales
Al ejecutar Delphi, en pantalla inicialmente siempre aparecen los
mismos elementos. Son precisamente los que utilizaremos con mayor
frecuencia aunque, como veremos posteriormente, en el entorno pueden
existir varias ventanas ms.
En la figura 2.1 puede ver el aspecto tpico de Delphi cuando es
cargado. Observe los nombres con los que se denomina a los apartados,
cuya funcin vamos a comentar seguidamente, ya que esos nombres son
los que se utilizan a lo largo de esta gua para hacer referencia a
ellos.
2.2.1. Ventana principal
En la parte superior de la pantalla, y habitualmente ocupando todo el
ancho disponible, podemos ver una ventana que contiene el nombre del
proyecto sobre el que se est trabajando, los botones de accin
rpida, la Paleta de componentes y el men principal. A esta ventana
la denominamos ventana principal, ya que ella contiene la mayora de
los elementos que necesitaremos para trabajar con Delphi. Si
minimizamos la ventana principal, las dems del entorno tambin
desaparecern y si la cerramos estaremos saliendo de Delphi.

Los botones de accin rpida, como su propio nombre indica, nos


permiten realizar determinadas operaciones de forma rpida, sin
necesidad .de tener que acceder al men o pulsar una combinacin de
teclas. Pulsando sobre los iconos que muestran estos botones podremos
guardar el proyecto actual, ejecutar el programa o aadir un nuevo
elemento al proyecto, por poner algunos ejemplos.
La finalidad de cada uno de los botones puede deducirse del icono que
utiliza, aunque bastar con situar el puntero del cursor sobre l para

obtener una pequea descripcin. Observe que algunos de los botones


disponen de una flecha que indica la existencia de una lista
desplegable de opciones.

Figura 2.1. Elementos iniciales en el entorno de Delphi

Personalizacin de los botones


El rea de botones de acciones rpidas est pensada para ahorrarnos
trabajo, por eso encontramos en ella botones que nos dan acceso a las
acciones ms habituales. A pesar de esto, nosotros podemos configurar
totalmente esta rea, eliminando y aadiendo botones, as como
modificando la disposicin.
Como
podr
apreciar,
los
botones
estn
agrupados
segn
su
funcionalidad. Existen varios que permiten iniciar un nuevo proyecto,
recuperar un proyecto existente, guardar el actual y aadir y eliminar
elementos del proyecto. Un segundo grupo de botones permiten ver un

formulario, un mdulo de cdigo, etc. Si pulsa el botn derecho sobre


el rea de botones, con el fin de desplegar el men emergente, ver
que existen varias opciones que permiten mostrar/ocultar esas paletas
de botones de forma individual.
Observe que tanto el men de opciones como la Paleta de componentes, y
los distintos grupos de botones de accin rpida, tienen a su
izquierda una doble lnea vertical, elemento que indica que esos
elementos estn contenidos en un rea que podemos fcilmente desplazar
a donde nos interese dndole las dimensiones que deseemos.
Todas las paletas de componentes son configurables, de tal forma que
podemos tanto aadir nuevos botones como eliminar los existentes o
cambiarlos de sitio. Para poder realizar esta tarea hay que abrir de
nuevo el men emergente y elegir la ltima opcin, llamada Customize,
que da paso a una ventana con varias pginas. La primera de ellas
facilita la seleccin de las paletas de botones que estarn activas;
la segunda, con el ttulo Commands, contiene todos los comandos
posibles agrupados por funcin. Es posible tomar cualquier comando de
la lista de la derecha y arrastrarlo hasta la paleta de botones que
nos interese para aadirlo, de tal forma que est disponible
directamente. De forma similar, podemos arrastrar un botn existente
en una paleta fuera de ella, eliminndolo. En la figura 2.2 puede ver
la ventana de personalizacin, as como las paletas de componentes
dispuestas en la parte superior de la ventana principal y con algunos
botones ms que se han aadido segn el procedimiento indicado.

Figura 2.2. Ventana de configuracin de los botones de acciones


rpidas
2.2.2. La Paleta de componentes
A la derecha del rea de botones, aunque podemos colocarla en
cualquier otro punto de la ventana principal, encontraremos la Paleta
de componentes. Esta paleta est compuesta por mltiples pginas, a

las que accederemos mediante las pestaas que hay en la parte


superior. Cada una de las pginas contiene componentes, que son los
elementos bsicos con los que construiremos nuestros programas.
En un captulo posterior tendremos ocasin de conocer la finalidad y
funcionamiento de los componentes Delphi ms habituales, con los que
podremos
construir
prcticamente
cualquier
programa.
Tambin
aprenderemos a usar algunos controles ms avanzados que permiten
mejorar la interfaz, haciendo que est ms en consonancia con el
sistema operativo.
Al igual que ocurre con el rea de botones de acciones rpidas, la
Paleta de componentes tambin puede ser personalizada. Si sita el
puntero del ratn sobre la Paleta de componentes, no importa el punto,
y pulsa el botn derecho del ratn ver que se abre un men contextual
con una opcin llamada Properties. Seleccione esa opcin, consiguiendo
hacer aparecer la ventana que se muestra en la figura 2.3. La lista
existente en la parte izquierda contiene los nombres de las pginas
existentes, mientras que la lista de la derecha muestra los
componentes existentes en la pgina seleccionada en la izquierda. Los
botones situados en la parte inferior nos permiten alterar el orden de
las pginas o de los componentes en una pgina, as como modificar el
nombre, que podemos adaptar a nuestras preferencias, aadir y eliminar
componentes.

Figura 2.3. Personalizacin de la Paleta de componentes de Delphi

2.2.3. El formulario
La ventana que aparece aproximadamente en el centro de la pantalla,
segn se ha mostrado en la figura 2.1, y que tiene por ttulo Form1,
recibe el nombre de formulario. Una formulario es una ventana que en
una aplicacin Delphi acta como contenedor, en el cual se irn
insertando los componentes que sean necesarios para solicitar datos,
mostrar informacin o realizar cualquier otra tarea.
Durante la ejecucin, un formulario se comporta como cualquier otra
ventana Windows, es decir, se mostrar con un ttulo, unos botones que
le permiten maximizar, minimizar o cerrar la ventana y un rea de
trabajo o rea cliente en la que se encontrarn los controles con los
que interactuar el usuario del programa. En realidad, todos estos
elementos son configurables y, mediante las propiedades oportunas,
podremos alterar el ttulo de la ventana, la existencia o no de los
citados botones, etc.
Habitualmente en un proyecto Delphi existe ms de un formulario, dando
as
lugar
a
un
programa
que
utiliza
ms
de
una
ventana.
Posteriormente, en el captulo 8, aprenderemos a gestionar un proyecto
de estas caractersticas.
2.2.4. El Inspector de objetos
Con este nombre se conoce a la ventana que inicialmente aparece en la
parte izquierda de la pantalla, justo debajo de la ventana principal y
a la izquierda del formulario. En el Inspector de objetos encontramos
bsicamente tres elementos diferentes: la lista de componentes, en la
parte superior, la pgina de propiedades y la pgina de eventos.
La lista desplegable existente en la parte superior del Inspector de
objetos, la cual podremos abrir pulsando el botn que hay en el
extremo derecho, contiene el nombre de cada uno de los componentes que
existen en el formulario sobre el que estamos trabajando en ese
momento. Al seleccionar cualquiera de esos componentes se mostrara en
la parte superior no slo su nombre sino tambin su tipo. En la figura
2.1 puede ver que el componente seleccionado es Form1, cuyo tipo es
TForm1.
Los componentes Delphi son elementos genricos que han de servir para
cualquier aplicacin, por lo que han de ser flexibles en ciertos
aspectos, permitiendo su personalizacin. La pgina Properties del
Inspector de objetos muestra las propiedades del componente que
tengamos seleccionado, as como los valores que actualmente contienen
dichas propiedades. Alterando el valor de una propiedad podemos
modificar el ttulo del formulario, conseguir que no aparezcan los
botones de minimizar o maximizar, etc. La pgina Events es la que
contiene los nombres de los eventos soportados por el componente, as
como los nombres de los procedimientos que se ejecutarn al generarse

esos eventos. Mediante un evento podemos, por ejemplo, indicar la


accin que se ha de realizar cuando se pulse un botn.
2.2.5. El men principal
Aunque las acciones ms habituales que llevaremos a cabo mientras
trabajemos con Delphi estarn disponibles en el rea de botones de
acciones rpidas, o bien en un men contextual que podemos hacer
aparecer en cualquier momento pulsando el botn secundario del ratn,
existen otras muchas, usadas con menos frecuencia, que tendremos que
buscar en el men principal de Delphi, el cual ocupa la parte superior
de la ventana principal.
Est claro que las opciones del men de Delphi las iremos conociendo a
medida que las usemos, por lo que no tiene mucho sentido la
descripcin pormenorizada de cada una de ellas. Al desplegar un men
observe que muchas de las opciones tienen un icono a su izquierda y,
en ocasiones, una combinacin de teclas a su derecha. Estos elementos
nos indican el icono que tiene el botn que podemos pulsar para
conseguir el mismo efecto, sin necesidad de abrir el men, o la
combinacin de teclas que hay que pulsar con la misma finalidad.
Dedique un tiempo a recorrer las opciones del men y ver las funciones
existentes, las ventanas a las que puede acceder, etc. En ste y
posteriores captulos iremos conociendo algunas de estas opciones
segn lo precisemos.
2.3. El Depsito de objetos
Al pulsar el botn New, que es el primero de la paleta de botones
estndar, o seleccionar la opcin del mismo nombre del men File
accederemos al Depsito de objetos, cuya ventana puede ver en la
figura 2.4. La primera pgina de esta ventana contiene varios iconos
que nos permiten la creacin de una nueva aplicacin, un nuevo
formulario, un nuevo componente, una librera de enlace dinmico, etc.
Las dems pginas del Depsito de objetos contienen formularios,
proyectos, cuadros de dilogo y mdulos de datos prefabricados que
nosotros podemos usar en nuestras aplicaciones. Si queremos, por
ejemplo, aadir a nuestro programa una ventana "Acerca de...", en
lugar de insertar un formulario vaco y crearlo desde cero podemos
abrir la pgina Forms del depsito de objetos y seleccionar el
elemento "About box", de tal forma que a nuestra aplicacin se aada
un formulario en el que tan slo tendremos que personalizar algunas
propiedades.

Figura 2.4. La ventana del Depsito de objetos


Al igual que ocurre con otros elementos del entorno de Delphi, tambin
el Depsito de objetos es totalmente configurable, siendo posible
aadir nuevas pginas, modificar las existentes, almacenar en l
nuestros propios formularios o prototipos de proyectos, etc. Como en
casos anteriores, para acceder a la ventana de propiedades de!
Depsito de objetos abra el men contextual, pulsando el botn derecho
del ratn, y seleccione la opcin Properties.
2.4. Obtener ayuda
El ltimo men existente en la ventana principal de Delphi, llamado
Help, cuenta con una serie de opciones que nos permiten acceder a
diferentes apartados de la ayuda. La primera de ellas da paso a la
ayuda general de Delphi, mientras que la segunda abre la ayuda de las
diferentes herramientas que acompaan a Delphi y la tercera a la ayuda
de la API de Windows. Las tres opciones del segundo grupo son enlaces
directos a pginas Web de Borland. La ltima opcin muestra la tpica
ventana de informacin acerca de la aplicacin, en este caso indicando
la versin^del Delphi que estamos usando. En la figura 2.5 puede ver
esta ventana.
2.5. Creacin de la interfaz de un programa
La creacin de una aplicacin con Delphi se inicia, generalmente, con
el diseo de su interfaz, para lo cual ser necesario manipular el
formulario o los formularios con que cuenta el proyecto, insertando y
manipulando componentes, propiedades y eventos, as como escribiendo
el cdigo que sea necesario. A continuacin vamos a hacer un breve

recorrido sobre los pasos que generalmente seguiremos para construir


un programa, desde la configuracin del formulario hasta la ejecucin
del programa.

Figura 2.5. Ventana con informacin acerca de la versin de Delphi


2.5.1. La ventana del programa
Toda aplicacin Windows de tipo estndar, que son la mayora, cuenta
con una ventana, un espacio de pantalla delimitado mediante un borde,
en la cual se visualiza o solicita informacin. En caso de que la
aplicacin cuente con varias ventanas siempre existir una que sea la
inicial o ventana principal, desde la cual se acceder a las dems.
Una ventana Windows cuenta con un borde, un fondo, un ttulo, unos
botones y un men de sistema. Todos estos elementos no tienen por qu
existir siempre, nos podemos encontrar con una ventana que tiene men
de sistema pero no botones de maximizar y minimizar.
En un programa Windows desarrollado con Delphi las ventanas de la
aplicacin son los formularios, cuyas caractersticas estableceremos
mientras estamos construyendo el programa, es decir, durante el
diseo. La ventana principal ser el formulario que hayamos creado en
primer lugar, aunque como veremos despus ste es un apartado
configurable.
El aspecto de un formulario, durante el diseo, no tiene por qu ser
precisamente el aspecto que tendr la ventana del programa cuando ste
se ejecute y, de hecho, en la mayora de las ocasiones no lo ser. Por
ejemplo, durante el diseo se muestra en el interior del formulario

una matriz o rejilla de puntos, cuya finalidad es facilitar la


alineacin de los componentes en su interior. Hasta matriz de puntos
no ser visible durante la ejecucin, ya que en ese momento el
programa ya est terminado y no tiene sentido la funcin para la cual
est pensada dicha matriz.
Inicialmente las dimensiones de la ventana, durante la ejecucin,
sern las mismas que nosotros hayamos dado al formulario durante el
diseo, aunque este aspecto tambin depende del valor que asignemos a
ciertas propiedades. Podemos modificar las dimensiones que por defecto
tiene el formulario simplemente situando el puntero del ratn en uno
de sus extremos y arrastrndolo. De igual forma, tambin podemos
modificar la posicin del formulario en pantalla, estableciendo la
posicin en la que por defecto aparecer la ventana al ejecutar el
programa.
Aunque durante el diseo en el formulario siempre existirn, en el
extremo derecho, los botones de maximizado, minimizado y cierre, ello
no implica que durante la ejecucin estos botones aparezcan tambin,
ya que es posible desactivarlos o hacerlos desaparecer, simplemente
alterando el valor de la propiedad adecuada.
2.5.2. La rejilla de puntos
Durante el diseo, el fondo del formulario cuenta por defecto con una
rejilla de puntos cuya finalidad es, como se ha comentado antes,
facilitar la alineacin de mltiples componentes, de tal forma que
stos queden ajustados segn nos interese. Al insertar un componente
el formulario, tarea que vamos a tratar en el apartado siguiente, as
como al desplazarlo de un punto a otro o al modificar sus dimensiones,
los puntos de la rejilla sern por defecto la medida de incremento o
decremento mnima.
Tanto la distancia entre los puntos de la rejilla como el hecho de que
todos los ajustes tengan como lmite uno de esos puntos son aspectos
configurables. Si selecciona la opcin Environment Options del men
Tools, acceder a la ventana que se muestra en la figura 2.6, en cuya
primera pgina existe un recuadro con las opciones que afectan a la
rejilla. Desactivando la opcin Display grid, que est activada por
defecto, conseguiremos hacer desaparecer la rejilla de puntos del
formulario, que aparecer durante el diseo prcticamente con el mismo
aspecto que tendr en ejecucin. En caso de que optemos por mantener
la rejilla de puntos, que es lo habitual, los apartados Grid size X y
Grid size Y nos permiten establecer la distancia, horizontal y
vertical, respectivamente, entre dos puntos consecutivos. Por ltimo,
con la opcin Snap to grid podemos indicar si deseamos que al mover un
componente, o modificar sus dimensiones, dicha distancia sea la unidad
mnima de trabajo.

Figura 2.6. Ventana de preferencias con opciones de la rejilla de


puntos.
2.5.3. Insercin de componentes
Una parte muy importante del desarrollo de una aplicacin con Delphi
consiste en insertar el formulario los componentes apropiados,
situndolos
adecuadamente
y
estableciendo
las
propiedades
que
correspondan. Todos estos pasos, completamente visuales, se ven
completados con la escritura de cdigo que se asociar a eventos.
Para insertar un componente en el formulario, lo primero que tendremos
que hacer ser seleccionarlo en la Paleta de componentes, para lo cual
antes deberemos activar la pgina en la que se encuentre dicho
componente. La seleccin del componente se efecta simplemente
pulsando sobre el icono que lo representa, con el botn principal del
ratn, tras lo cual bastara con desplazar el puntero del ratn al
lugar aproximado del formulario en que se desea insertar, pulsando de
nuevo el mismo botn. El nuevo componente se ajustar al punto ms
cercano, en caso de que est activada la opcin correspondiente de la
rejilla de puntos, y tomar unas dimensiones por defecto.
El tamao de un componente puede ser modificado en el mismo momento en
que se inserta en el formulario, para lo cual, una vez seleccionado en
la Paleta de componentes, habr que desplazarse hasta el punto del
formulario en que se desee realizar la insercin, pulsando el botn
principal del ratn y mantenindolo pulsado al tiempo que nos

desplazamos a un punto opuesto, estableciendo las dimensiones


deseadas. Al liberar el botn, veremos aparecer el componente con el
tamao que hayamos fijado.
En ocasiones es necesario insertar en un mismo formulario mltiples
componentes del mismo tipo, por ejemplo varios botones. En lugar de
repetir el proceso anterior, seleccionando el componente, insertndolo
y volvindolo a seleccionar una y otra vez, podemos dejarlo
seleccionado de forma fija. Para ello tendremos que pulsar la tecla
<Mays> antes de seleccionar el componente, tras lo cual no tendremos
mas que desplazar el puntero hasta el formulario insertando tantos
componentes como necesitemos, simplemente pulsando el botn principal
del ratn cada vez. Para eliminar la seleccin del componente, y poder
as trabajar con los componentes que se han insertado, deberemos
pulsar sobre el icono que representa al puntero del ratn, que aparece
en el extremo izquierdo de la Paleta de componentes.
2.5.4. Manipulacin de los componentes
El trabajo con un componente no termina con la insercin en el
formulario, en muchos casos es necesario moverlo a otro punto,
modificar su tamao o realizar otras tareas que determinarn el
comportamiento del componente durante la ejecucin.
Para manipular un componente lo primero que debemos hacer es
seleccionarlo, situando el puntero del ratn sobre l y pulsando el
botn principal. Un componente seleccionado se diferencia de los dems
en que tiene un borde alrededor, con varios cuadraditos.
El cambio de posicin de un componente es muy simple, una vez que est
seleccionado basta con arrastrarlo a la nueva posicin, sin ms. Para
modificar su tamao deberemos mover el puntero hasta uno de los
cuadraditos que hay en el borde, arrastrando ste en la direccin que
nos interese. En lugar del ratn tambin podemos usar el teclado para
conseguir las mismas acciones. La combinacin <Control+Flecha> nos
permitir desplazar punto a punto el componente seleccionado en la
direccin que nos interese, mientras que con <Mayus+Flecha> podemos
incrementar
o
decrementar
su
altura
y
anchura.
Pulsando
<Control+Mays+Flecha> podremos desplazar el componente no punto a
punto, sino utilizando el incremento que se haya fijado en la rejilla.
Aunque lo habitual es manipular un solo componente cada vez, Delphi
tambin nos permite seleccionar mltiples componentes de forma
simultnea, de tal forma que podemos desplazarlos conjuntamente, as
como
modificar
propiedades
comunes.
Para
seleccionar
varios
componentes podemos usar dos mtodos diferentes: mantener pulsada la
tecla <Mays> mientras con el botn principal del ratn vamos
marcndolos, o bien trazar con el puntero del ratn, manteniendo el
botn izquierdo pulsado, un recuadro que contenga total o parcialmente
los componentes a seleccionar. Terminada la operacin, podr ver qu

componentes son los que han resultado seleccionados fcilmente, ya que


cada uno de ellos tendr un recuadro a su alrededor.
Cada vez que se inserta un nuevo componente ste toma unas propiedades
por defecto, como pueden ser las dimensiones, ttulo, etc. En caso de
que nos interese insertar en un formulario un componente con las
mismas propiedades de otro ya existente, en lugar de usar el mtodo
descrito en el punto anterior podemos realizar una operacin de copiar
y pegar. Para ello seleccionaremos el componente original y pulsaremos
<Control+C>, copindolo al portapapeles. A continuacin pulsaremos
sobre el fondo del formulario o el contenedor deseado y pegaremos el
componente, mediante la combinacin <Control+V>.
Adems de las tareas descritas hasta ahora, un componente tambin
puede ser eliminado del formulario. Tras seleccionar el componente, lo
nico que habremos de hacer ser pulsar la tecla <Supr> y el
componente desaparecer.
Una vez que todos los componentes de un formulario se encuentran en la
posicin deseada y con las dimensiones necesarias, para evitar una
modificacin accidental podemos utilizar la opcin Lock Controls del
men Edil, que los bloquear de tal forma que no sea posible modificar
posicin o tamao ni con el ratn ni con el teclado, aunque s ser
posible hacerlo editando las propiedades correspondientes.
2.5.5. Modificacin de propiedades
Tras la insercin de un componente en un formulario, la tarea ms
habitual suele ser el establecimiento de propiedades, mediante las
cuales se definen diferentes, caractersticas que, de una forma u
otra, afectarn al aspecto del componente a su funcionamiento.
Ciertas
propiedades
se
modifican
de
forma
indirecta,
cuando
manipulamos un control en un formulario, alterando, por ejemplo, su
posicin. Sin embargo, la mayor parte de las propiedades habr que
editarlas directamente sirvindonos para ello del Inspector de
objetos, ventana que describamos brevemente al principio de este
captulo.
Cada vez que en el formulario se selecciona un componente,
automticamente el Inspector de objetos muestra su nombre, en la parte
superior, y sus propiedades y eventos, en las dos pginas con que
cuenta. Cada pgina est dividida en dos columnas, conteniendo la de
la izquierda el nombre de la propiedad o evento, un parmetro que no
podemos modificar. La columna de la derecha es la que mantiene el
valor de la propiedad o bien el nombre del mtodo asedado al evento.
El ancho de cada una de las columnas puede ser modificado, situando el
puntero del ratn en la lnea central que las separa y arrastrndola
segn nos interese.
Tambin podemos seleccionar un determinado componente desplegando la
lista que hay en la parte superior del Inspector de objetos, en la que

aparecern los nombres de todos los componentes, existentes en el


formulario sobre el que estamos trabajando.
Tipos de propiedades
Al modificar el valor de una propiedad, en el Inspector de objetos nos
podemos encontrar con varias opciones diferentes, segn las cuales
podremos editar directamente dicho valor, seleccionar en una lista
desplegable o bien usar una ventana especfica para la edicin de esa
propiedad. Tambin nos encontraremos con propiedades que son conjuntos
u objetos, que cuentan a su vez con otras propiedades.
En Pascal existe un tipo de dato, al que se denomina conjunto, que se
caracteriza por poder contener varios valores de un conjunto
predeterminado. Las propiedades que son de este tipo aparecen en el
Inspector de objetos con un signo + a la izquierda del nombre,
indicando as que es posible desplegar la propiedad para acceder a las
subpropiedades. Esta misma tcnica tambin se usa para permitir la
modificacin de las propiedades correspondientes a una propiedad que
representa un objeto. La propiedad Bordericons del formulario es un
conjunto y la propiedad HorzScrollBar es un objeto. Compruebe cmo
puede desplegar estas propiedades, haciendo doble clic sobre el
nombre, y a continuacin modificar las subpropiedades.
Ciertas propiedades pueden ser editadas en el Inspector de objetos de
diversas formas. La propiedad Color, por ejemplo, puede ser modificada
introduciendo directamente el nombre del nuevo color, usando el
teclado, o bien desplegando la lista adjunta, seleccionado el color
deseado, o bien haciendo doble clic sobre el valor, provocando la
apertura de una ventana en la que visualmente podremos elegir el
color.
Otra propiedad similar es Font, que representa a un objeto. Podemos
modificar esta propiedad utilizando un editor especfico o bien
desplegando una serie de subpropiedades.
2.5.6. Uso de los eventos
El cdigo de un programa Windows no se ejecuta de forma secuencial,
sino que lo hace segn los mensajes que recibe del propio sistema.
Estos mensajes se generan, por ejemplo, al pulsar un botn, introducir
un carcter o desplazar el puntero del ratn. En Delphi estos mensajes
son gestionados automticamente por cada componente y traducidos en
eventos.
Nosotros podemos asociar un mtodo a un evento, de tal forma que
cuando dicho evento se produzca se ejecute el cdigo de ese mtodo.
No todos los mensajes de Windows tienen un evento equivalente en los
componentes Delphi, pero en la mayora de los casos, o en los ms

habituales, siempre encontraremos


finalidad que necesitemos.

un

evento

apropiado

para

la

Pulsando sobre la pestaa Events del Inspector de objetos podremos


abrir la pgina de eventos, en la que veremos los nombres de los
eventos con los que cuenta el componente que tengamos seleccionado en
ese momento en el formulario. A la derecha de cada uno de los eventos
puede existir el nombre de un mtodo, que ser el que se ejecute en el
momento en que se genere el evento. Haciendo doble clic sobre la
columna derecha de un evento abriremos automticamente la ventana de
cdigo situando el cursor en el mtodo adecuado. En caso de que dicho
evento no contase hasta ese momento con un mtodo asociado, Delphi
automticamente crear el cuerpo de un nuevo mtodo e introducir su
nombre en el Inspector de objetos, a la derecha del nombre del evento.
Mltiples eventos pueden compartir un mismo mtodo, siempre y cuando
los eventos sean del mismo tipo. El tipo de un evento determina,
bsicamente, los parmetros que el mtodo recibir cuando sea llamado.
El evento OnClick, por ejemplo, recibe un solo parmetro, mientras que
el evento OnMouseMove recibe cuatro. Estos eventos no podran, por
tanto, compartir un mismo mtodo.
2.5.7. Edicin de cdigo
En un programa Delphi la interfaz se crea de una forma visual, tal y
como estamos viendo en los ltimos puntos de este captulo. Sin
embargo, siempre existirn acciones que necesiten la escritura de algo
de cdigo para poder realizarse.
Imagine, por ejemplo, que usted quiere escribir un programa que
muestre una ventana con un botn, de tal forma que al pulsarse ste
aparezca un mensaje con un saludo. La parte visual consistira en
insertar el botn en el formulario, establecer el ttulo, su posicin
y dimensiones, color, etc. Al pulsarse el botn, momento en el cual se
generara un evento, se debera ejecutar un mtodo en el que
previamente nosotros habramos escrito el cdigo necesario para
mostrar el citado mensaje.
La mayor parte del cdigo de un programa Delphi estar siempre
asociado a algn evento, al que accederemos mediante la pgina de
eventos del Inspector de objetos o bien haciendo doble clic sobre el
componente. En cualquier caso, Delphi se encargar de establecer el
nombre de los mtodos, determinar los parmetros necesarios y sus
tipos, de tal forma que nosotros tan slo deberemos introducir las
sentencias que deseemos ejecutar, sin preocupamos por cmo se
transferir el control a dicho cdigo, apartado del que se ocupar
adecuadamente el componente afectado.
A pesar de lo dicho, y tal y como veremos en un captulo posterior, en
Delphi tambin puede existir cdigo que no est directamente ligado a
un determinado evento de un componente. Podemos, por ejemplo, escribir

cdigo para definir un nuevo objeto o crear un


procedimiento que despus ser usado desde el programa.

determinado

El cdigo de un programa Delphi se estructura en lo que denominan


mdulos, que son archivos de texto conteniendo cdigo. Cada uno de los
formularios de un proyecto tiene asociado un mdulo, pudiendo adems
existir mdulos independientes que nosotros aadamos para definir
funciones, procedimientos u objetos.
La edicin de cdigo en Delphi se realiza en la ventana de Editor de
cdigo, una ventana que normalmente permanece bajo el formulario en la
que se est trabajando. Podemos alternar entre el formulario y el
correspondiente mdulo de cdigo simplemente pulsando la tecla <F12>.
El Editor de cdigo de Delphi es un editor multi-archivo, lo que
quiere decir que es capaz de mantener abiertos mltiples mdulos de
cdigo de forma simultnea. En la parte superior de la ventana, como
puede ver en la figura 2.8, existir una pestaa por cada mdulo
abierto, lo que nos permitir cambiar de forma rpida y simple entre
el cdigo de los distintos archivos. Tambin disponemos de dos
botones, en la parte superior derecha de la ventana, que facilitan la
navegacin adelante y atrs por los ltimos puntos en los que hemos
estado, de forma similar a los botones de una navegador Web. Por
defecto a la izquierda del Editor de cdigo se muestra el Explorador
de cdigo.

Figura 2.8. Ventana del editor de cdigo de Delphi

Para trabajar con el Editor de cdigo de Delphi utilizaremos las


mismas combinaciones de tecla que estamos acostumbrados a usar en
otras aplicaciones, aunque podemos seleccionar uno de entre varios
modos de funcionamiento diversos. Este editor tiene la caracterstica
de diferenciar en el cdigo, usando colores y estilos, los diferentes
elementos de cada sentencia, como pueden ser palabras reservadas,
variables o comentarios. Todas estas caractersticas y algunas ms,
podremos personalizarlas mediante la ventana de opciones del editor, a
la que podremos acceder desplegando el men emergente, pulsando el
botn derecho del ratn sobre la ventana del editor, y seleccionando
la opcin Properties. En la ventana, que cuenta con cuatro pginas,
podremos configurar desde los colores de cada parte del cdigo hasta
el aspecto del cursor, pasando por los puntos de los fabuladores o la
columna en la que se mostrar el margen derecho.
El Explorador de cdigo es una lista jerrquica en la que se muestran
las clases, variables y, en general, todos los elementos existentes en
el mdulo de cdigo seleccionado. Podemos hacer doble clic sobre
cualquier elemento para ir directamente a l, sin necesidad de buscar
secuencialmente por el cdigo.
Podramos decir que el Explorador de cdigo nos ofrece una imagen "a
vista de pjaro" del mdulo de cdigo.
Ventanas acoplables
Al acceder al Editor de cdigo hemos visto que existe otra ventana, el
Explorador de cdigo, acoplada a su izquierda. La ventana acoplada
tiene, en este caso en su parte superior, una doble lnea y un botn
de cierre. Tomando la ventana por esa doble lnea y arrastrndola
podemos "sacar" la ventana de tal forma que sea una ventana
independiente ms. Tambin podemos realizar la operacin contraria,
acoplando una ventana que inicialmente era independiente. Puede
intentar, por ejemplo, acoplar el Inspector de objetos simplemente
tomando la ventana por su barra de ttulo y movindola hasta la
posicin deseada de la ventana a la que va a acoplarse. En la figura
2.9 puede ver cmo se han acoplado el Explorador de cdigo, el Editor
de cdigo, el Gestor de proyectos y el Inspector de objetos. Podemos
maximizar este conjunto de ventanas como si fuesen un todo.

Figura 2.9. Varias ventanas acopladas


La configuracin actual del escritorio, disposicin y tamao de las
diferentes ventanas, puede guardarse pulsando el botn Save current
desktop, que se encuentra en la parte superior de la ventana
principal, a la derecha de una lista desplegable. Al pulsar dicho
botn deber introducir un nombre para la configuracin. Puede guardar
varias
configuraciones
diferentes,
seleccionando
de
la
lista
desplegable la que ms le interese en cada momento. Esto le ahorrar
tener que colocar las ventanas cada vez que trabaje en un nuevo
proyecto.
2.5.8. Ejecucin de un programa
El fin ltimo de todo el proceso que se est describiendo, desde la
insercin del componente hasta la escritura del cdigo, es conseguir
un programa que sea posible compilar y ejecutar. Podemos realizar este
proceso, ejecutando el programa desde el propio entorno de Delphi,
simplemente pulsando la tecla <F9>.
En caso de que el proceso de compilacin se detenga por haber
encontrado algn error en el cdigo, el Editor de cdigo mostrar en
la parte inferior una lista con los errores encontrados, lista que
podremos usar para desplazamos a las diferentes lneas que contienen
esos errores.

Suponiendo que no exista error alguno el programa se compilar y ser


ejecutado. En el momento en que ste termine, lo que conseguiremos
generalmente cerrando la ventana principal, el control volver
automticamente a Delphi.
Habitualmente el proceso de ejecucin de un programa desde el propio
entorno de Delphi se repite una y otra vez, con el fin de ir viendo si
el funcionamiento del programa es correcto y se ajusta a lo que
nosotros deseamos conseguir. A pesar de ello no debe preocupamos, ya
que la compilacin del cdigo por parte de Delphi es muy rpida.
3. Proyectos
3.1. Introduccin
Toda aplicacin desarrollada con Delphi parte de un proyecto, nombre
con el que se denomina al conjunto de formularios, mdulos de cdigo y
cualquier otro elemento que forme parte del programa. El proyecto que
se abre por defecto, al iniciarse Delphi o seleccionar la opcin New
Application, tan slo cuenta con un formulario y el mdulo de cdigo
asociado. A este proyecto mnimo nosotros podemos ir aadiendo otros
elementos, como veremos en los puntos siguientes.
Cada proyecto Delphi se compone de mltiples archivos, en los cuales
se almacena informacin de cada formulario, el cdigo de cada mdulo,
los recursos y la propia definicin del proyecto. En los puntos
siguientes conoceremos la mayora de estos tipos de archivo.
3.2. Gestin del proyecto
Adems de saber cmo trabajar con un formulario o cmo modificar las
propiedades de un componente, temas que se trataron en el captulo
anterior, es tambin de vital importancia que sepamos cmo gestionar
el proyecto que deseamos crear. Comenzaremos por ver cmo se crea un
nuevo proyecto y cmo podemos establecer un proyecto por defecto, para
a continuacin tratar el funcionamiento del Gestor de proyectos de
Delphi y conocer los diferentes proyectos predefinidos que podemos
encontrar en el Depsito de objetos.
3.2.1. El proyecto por defecto
Cada vez que iniciamos un nuevo proyecto, al arrancar Delphi o
utilizar la opcin New Application del men File, abrimos el proyecto
por defecto, que puede ser tan simple como el que hay establecido
inicialmente, con un solo formulario, o tan complejo como una
aplicacin completa enteramente desarrollada, ya que nosotros podemos
indicar cul deber ser el proyecto que se utilice por defecto.
Seleccionando la opcin Repository del men Tools accederemos a una
ventana de personalizacin del Depsito de objetos. Eligiendo en la
lista de la izquierda el elemento denominado Projects, en la lista de

la derecha se mostrarn las plantillas de proyectos que existen


actualmente en el depsito, cualquiera de las cuales puede ser
establecida como proyecto por defecto. En la figura 3.1 puede ver cmo
se ha seleccionado la plantilla Win95/98 Logo Application como
proyecto por defecto, de tal forma que cada vez que se inicie un nuevo
proyecto aparezcan los elementos caractersticos de una aplicacin
para Windows 95/98.
Aunque, inicialmente, en el Depsito de objetos tan slo existen los
proyectos que se pueden ver en la figura 3.1, nosotros podemos aadir
cualquier otro proyecto. Suponga, por ejemplo, que todas las
aplicaciones que usted va a desarrollar van a contar con un formulario
y elementos comunes, como pueden ser las opciones del men o algunos
componentes. Tras preparar una plantilla del proyecto con todos esos
elementos comunes, habiendo partido de un proyecto en blanco, no
tendremos ms que seleccionar la opcin Add To Repository del men
Project, indicando en la ventana que se muestra el ttulo del
proyecto, la descripcin, la pgina del Depsito de objetos en la que
deseamos que aparezca, el nombre del autor y opcionalmente un icono.

Figura 3.1. Seleccin de un proyecto por defecto

3.2.2. Uso del Gestor de proyectos


Independientemente de cules sean los elementos existentes en el
proyecto por defecto, una vez que ste ha sido creado nosotros podemos
manipularlo, aadiendo o eliminando formularios o mdulos de cdigo.

Para ello haremos uso de algunas opdones, como New Form o Add To
Project y, adems, utilizaremos el Gestor de proyectos de Delphi.
Para hacer aparecer la ventana del Gestor de proyectos, que se muestra
en la figura 3.2, deberemos utilizar la opcin Project Manager del
men View, a no ser que en el rea de botones de acciones rpidas
exista un botn que nos permita realizar esa misma funcin. La ventana
mostrada consta, bsicamente, de una lista jerrquica en la que se
enumeran los proyectos existentes y los elementos de cada uno de
ellos. En la parte superior tenemos unos botones que nos permitirn
aadir nuevos proyectos, eliminar cualquiera de los existentes o
activar el seleccionado en ese momento. Tambin puede seleccionarse un
proyecto directamente, desde la lista desplegable que hay a la
izquierda de los botones.
En la barra de estado, situada en la parte inferior, podemos ver el
nombre del archivo en que est contenido el elemento seleccionado,
incluyendo el camino completo en el que se encuentra en disco. Por
cada una de los elementos se indica el nombre del mdulo de cdigo, el
nombre del formulario, en caso de que dicho mdulo est asociado a
una, y por ltimo el camino en que se encuentra el elemento.
Pulsando el primer botn existente en la parte superior podremos
aadir un nuevo proyecto al grupo actual. Esto nos permite trabajar
simultneamente con varios proyectos, lo cual es muy til cuando
existen dependencias entre ellos. Si abrimos el men emergente
correspondiente a un proyecto, pulsando el botn derecho del ratn
tras haber situado correctamente el puntero, encontraremos una primera
opcin, Add, que nos permite aadir cualquier mdulo o formulario ya
existente en disco, simplemente facilitando el camino y nombre. La
accin contraria, eliminar un elemento del proyecto, la podemos
efectuar seleccionando en la lista el elemento que deseamos borrar y
seleccionando la opcin Remove from project de su men emergente.

Figura 3.2. La ventana del Gestor de proyectos de Delphi


Para abrir un determinado formulario o mdulo de cdigo, basta con
hacer doble clic sobre el elemento correspondiente en el Gestor de
proyectos. Como ya sabemos, podemos alternar entre un formulario y su
correspondiente mdulo de cdigo con tan slo pulsar la tecla <F12>.
Opciones de proyecto
Mediante la opcin Options, disponible en el men emergente de cada
proyecto, podremos acceder a la ventana de opciones de proyecto. Esta
ventana cuenta con mltiples pginas, en las cuales podremos indicar
cul es el formulario principal del programa, en caso de que existan
varias en el proyecto, el ttulo de la aplicacin, el icono con el que
aparecer en la barra de tareas o el Explorador, el archivo de ayuda y
otra serie de opciones que afectarn al proceso de compilacin y
generacin del ejecutable final.
En la parte inferior de la ventana, que puede* ver en la figura 3.3,
existe una opcin llamada Default, que podemos activar si deseamos que
las modificaciones que vamos a realizar en las opciones de proyecto
sean tomadas como valores por defecto para proyectos posteriores.
3.2.3. Proyectos predefinidos
Ya en un apartado anterior hemos visto cmo podamos aadir al
Depsito de objetos una plantilla de proyecto y cmo sta poda
convertirse en el proyecto por defecto, de tal forma que se utilizase
al iniciar cada nuevo proyecto. En ocasiones, sin embargo, podemos
necesitar iniciar un proyecto con unas caractersticas diferentes a
las del proyecto por defecto. En este caso, en lugar de usar la opcin
New Application del men File utilizaremos la opcin New, que nos

llevar a la ventana principal del Depsito de objetos. En ella


podremos abrir la pgina Projects y seleccionar cualquiera de las
plantillas disponibles.

Figura 3.3. Ventana de las opciones de proyecto


Para crear un nuevo proyecto a partir de una plantilla del Depsito de
objetos, lo nico que habremos de hacer ser un doble clic sobre el
icono que representa al modelo de proyecto que nosotros queremos.
Tambin podemos seleccionar dicho icono y pulsar a continuacin el
botn OK. Acto seguido aparecer una ventana, en la que tendremos que
indicar el camino en el que deseamos alojar los archivos del nuevo
proyecto que se va a crear. Lo habitual es utilizar un directorio
independiente para cada proyecto, de tal forma que no se puedan dar
confusiones entre los elementos de distintos proyectos.
3.3. El archivo de proyecto
Delphi relaciona todos los elementos de un proyecto generando un
mdulo de cdigo, que se almacena en un archivo con extensin DPR. Es
a ste al que se llama archivo de proyecto y, al tratarse de un mdulo
de cdigo, podemos editarlo como cualquier otro en el Editor de cdigo
de Delphi. Para ello bastar con seleccionar la opcin View Source del
men Project, que abrir una nueva pgina en la ventana del Editor de
cdigo conteniendo el archivo de proyecto.

Por regla general, nunca necesitaremos manipular directamente el


cdigo del archivo de proyecto, ya que de ello se ocupa Delphi. En
cualquier caso, su estructura es bastante simple como podemos ver en
la figura 3.4. Bsicamente, contiene una referencia a cada uno de los
archivos que almacenan los mdulos de cdigo, tras la clusula Uses, y
una llamada al mtodo CreateForm() por cada formulario a crear. La
ejecucin del programa se lleva a trmino en el momento en que se
llama al mtodo Run().

Figura 3.4. Archivo con el cdigo de un proyecto simple


3.4. Archivos de formulario
El contenido de cada uno de los formularios existentes en el proyecto:
los componentes, valores de sus propiedades y los enlaces de los
eventos con el cdigo, se almacena de forma individual en un archivo
con extensin DFM. A la hora de guardar un proyecto, Delphi siempre
nos preguntar el nombre que deseamos dar a cada uno de los archivos.
Un archivo DFM es, en realidad, un archivo de texto que, aunque no es
habitual, puede ser editado manualmente. El contenido de este archivo
se almacena en el ejecutable final como un recurso ms, que durante la
ejecucin ser usado para crear adecuadamente cada formulario.
Para editar un archivo DFM, que es el cdigo que define un formulario,
tan slo hay que pulsar la combinacin <Alt+F12> mientras estamos en
el formulario, o bien desplegar el men emergente de sta y
seleccionando la opcin View as Text. A partir de ese momento podemos

modificar el contenido del archivo, lo que indirectamente afectar al


diseo del formulario.
Cuando hayamos finalizado podemos usar la misma combinacin de teclas,
o bien la opcin View as Form del men emergente del Editor de cdigo,
para convertir de nuevo el archivo de texto en un formulario. Ha de
tener en cuenta que mientras tenga abierto el archivo DFM en el editor
no le ser posible acceder al mdulo de cdigo asociado al formulario.
Podemos aadir nuevos formularios a nuestro proyecto de diversas
formas. La opcin New Form del men File, o el botn equivalente,
crearn un formulario vaco o el formulario que se haya fijado por
defecto en las opciones del Depsito de objetos. Mediante la opcin
New del mismo men podemos acceder al Depsito de objetos,
seleccionando
cualquiera
de
las
plantillas
de
formularios
ya
existentes.
3.5. Mdulos de cdigo
Todo formulario lleva siempre asociado un mdulo de cdigo, un archivo
con extensin PAS y con el mismo nombre que el archivo DFM en el que
se almacena la definicin del formulario. La finalidad de este mdulo
de cdigo, como su propio nombre indica, es contener el cdigo
correspondiente a los mtodos asociados a los eventos de los
componentes y del propio formulario. Adicionalmente, en un mdulo de
cdigo pueden existir otros procedimientos, funciones y definiciones.
Ya sabemos cmo podemos editar un archivo de este tipo, mediante el
Editor de cdigo. Un archivo PAS es en realidad un archivo de texto,
al igual que los archivos DPR y DFM, por lo que puede ser editado con
cualquier otro editor sin ningn problema.
Adems de los mdulos de cdigo asociados a cada uno de los
formularios, en el proyecto pueden existir tambin mdulos de cdigo
independientes,
conteniendo
tan
slo
definiciones
de
objetos,
procedimientos o funciones, que posteriormente podrn ser utilizados
desde otros puntos. A todos los efectos, estos mdulos independientes
se gestionarn de igual forma que los que estn asociados a un
formulario.
Cada vez que se aade un nuevo formulario al proyecto, de forma
indirecta tambin se est aadiendo un mdulo de cdigo. Si deseamos
insertar en el proyecto un mdulo de cdigo independiente, no tenemos
ms que abrir el Depsito de objetos y hacer doble clic sobre el icono
Unit de la primera pgina.
3.6. Grupos de proyectos
Como se ha comentado anteriormente, Delphi 5 cuenta con un Gestor de
proyectos que permite trabajar de forma simultnea con varios
proyectos. En un determinado momento, no obstante, slo uno de ellos

estar activado, mostrndose


diferenciarse del resto.

con

Los grupos de proyecto son archivos


archivos de texto, conteniendo el
los proyectos que componen el
simplemente seleccionando la opcin
emergente.

un

tipo

de

letra

resaltado

para

con extensin BPG. En realidad son


cdigo preciso para generar todos
grupo. Podemos ver este cdigo
View Project Group Source del men

Si trabajamos con un grupo de proyectos y guardamos el archivo BPG,


posteriormente podremos volver a abrirlos con un solo paso, sin
necesidad de recuperar de forma individual cada uno de ellos. Tan slo
tendremos que recuperar el archivo BPG, es decir, el grupo de
proyectos.
3.7. Otros elementos de un proyecto
Adems de los elementos que se han citado en los puntos anteriores, un
proyecto puede contar con otros archivos adicionales que no han de
estar necesariamente asociados a un formulario ni contener cdigo.
Entre estos elementos podemos encontrar, por ejemplo, el archivo de
ayuda, que se distribuir conjuntamente con la aplicacin, o los
archivos de recursos. Estos ltimos, que pueden contener iconos,
imgenes, cadenas de texto y muchos otros elementos, s que pasan a
formar parte del ejecutable, aun cuando la referencia a ellos no se
realiza mediante ninguna opcin de men ni botn del Gestor de
proyectos, sino utilizando una directiva: {$RI}.

4. Fundamentos de Object Pascal


4.1. Introduccin
A pesar de que la mayor parte del desarrollo de una aplicacin con
Delphi se realiza de forma visual, insertando componentes y
modificando propiedades, ningn programa tendr una aplicacin
prctica si tan slo cuenta con una interfaz, sin un cdigo de
programa que sea capaz de procesar las entradas de datos y generar
unos resultados, o lo que es lo mismo, sin que el programa sea
interactivo.
Consecuentemente, el conocimiento del lenguaje que utiliza Delphi es
de suma importancia, ya que de lo contrario difcilmente podremos
escribir nada de cdigo. Este lenguaje, llamado Object Pascal, es un
heredero del Turbo Pascal de Boriand y, seguramente, el Pascal ms
evolucionado que existe actualmente. Se trata de un lenguaje
completamente estructurado, con orientacin a objetos, claro y muy
elegante en cuanto respecta a la claridad y eficacia del cdigo.
A lo largo de este captulo vamos a conocer los fundamentos de Object
Pascal con el fin de aprender a declarar variables, construir
expresiones, conocer las estructuras de control y adquirir algunos
conocimientos de las capacidades de orientacin a objetos. Como se ha
dicho, stos sern los fundamentos que nosotros necesitemos para
comenzar, pero Object Pascal es un lenguaje mucho ms amplio y
complejo, que difcilmente es posible abarcar en un libro de este
tipo.
4.2. Estructura general
El cdigo de un programa Object Pascal se almacena en lo que se
denominan mdulos o units. Un mdulo no es mas que un archivo de
texto, generalmente con extensin PAS, que tiene una estructura
general siempre idntica, contando con una cabecera, en la que se
establece el nombre del mdulo, y un bloque principal, delimitado
entre las palabras Begin y End, en el que se alojarn las sentencias o
cdigo a ejecutar.
Las siguientes cuatro lneas de
programa completo en Object Pascal.

cdigo,

por

ejemplo,

seran

un

Program Prueba;
Begin
ShowMessage('Hola') ;
End.
En este programa existen una serie de palabras reservadas, que en el
Editor de cdigo de Delphi aparecern en negrita. Estas palabras son
Program, Begin o End, reconocidas directamente por el lenguaje Object

Pascal, mientras que la lnea que comienza con ShowMessage(), por el


contrario, es una llamada a un procedimiento.
4.2.1. El punto y el punto y coma
Si se fija en el programa anterior, o abre cualquier mdulo de cdigo
en el editor de Delphi, observar que al final de algunas lneas
existe un punto y coma, que se usa como separador de sentencias. El
punto y coma se dispondr, por regla general, al final de cada
sentencia que no est compuesta estrictamente de una palabra
reservada, como Begin, tras la cual no existe este elemento. Tambin
se puede omitir el punto y coma en la sentencia anterior a la lnea
que contiene la palabra End.
Ciertas construcciones, como el condicional lf..Then..Else, exigen que
el punto y coma sea omitido en la sentencia anterior a la palabra
Else. La palabra End, a pesar de ser una sentencia compuesta por una
sola palabra reservada, por regla general siempre ir seguida de un
punto o punto y coma.
A medida que vayamos viendo cdigo en Object Pascal, usted aprender
intuitivamente cundo debe y cundo no debe utilizar un punto y coma.
En el cdigo de un programa pueden existir mltiples bloques,
delimitados por las citadas palabras Begin y End y precedidos por un
nombre. Al bloque ms exterior, que se inicia con el primer Begin sin
nombre y se termina con el End correspondiente, es al que se denomina
bloque principal del mdulo.
Dentro de ste pueden existir otros bloques, por ejemplo definiendo
mtodos y fundones, tipos, etc. La palabra End del bloque principal,
que determina el final del cdigo, ir siempre seguida de un punto, en
lugar de hacerlo con un punto y coma.
4.2.2. Mdulos y la clusula Uses
Como se dijo en un captulo anterior, una aplicacin desarrollada con
Delphi suele estar compuesta de mltiples mdulos, cada uno de los
cuales almacena el cdigo de un formulario o cualquier otro cdigo
necesario, como puede ser el de la definicin de objetos o
procedimientos y funciones. La cabecera de un mdulo se inicia con la
palabra Unit y no con la palabra Program.
En realidad, el mdulo que contiene en su cabecera la palabra Program
es un mdulo ms, en cuanto a su formato y contenido, pero se
diferencia de los dems en que l es el mdulo principal, por el que
se iniciar la ejecucin del programa.
En un programa Delphi el mdulo principal es el archivo de proyecto,
un archivo con extensin DPR cuya estructura fue ya comentada
brevemente en el captulo anterior. El resto de los mdulos de la

aplicacin, por tanto, contienen cdigo que no ser ejecutado


directamente, hasta en tanto desde el mdulo principal, u otro mdulo
en ejecucin, se realice la llamada oportuna.
La divisin del cdigo de una aplicacin en mltiples mdulos es algo
muy prctico, ya que permite un fcil mantenimiento del cdigo, en
contraposicin a la construccin monoltica en un slo archivo de
texto que se utilizaba antes.
Adems de los mdulos de cdigo que nosotros mismos aadamos a nuestro
proyecto, Delphi cuenta con una serie de mdulos prefabricados, con
cdigo ya ejecutable, preparados para ser usados desde nuestros
programas. El cdigo de estos mdulos se almacena en archivos con
extensin DCU y en ellos podemos encontrar procedimientos, funciones,
objetos y componentes a los que tan slo tendremos que llamar para
realizar una accin determinada.
Para poder usar el cdigo contenido en un cierto mdulo desde otro
mdulo, es necesario incluir en el primero una clusula llamada Uses,
seguida del nombre del mdulo o mdulos a usar. Si abre en el Editor
de cdigo de Delphi el archivo de un proyecto cualquiera, podr ver
que tras la clusula Uses se hace una referencia al mdulo Forms, en
el que se encuentra todo el cdigo necesario para hacer funcionar un
formulario, y tambin a cada uno de los mdulos que existan en el
proyecto.
4.3.2. Tipos
Tanto para declarar una variable como para utilizar un valor
constante, es necesario que conozcamos los diferentes tipos de datos
con los que puede trabajar Object Pascal. Estos tipos nos permitirn
trabajar
con
nmeros,
en
diferentes
precisiones,
cadenas
de
caracteres, punteros, etc. Cada uno de los tipos est representado por
una palabra clave que, de una forma ms o menos clara, representa al
tipo de dato. En la tabla 4.1 se enumeran los tipos ms habituales.
Tipo

Valores que puede contener

Byte
Shortint
Smallint
Word

Nmeros enteros comprendidos entre 0 y 255.


Nmeros enteros comprendidos entre -128 y 127.
Nmeros enteros comprendidos entre -32768 y 32767.
Nmeros enteros comprendidos entre 0 y 65535.
Nmeros enteros comprendidos entre -2147483648 y
2147483647.
Igual que Integer.
Nmeros enteros entre 0 y 4294967295.
Nmeros enteros entre 0 y 2147483647.
Nmeros enteros entre 2^63 y 2^63.

Integer
LongInt
LongWord
Cardinal
Int64

Boolean
ByteBool
WordBool
LongBool
Single
Double
Real
Extended
Comp
Char
AnsiChar
WideChar
String
ShortString
AnsiString
PChar
PansiChar
PwideChar
Pointer
Variant

True o False ocupando un byte de memoria.


Igual que Boolean.
Igual que Boolean pero ocupando dos bytes de
memoria.
Igual que Boolean pero ocupando cuatro bytes de
memoria.
Nmeros en coma flotante con hasta 8 dgitos.
Nmeros en coma flotante con hasta 16 dgitos.
Igual que Double.
Nmeros en coma flotante con hasta 20 dgitos.
Nmeros enteros de hasta 20 dgitos.
Un carcter cualquiera.
Lo mismo que Char.
Carcter de 16 bits para soporte Unicode.
Cadena de caracteres.
Cadena de un mximo de 255 caracteres.
Cadena de caracteres.
Puntero a secuancia de caracteres terminada con
nulo.
Lo mismo que PChar.
Puntero a secuencia de caracteres de 16 bits.
Puntero genrico.
Tipo de dato variable.

Tabla 4.1. Tipos de datos Object Pascal


Los tipos enumerados en esta tabla pueden ser divididos en dos grupos,
segn sean tipos genricos o tipos fundamentales. Los tipos genricos,
como Integer o String, no son iguales en Delphi 1 y en Delphi 5, ya
que mientras en el primer caso un entero ocupa 16 bits, en el segundo
se almacena en 32 bits, por lo que el rango de valores es diferente.
Otro tanto ocurre con el tipo String, que puede almacenar una cadena
de 255 caracteres o sin lmite, dependiendo de la versin del
compilador. En contraposicin tenemos a los tipos fundamentales, como
Shortint o AnsiString, cuyo tamao es siempre el mismo.
Adems de los tipos que puede ver en la tabla 4.1, que son muchos,
pueden existir muchos tipos ms, ya que Object Pascal permite crear
nuevos tipos de datos, como veremos posteriormente. As, nos podemos
encontrar con un tipo llamado TDateTime que nos permite el
almacenamiento de fechas y horas.

4.3.3. Declaracin de variables


La declaracin de una variable puede tener lugar a diferentes niveles
o mbitos, como puede ser en mbito de mdulo, antes del bloque
principal, o en mbito local, en el interior de algn bloque de
definicin de procedimiento o funcin.
En cualquier caso, el inicio de la seccin de declaracin de variables
estar siempre marcado por la palabra Var. Esta ir seguida de una o
ms lneas, en cada una de las cuales es posible declarar una o ms
variables de un determinado tipo.
Cada una de estas lneas estar compuesta del identificador de una
variable y el tipo, separando ambos elementos por dos puntos. En caso
de que vayamos a declarar varias variables del mismo tipo, podemos
disponer los identificadores uno tras otro separndolos por coma,
especificando al final el tipo.
En caso de que la variable que se est declarando sea de tipo String,
AnsiString o ShortString, de forma opcional podemos especificar, entre
corchetes, el nmero de caracteres que como mximo podr contener
dicha cadena. Si usamos el tipo AnsiString
y no especificamos una longitud mxima, el espado para la cadena se
asignar dinmicamente segn las necesidades.
En el siguiente fragmento de cdigo puede ver cmo se han declarado
cuatro variables, una de tipo Byte, dos de tipo Integer y una de tipo
String con un lmite mximo de 25 caracteres.
Var // Declaramos lo siguiente
Contador; Byte; // Una sola variable
N1, N2: Integer; // Dos variables del mismo tipo
Nombre: String [25]; // Una cadena de 25 caracteres mximo
4.3.4. Matrices
A veces es necesario mantener mltiples valores del mismo tipo, para
los cuales, obviamente, podramos declarar variables individuales.
Esta tcnica, sin embargo, no es til cuando el nmero de variables es
muy grande. Suponga, por ejemplo, que desea almacenar cien nmeros
para realizar unos clculos. Desde luego no sera muy cmodo tener que
declarar cien identificadores distintos, gestionndolos de forma
individual en posteriores asignaciones y expresiones.
En casos como el descrito es mucho ms cmodo usar matrices, nombre
con el que se conoce a un tipo de variable que se caracteriza por ser
capaz de contener mltiples valores del mismo tipo, haciendo
referencia a cada uno de ellos mediante un ndice.
Object Pascal permite crear matrices prcticamente de cualquier tipo,
incluso es posible crear matrices de matrices, como veremos en un

momento. Esto quiere decir que podemos crear matrices no slo de


nmeros, sino tambin de cadenas, de objetos o de cualquier otro tipo
que nosotros hayamos definido previamente.
Declarar una matriz
La declaracin de una matriz es muy similar a la declaracin de
cualquier otra variable, si exceptuamos que delante del tipo, tras los
dos puntos, habremos de disponer la palabra Array, indicando entre
corchetes el rango de elementos que deseamos que tenga la matriz y, a
continuacin, la palabra Of seguida del tipo.
En Object Pascal un rango de valores se escribe especificando el
primer valor seguido de dos puntos y el ltimo valor del rango. As,
si deseamos declarar una matriz de, por ejemplo, veinticinco elementos
de tipo Byte, podramos usar la sentencia siguiente:
Matriz: Array[1..25] Of Byte;
En este caso la variable Matriz es una matriz que contiene veinticinco
elementos, con ndices que van desde el 1 hasta el 25. Cada uno de los
elementos es una variable de tipo Byte, que podemos usar en cualquier
mbito y expresin en la que se admita un valor de este tipo.
La matriz anterior sera de una sola dimensin, es decir, podemos
representarla como si fuese una lista de celdillas, en cada una de las
cuales se almacena un valor individual. Podemos tambin definir
matrices de dos, tres o cualquier otro nmero de dimensiones.
Supongamos que deseamos tener una matriz en forma de tabla, con diez
columnas por quince filas, lo que hara un total de ciento cincuenta
casillas, en cada una de las cuales deseamos almacenar una cadena de
caracteres. Podramos declarar esta matriz de cualquiera de las dos
formas siguientes:
Cadenas1: Array[1..10, 1..151 Of String;
Cadenas2: Array[I..10] Of Array[1..15] Of String;
En el primer caso hemos facilitado el rango de la primera dimensin y
el de la segunda dimensin en los mismos corchetes, separndolos por
una coma. La segunda versin es algo ms compleja y lo que se hace es
declarar una matriz de diez elementos, cada uno de los cuales contiene
una matriz de quince elementos de tipo String. En realidad el
resultado final es el mismo, es decir, tendramos una matriz
bidimensional de cadenas de caracteres. De forma similar podramos
declarar matrices con cualquier otro nmero de dimensiones.
Referencia a los elementos de una matriz
Aunque en ocasiones, dependiendo del contexto, nos puede interesar
hacer referencia a una matriz como un todo, en la mayora de los casos
necesitaremos referimos a uno solo de sus elementos, para lo cual

deberemos
elemento.

utilizar

el

ndice

ndices

que

correspondan

dicho

Para acceder a un determinado elemento de una matriz lo nico que


habremos de hacer es facilitar el ndice, entre corchetes, detrs del
identificador. En caso de que la matriz tenga mltiples dimensiones
deberemos facilitar un ndice para cada una de ellas, bien utilizando
unos corchetes para cada ndice o separndolos por comas dentro de una
nica pareja de corchetes.
Suponiendo que tuviramos declarada la matriz Cadenas 1 que se ha
expuesto como ejemplo en el punto anterior, podramos hacer referencia
a uno de sus elementos de cualquiera de las dos formas siguientes. El
resultado es equivalente y en ambos casos se mostrara el contenido de
la cadena correspondiente a la columna 1 fila 5.
ShowMessage(Cadenas[1,5]);
ShowMessage(Cadenas[1][5]) ;
4.3.5. Definir nuevos tipos
Los tipos de datos bsicos de Object Pascal, tanto fundamentales como
genricos, pueden ser usados en nuestros programas para construir
otros tipos de datos. Estos nuevos tipos pueden ser escalares, en caso
de que puedan tomar un nmero determinado de valores, o bien tipos
complejos o estructurados, en caso de que estn compuestos de varios
elementos.
Entre los tipos del primer apartado, escalares, tenemos los tipos
enumerados y los subrangos, adems de algunos de los tipos que ya
conocemos, como Boolean, Integer, etc. En el segundo apartado, tipos
estructurados, nos encontramos con los registros y los conjuntos.
Tambin pertenecen a este grupo de tipos las matrices, aunque no
necesariamente sus elementos. Es decir, una matriz de enteros es un
tipo estructurado, pero un elemento de esa matriz es un tipo escalar.
La definicin de nuevos tipos se efecta previamente a la declaracin
de variables de esos tipos, como es lgico. El apartado del mdulo en
que se definen tipos se inicia con la palabra Type.
Enumeraciones
Cuando necesitemos crear una variable para contener un nmero
determinado de valores, no muy extenso, en lugar de usar cualquiera de
los tipos predefinidos de Object Pascal, que seguramente no se
adecuarn a nuestras necesidades, lo nico que hemos de hacer es
declarar una enumeracin.
Suponga que necesita crear una variable que sea capaz de contener un
da de la semana y no desea utilizar una variable numrica, puesto que
sta le permitir asignar cualquier valor.

La solucin sera la declaracin de una enumeracin como la siguiente:


Type
{ TDiaSemana no ea una variable, sino un
identificador de tipo }
TDiaSemanas (Lunes, Martes, Mircoles, Jueves, Viernes,
Sbado, Domingo);
Algo a tener en cuenta, tal y como se indica en un comentario en el
fragmento anterior, es que el idendficador TdiaSemana no es una
variable, al igual que no lo es la palabra Integer o la palabra
String. Este nuevo identificador es un tipo de dato y, como tal, puede
ser usado para declarar variables de ese tipo.
La forma de declarar variables del tipo TDiaSemana sera idntica a la
ya vista para cualquier tipo de dato, siendo posible tambin la
creacin de matrices de este nuevo tipo. En el siguiente fragmento
puede ver dos ejemplos de declaracin y uso del nuevo tipo.
Var
Hoy: TDiaSemana;
Incidencias: Array[1..5] 0 TDiaSemana;
begin
Hoy := Domingo;
Incidencias[1] := Mircoles;
El nuevo tipo tambin puede ser usado como ndice de una matriz, al
igual que cualquier otro tipo escalar. Suponga que desea definir una
matriz de enteros en la que poder anotar los gastos diarios. Lo ms
lgico es que el ndice de esta matriz no sea un nmero, sino uno de
los elementos de la enumeracin que hemos definido antes. En el
siguiente fragmento puede ver cmo se declara la matriz Gastos y cmo
se asigna un valor a uno de sus elementos. Observe que para declarar
la matriz no es necesario especificar un ndice de inicio y fin, ya
que el propio tipo TDiaSemana ya cuenta con unos lmites, que son los
identificadores Lunes y Domingo.
var
Gastos: ArraytTDiaSeinana] 0 integer;
begin
Gastos[Lunes] := 1500;
Subrangos
En caso de que necesitemos declarar una variable de un tipo ya
existente, pero en la que no queremos permitir la asignacin de todos
los valores, sino slo de un determinado rango de ellos, ser
necesario definir un subrango. Este tipo de dato le ser til, por
ejemplo, si precisa una variable numrica que tan slo pueda contener

los valores 1 a 100, o una variable TDiaSemana a la que slo sea


posible asignar das laborables.
La definicin de un subrango es muy simple y, de hecho, ya la
conocemos, puesto que para establecer los ndices de una matriz hemos
estado usando subrangos. En el siguiente fragmento puede ver cmo se
crean los dos tipos que se acaban de comentar, declarando una variable
de cada uno de ellos a la que posteriormente se asigna un valor.
Observe que la segunda asignacin no es vlida, ya que el valor
facilitado no est incluido en el subrango TLaborable.
{ Definimos los tipos }
TUnoCien = 1..100;
TLaborable = Lunes..Viernes;
Var
{ Y una variable de cada tipo )
N; TUnoCien;
Inicio: TLaborable;
begin
N := 34; // Asignacin correcta
Inicio := Domingo; // Esto generara un error
Al igual que los tipos enumerados, los subrangos pueden ser usados
como ndices de una matriz. Tambin podemos crear matrices de un tipo
subrango, como de cualquier otro tipo escalar.
Conjuntos
Podramos definir un conjunto como una variable capaz de contener uno,
varios, todos o ninguno de los elementos de un determinado tipo
escalar. Dicho tipo escalar, que se utiliza como base del conjunto, no
deber tener ms de 256 valores diferentes, por lo que no es posible
usar como base para un conjunto tipos como Integer.
No se ha de confundir un conjunto con una matriz, ya que a pesar de
ser ambos tipos estructurados, no son equivalentes. Un conjunto no
contiene un nmero de elementos predeterminado y, como se ha dicho,
puede estar vaco o contener todos los elementos del tipo base.
A diferencia de lo que ocurre con una matriz, no es posible acceder a
los elementos individuales de un conjunto como si fuesen variables
independientes. Sin embargo, el lenguaje cuenta con una serie de
operadores que permiten aadir, eliminar y comprobar la existencia de
un elemento en el conjunto.
La declaracin de un conjunto se construye con las palabras Set Of,
seguidas del tipo base. Por ejemplo, suponga que desea declarar una
variable que sea un conjunto de das, en la que pueda almacenar los
das de la semana en los que ha hecho una copia de seguridad de su
disco. La declaracin del tipo, la variable y posterior asignacin
podran ser las siguientes:

TDiasSemana = Set Of TDiaSemana;


Var
Copias: TDiasSemana;
begin
Copias := [Lunes, Jueves, Domingo];
En este fragmento se asume que el tipo TDiaSemana ya est declarado,
en forma de enumeracin, por lo que la variable Copias puede contener
cualquier combinacin de los valores de dicha enumeracin.
Registros
Un
registro
es
tambin
un
tipo
estructurado
o
complejo,
caracterizndose por contener en su interior mltiples campos o
variables, cada una de las cuales puede ser de un tipo diferente, lo
que le diferencia de una matriz. Este tipo de dato es muy til cuando
necesitamos
mantener
una
serie
de
datos
de
forma
conjunta,
generalmente porque estn relacionados de alguna forma. Imagine, por
ejemplo, que desea crear una agenda telefnica en la que anotar
nombres de personas, su nmero de telfono y su direccin. En lugar de
definir una variable separada para cada dato, es mucho ms lgico
crear un nuevo tipo de dato, un registro, que nos permita gestionar
esos valores conjuntamente.
Para definir un registro facilitaremos primero, como es habitual, el
identificador con el que se le va a conocer, seguido de un signo = y
la palabra Record. En las lneas siguientes tendremos que especificar
cules sern los componentes del registro, para lo cual iremos
facilitando identificadores y tipos para cada miembro, como si
estuvisemos declarando variables. La declaracin de cada miembro
estar terminada con un punto y coma, y el fin de la definicin del
registros indicar mediante la palabra End.
Por tanto, podramos declarar el registro para mantener los datos de
nuestra agenda telefnica de la siguiente forma:
Type
{ Declaramos un registro }
TFormAgenda = Record
Nombre: String; { Nombre de la persona }
Direccin; String; < su direccin >
Telefono: String; { y su telfono }
Personal: Boolean; { Indicador de telfono personal }
End;
Teniendo ya el registro definido, podemos declarar una variable de
tipo TFormAgenda de igual forma que haramos con cualquier otro tipo.
El problema, sin embargo, lo encontraremos a la hora de acceder a los
miembros de esa variable, ya que lo habitual es hacer referencia a uno
de ellos y no al registro como un todo.

Siempre que necesitemos acceder a un miembro de un registro, una


propiedad, evento o mtodo de un objeto, como pueda ser un componente
y, en general, cada vez que para acceder a un elemento tengamos que
referimos antes a otro en el que est contenido, deberemos usar el
operador de cualificacin, que es un punto. Este operador se usar
como separador entre los dos identificadores, tal y como puede ver en
el siguiente fragmento de cdigo.
Var
UnaForm: TFormAgenda;
begin
UnaForm.Nombre :a 'Pedro Garca';
UnaForm.Direccin := 'Avda. de la Paz, 24';
UnaForm.Telefono := '348123';
UnaForm.Personal :s True;
Al escribir este cdigo comprobar que tras introducir el nombre de la
variable, UnaForm en este caso, y el punto de separacin, Delphi abre
una pequea ventana emergente en la que enumeran los miembros del
tipo. Esto evita que tengamos que recordar los nombres asignados
evitando fallos tambin de tecleo, ya que podemos seleccionar
directamente el elemento de esa lista.
Los miembros de un registro pueden ser de cualquier tipo, incluidas
matrices, otros registros e incluso objetos. Tambin es posible crear
matrices de registros. Todo esto puede crear una cierta complejidad a
la hora de referirse a un determinado miembro. La regla que hemos de
tener
clara
es
que
siempre
hay
que
especificar
primero
el
identificador de la variable que acta como contenedor para, a
continuacin y separado por un punto, escribir el identificador de la
variable contenida. Si sta a su vez es un contenedor tan slo hemos
de repetir el proceso. Observe las siguientes declaraciones y accesos
a miembros. Hemos modificado la definicin del registro TFormAgenda y
creado un nuevo registro, cuya finalidad es facilitarnos el
agrupamiento del prefijo, nmero de telfono y un indicador.
Posteriormente creamos una matriz para cien formas de agenda y
asignamos valores a algunos miembros del primer formulario.
Type
{ Registro para mantener un nmero de
telfono, con su prefijo, y un indicador
de si es un telfono personal )
TTelefono = Record
Prefijo, Numero: String;
Personal: Boolean;
End;
{ Declaramos un registro }
TFormAgenda = Record
Nombre: String; { Nombre de la persona }
Direccin: String; { su direccin )

Telefono: Array[l..5] Ot TTelefono; { y sus telfonos }


End;
Var
{ Matriz para cien formularios de agenda )
Formularios: Array[l..1001 Of TFormAgenda;
begin
Formularios[1].Nombre != 'Pedro Garca';
Formularios[1].Direccin := 'Avda. de la Paz, 24';
Formularios[1].Telefonodl .Prefijo := '953';
Formularios[1].Telefono[1].Numero := '348123';
Formularios[1].Telefonoll].Personal := True;
Formularios[1].Telefono[2] .Prefijo := '953';
Formularios[1].Telefono[2].Numero := '346539';
Formularios[1].Telefono[2].Personal := False;
4.3.6. Constantes y literales
No todos los valores que se usan en un programa son facilitados
mediante variables, en muchas ocasiones es necesario usar constantes.
Estas constantes pueden aparecer en forma de literales o bien
representadas mediante un identificador, que nosotros habremos
declarado previamente.
Una constante puede ser prcticamente de cualquiera de los tipos que
hemos conocido hasta ahora: numricos, de cadena, conjuntos, etc. Las
constantes literales numricas son las ms simples, ya que se componen
de la secuencia de dgitos correspondiente, sin ms. Las literales de
tipo cadena se caracterizan por ir delimitadas entre comillas simples,
como hemos podido ver en algunos de los ejemplos anteriores. Los
conjuntos, por su parte, se representan literalmente mediante los
valores del tipo base, que irn separados por comas y entre corchetes.
Tambin anteriormente vimos un ejemplo de este tipo de notacin.
El uso de constantes literales en el cdigo es una tcnica no muy
aconsejable, ya que si su valor ha de ser modificado nos veremos
forzados a buscar todas las apariciones de la constante en el cdigo.
Adems, si no se incluyen los necesarios comentarios la constante
puede convertirse en un elemento oscuro, al no saber exactamente qu
es lo que representa.
En Object Pascal cualquier constante literal puede ser sustituida por
un identificador, que habr sido previamente
declarado. Esta
declaracin se llevar a cabo en un apartado que se inicia con la
palabra Const y en el cual existir una lnea por constante, en la que
se especificar el identificador que va
a representarla y el valor que va a contener, separando ambos
elementos mediante un signo =. Estos identificadores podrn ser
posteriormente usados en el mismo contexto en el que se utilizaran
las literales, con la nica diferencia de que la expresin ser
bastante ms clara.

Suponga que necesita asignar a una variable el nmero de minutos que


tiene un da, para lo cual deber multiplicar el nmero de horas del
da por el nmero de minutos de una hora. En lugar de usar la
expresin 24 * 60, que es totalmente correcta, podramos declarar y
utilizar las constantes que se exponen como ejemplo en el siguiente
fragmento de cdigo.
Const
HorasDia = 24;
MinutosHora = 60;
Var
Minutos: Integer;
Begin
Minutos := HorasDia * MinutosHora;
Aunque en este ejemplo las dos constantes contienen un valor numrico,
podemos asignarles perfectamente cualquier otro tipo de valor, como
puede ser una cadena o un conjunto.
Constantes con tipo
Las constantes explicadas y puestas como ejemplo en el punto anterior,
HorasDia y MinutosHora, son conocidas como constantes sin tipo, ya que
a la hora de declararlas simplemente se les asigna un valor, pero no
se especifica su tipo, como se hace al declarar una variable. Las
constantes de este tipo no pueden contener, por ejemplo, una matriz de
valores, o un registro.
La declaracin de una constante con tipo se lleva a cabo en el
apartado Const, como cualquier otra constante, pero el formato de la
declaracin es idntico al de una variable, debiendo especificarse el
tipo. Tras ste, y separado por un signo =, facilitaremos el valor que
deseamos asignar.
Las constantes con tipo pueden ser de cualquier tipo que est
permitido para una variable, por lo que es posible crear constantes
que contengan matrices de valores, registros, objetos, etc. En el
siguiente fragmento de cdigo puede ver cmo se declara una constante
conteniendo una matriz de cadenas.
Const
CadenaMes: Array[1..12] Of String =
('Ene', 'Feb', 'Mar', 'Abr', 'Hay', 'Jun',
'Jul', 'Ago', 'Sep', 'Oct', 'NoV, 'Dio');
Observe que los valores han sido delimitados por unos parntesis y
separados por comas, ya que la constante no contiene un slo valor,
sino una matriz. Esta misma notacin se utilizara en caso de que
necesitsemos crear una constante de algn tipo de registro.

4.4. mbito de los identificadores


Los identificadores que se declaran y usan en el cdigo de un programa
Delphi pueden tener distintos mbitos, segn lo cual estarn o no
disponibles en determinados puntos del programa. Bsicamente existen
dos mbitos: global y local.
Un identificador global es aquel que est disponible desde cualquier
punto del cdigo del programa, incluso si dicho punto se encuentra en
un mdulo distinto. Un identificador local, por el contrario, tan slo
est disponible en el interior del bloque en que se ha declarado.
4.4.1. Identificadores locales
Cualquier identificador que se declare en el interior de un
procedimiento, una funcin, la definicin de un objeto, o la parte de
implementacin de un mdulo, es un identificador local que, por tanto,
slo puede ser usado por el cdigo correspondiente al bloque en que se
ha efectuado dicha declaracin, as como por los bloques que puedan
existir en su interior.
El caso ms claro de un identificador local lo encontraremos en la
definicin de tipos o declaracin de variables que se realiza en el
cuerpo de un procedimiento o funcin. Suponga, por ejemplo, que
escribimos un procedimiento en cuyo interior declaramos una variable,
como se muestra a continuacin.
{ Procedimiento Espera }
Procedure Espera;
Var
N: Integer; { Declaramos una variable entera >
Begin
N := 5; {Le asignamos un valor }
End;
La variable N es una variable local, que se caracteriza por ser creada
automticamente cuando la ejecucin del programa llega a este
procedimiento y ser destruida cuando dicho procedimiento llega a su
fin. Por tanto, la variable N slo existe mientras el procedimiento
Espera se est ejecutando, por lo cual es lgico pensar que no es
posible usarla desde ningn otro punto del cdigo, como puede ser
desde otro procedimiento o desde el mismo bloque principal del mdulo.
mbito de mdulo
Un identificador tambin puede ser creado al nivel de mdulo, fuera
cualquier procedimiento o funcin, antes del bloque principal
cdigo. Los apartados Const, Var y Type pueden ser dispuestos en
mdulo en dos secciones diferentes: la de interfaz y la
implementacin.

de
de
un
de

La seccin de interfaz de un mdulo sirve para definir todos aquellos


elementos que el mdulo pone a disposicin de terceros, mientras que
en la seccin de implementacin, que se inicia con la palabra
Implementation, se codifica todo aquello que es interno y que no debe
ser usado nada ms que por el propio mdulo.
Declarando un identificador en la parte de implementacin de un mdulo
estaremos creando un identificador que es local al mdulo, pero que
puede ser usado tanto por el cdigo escrito en el bloque principal
como por el contenido en cualquier procedimiento o funcin que
definamos en el mismo mdulo. Este identificador, que a pesar de ser
local est disponible para todo el cdigo del mdulo, tiene un mbito
especial al que se denomina mbito de mdulo.
Una variable con mbito de mdulo es til, por ejemplo, para compartir
datos entre los distintos procedimientos y funciones de un mismo
mdulo. En el siguiente fragmento puede ver cmo se declara una
variable con este mbito, que posteriormente es usada desde diferentes
puntos del cdigo.
Implementation
Var
N: Integer;
{ Procedimiento Espera }
Procedure Espera;
Begin
N := 5; { Asignamos un valor a N }
End;
{ Procedimiento Duplica }
Procedure Duplica;
Begin
N := N * 2; { Multiplicamos por dos el valor )
End;
En este ejemplo los procedimientos Espera() y Duplica() estn
trabajando con la misma variable, que es creada automticamente al
iniciarse el mdulo y no al entrar en el cuerpo de ningn
procedimiento o funcin.
4.4.2. Identificadores globales
Si deseamos definir un identificador que est disponible para toda la
aplicacin y cualquier programa que utilice el mdulo en que nosotros
vamos a realizar la declaracin, es necesario crear un identificador
global.
Estos identificadores, al igual que los que tienen mbito de mdulo,
se declaran fuera de cualquier procedimiento o funcin, ms

concretamente en la parte de interfaz del mdulo, que se inicia con la


palabra Interface.
Obviamente,
una
variable
global
es
accesible
desde
cualquier
procedimiento o funcin definida en el mismo mdulo, adems de serlo
desde cualquier otro punto, como se ha dicho.
A medida que vayamos creando programas en Delphi iremos usando
identificadores globales, definidos en una serie de mdulos que ya
acompaan a Delphi, que nos facilitarn muchos aspectos del trabajo.
4.4.3. Problemas de accesibilidad
Queda claro, segn las explicaciones dadas en los apartados
anteriores, que una variable local tan slo es accesible desde el
interior del bloque en que se ha declarado, y cualquier intento de
hacer referencia a ella desde un punto extemo a dicho bloque generar
un error que el compilador nos comunicar adecuadamente.
Los problemas reales de accesibilidad tienen lugar cuando en un
determinado mbito, como puede ser un procedimiento, se declara un
identificador, por ejemplo una variable, cuyo nombre ya estaba en uso
por otro identificador extemo, declarado al nivel de mdulo o global.
Tomemos como bas el cdigo siguiente, en el que existen dos
procedimientos que modifican una variable llamada N. Sin embargo,
dichos procedimientos no estn haciendo referencia a la misma
variable, ya que mientras el primero asigna el valor a una variable
local, el segundo lo est asignando a la variable declarada a nivel de
mdulo.
Implementation
Var
N: integer;
{ Procedimiento Espera }
Procedure Espera;
Var
N: integer;
Begin
M := 5; { Asignamos un valor a N }
End;
{ Procedimiento Duplica }
Procedure Duplica;
Begin
N := N * 2; { Multiplicamos por dos el valor }
End;
Suponiendo que en el procedimiento EsperaO necesitsemos la variable N
local que hemos declarado pero, a pesar de ello, quisisemos modificar

el valor de la variable N que hay al nivel de mdulo, tendramos que


crear una referencia inequvoca, para lo cual utilizaramos el
operador de cualificacin, facilitando primero el nombre del mdulo y
a continuacin el nombre de la variable. De esta forma, la siguiente
versin del procedimiento EsperaO s modificara la variable N que hay
al nivel de mdulo, asumiendo que el mdulo se llama Unitl.
{ Procedimiento Espera }
Procedure Espera;
Var
N: integer;
Begin
N := 5; { Asignamos un valor a N }
Unitl.N := 3; { Modificamos la variable a nivel de mdulo }
End;
La misma tcnica la podramos usar si necesitsemos acceder a una
variable global que perteneciese a un mdulo diferente del actual. En
cualquier caso, para que no haya problemas, lo mejor es evitar la
duplicidad de identficadores.
4.5. Expresiones
La finalidad de las constantes y las variables, en la mayora de las
ocasiones, es representar a unos valores que actuarn como operandos
de una expresin, en base a la cual se desea obtener un determinado
resultado. Para componer estas expresiones, adems de los operandos,
que seran esos valores, tambin necesitaremos unos operadores,
mediante los cuales indicaremos las operaciones que deseamos realizar.
Por tanto, podramos definir una expresin como una combinacin de
operandos y operadores en el orden correcto y apropiado para obtener
un resultado nico. Este resultado puede ser de tipo numrico, una
cadena, un valor de tipo Boolean, etc.
Seguramente la expresin ms simple que podemos crear es la de
asignacin, en la cual toman parte dos operandos: el valor a asignar y
la variable de destino, y un operador: el de asignacin. ste, segn
hemos visto en algunos ejemplos anteriores, se representa mediante los
caracteres :=.
Las expresiones que es posible crear en Object Pascal las podemos
agrupar
principalmente
en
tres
grandes
grupos:
expresiones
aritmticas, relacinales y lgicas. Para componer una expresin de
cada uno de estos tipos, disponemos de una serie de operadores, que
vamos a conocer en los siguientes puntos.
4.5.1. Operadores aritmticos

Se denomina aritmtica a cualquier expresin en la cual intervienen


uno o ms operadores aritmticos y cuyo resultado final es numrico.
Los operadores aritmticos son binarios, lo cual quiere decir que
actan sobre dos operandos, uno dispuesto a la izquierda del operador
y otro dispuesto a la derecha. Los operadores + y - tambin puede ser
usados como operadores unarios, disponindolos delante de un nmero
para indicar su signo.
En la tabla 4.2 se enumeran los distintos operadores aritmticos,
indicndose
la
operacin
que
efectan.
Es
posible
construir
expresiones aritmticas en las que toman parte ms de un operador
aritmtico,
obviamente
disponiendo
tambin
los
operandos
correspondientes.
Operador
+
*
/
Div
Mod

Resultado de la operacin que lleva a cabo.


La suma de los dos operandos.
El primer operando menos el segundo.
El producto de los dos operandos.
El cociente de dividir el primer operando entre el
segundo.
El cociente de una divisin entrera del primer
operando entre el segundo.
El resto de una divisin entera del primer
operando entre el segundo.
Tabla 4.2. Operadores aritmticos

Todos los operadores aritmticos, a excepcin del de divisin, generan


un resultado del mismo tipo al que pertenecen los operandos. Es decir,
si sumamos dos enteros obtenemos un resultado entero y si sumamos dos
nmeros reales obtenemos un nmero real. El operador de divisin
siempre genera un resultado de tipo real, a pesar de que los operandos
sean enteros. Esto significa que no podemos asignar el resultado de
una divisin a una variable entera, se generara un error. En caso de
que deseemos obtener una divisin entera, sin parte decimal, en lugar
del operador/usaremos el operador div.

4.5.2. Operadores relacinales


Una expresin relacional es aquella en la que se comprueba la relacin
existente entre dos operandos, generndose un resultado de tipo
Boolean segn que la relacin se cumpla o no se cumpla. Si
comprobamos, por ejemplo, la relacin de igualdad entre dos variables,
el valor devuelto ser True si efectivamente los valores que almacenan
son iguales o False en caso contrario.
Los operandos de una expresin relacional no han de ser necesariamente
numricos, como s es obligatorio en una expresin aritmtica, y

podemos perfectamente comprobar


cadenas, por poner un ejemplo.

la

relacin

existente

entre

dos

Todos los operadores relacinales, que se enumeran en la tabla 4.3,


son binarios, lo que significa que actuarn siempre sobre dos
operandos. En una misma expresin es posible combinar operadores
aritmticos y relacinales, siempre que la composicin se haga de
forma correcta.
Operador
=
<>
<
<=
>
>=

El resultado es True en caso de que ...


Ambos operandos sean iguales.
Los operandos no sean iguales.
El primer operando sea menor que
El primer operando sea menor
segundo.
El primer operando sea mayor que
El primer operando sea mayor
segundo.

el segundo.
o igual que

el

el segundo.
o igual que

el

Tabla 4.3. Operadores relacinales


Como se ha comentado anteriormente, los operandos de una expresin
relacional no tienen necesariamente que ser numricos, siendo posible,
por ejemplo, comprobar si dos cadenas son iguales, o si una es mayor
que la otra.
Los operandos de una expresin relacional pueden ser, a su vez, otras
expresiones, generalmente de tipo aritmtico. En el siguiente
fragmento de cdigo puede ver cmo se comprueba una cierta relacin,
con el operador >, entre el resultado generado por dos expresiones
aritmticas. El resultado final, de tipo Boolean, es almacenado en una
variable.
Var
Resultado: Boolean;
begin
Resultado := 2*5 > 14 Div 2; {El resultado es True }
...

4.5.3. Operadores lgicos


En ocasiones nos podemos encontrar con varios resultados de tipo
Boolean,
por
regla
general
obtenidos
de
varias
expresiones
relacinales, necesitando saber si todos ellos son True, si al menos
uno de ellos es True, etc. Esto nos permitir comprobar en un slo
paso mltiples expresiones relacinales, sabiendo si todas ellas se
cumplen, si se cumple alguna, etc.

A este tipo de expresiones, en las cuales se trabaja tan slo con los
valores True y False, se las denomina expresiones lgicas o booleanas.
Para componerlas usaremos los operadores lgicos que se muestran en la
tabla 4.4, que por regla general formarn parte de una expresin ms
compleja en la que finalmente se obtendr un valor de tipo Boolean.
Operador
Not
And
Or
Xor

Resultado que se genera


True si el operando es False o viceversa.
True si los dos operandos son True, False en caso
contrario.
True si uno de los dos operandos son True, False
si ambos son False.
True si slo uno de los dos operandos es True.
Tabla 4.4. Operadores lgicos

El operador Not es un operador unario, que ir seguido de un operando


sobre el que actuar negndolo, es decir, invirtiendo su valor. La
expresin Not True devolvera el valorFalse y, de forma anloga, la
expresin Not False devolvera True.
Los otros tres operadores son binarios, actuando sobre dos operandos
que sern facilitados a la izquierda y derecha del operador, sin
importar su orden.
4.5.4. Otros operadores
Adems de los operadores que se han englobado en las tres categoras
anteriores, Object Pascal cuenta con otros adicionales que nos
permiten, por ejemplo, concatenar dos cadenas, comprobar la existencia
de un elemento en un conjunto u obtener la direccin en la que se
almacena el valor que hay contenido en una variable.
Concatenacin de cadenas
La concatenacin de cadenas consiste en unir la secuencia de
caracteres de dos o ms cadenas para generar una sola, cuya longitud
final ser la suma de las longitudes de cada una de las cadenas que
actan como operandos. En caso de que estemos usando como destino,
para almacenar la cadena resultante, una variable de tipo ShortString,
si dicha cadena supera los 255 caracteres parte del resultado se
perder.
Para concatenar dos cadenas se utiliza el operador +, que en este caso
no actuar como operador aritmtico, sumando dos nmeros, sino como
operador de cadena. En el siguiente fragmento de cdigo puede ver cmo
se
concatenan
dos
cadenas,
representadas
mediante
constantes,
almacenndose el resultado en una variable, cuyo contenido es a
continuacin mostrado en una ventana.

Const
Cadenal = 'Cadena 1.';
Cadena2 = 'Cadena 2.';
Var
Cadena: String;
begin
Cadena := Cadenal + Cadena2;
ShowMessage(Cadena) ;
Operadores entre bits
Estos operadores son tiles cuando se necesita manipular los bits
individuales de un dato, que habr de ser necesariamente un tipo
entero. En Delphi, desarrollando un programa Windows, sern muy pocas
las ocasiones en las que se necesiten este tipo de operaciones.
Los operadores de manipulacin de bits actan de forma individual
sobre cada uno de los bits de los operandos, generando un resultado
del mismo tipo. En la tabla 4.5 se enumeran estos operadores,
indicndose la operacin que lleva a cabo cada uno de ellos. Observe
que los primeros cuatro operadores son los mismos que anteriormente
vimos para construir expresiones lgicas.
Operador
Not
And
Or
Xor
Shr
Shl

Operacin que se realiza


Inversin del valor de cada bit del operando.
Operacin lgica And bit a bit.
Operacin lgica Or bit a bit.
Operacin lgica Xor bit a bit.
Desplazamiento de los bits hacia la derecha.
Desplazamiento de los bits hacia la izquierda.
Tabla 4.5. Operadores de bits

El operador Not acta sobre un slo operando, invirtiendo el estado de


todos sus bits, de tal forma que los que estn a cero pasarn a estar
a uno y viceversa. Los tres operadores siguientes actan sobre dos
operandos, realizando una operacin lgica entre los bits de cada uno
de ellos, obtenindose un nuevo conjunto de bits que ser el
resultado. Los dos ltimos operadores tienen por finalidad desplazar
los bits del operando hacia la derecha o izquierda, para lo cual
tendremos que facilitar a la izquierda del operador el operando sobre
el que se va a actuar y a la derecha un nmero indicando cuantos bits
se van a desplazar.
Operadores de conjuntos
Ya sabemos lo que es un conjunto, cmo se define y cmo se crea una
literal de este tipo, incluyendo entre corchetes los distintos
elementos del tipo base que van a formar el conjunto. Adems del

operador de asignacin, existen otros operadores que tambin pueden


ser usados con conjuntos, permitiendo realizar operadones tales como
la unin, interseccin o diferencia.
Los operadores para trabajo con conjuntos son algunos de los que ya
conocemos como operadores aritmticos, pero al trabajar sobre
operandos de tipo conjunto actan de forma diferente. En la tabla 4.6
se enumeran estos operadores y se comenta la accin que llevan a cabo.
Operador
+
*
In

Operacin que realiza


Unin de los conjuntos.
Diferencia del primer conjunto menos el segundo.
Interseccin de los conjuntos.
Comprobacin de un elemento en un conjunto.
Tabla 4.6. Operadores para trabajo con conjuntos

Los tres primeros operadores toman dos operandos de tipo conjunto y


devuelven
uno
nuevo,
que
contendr
la
unin,
diferencia
o
interseccin, tal y como se ha indicado. El ltimo operador toma como
primer parmetro un elemento del tipo base y como segundo un conjunto,
devolviendo un valor de tipo Boolean mediante el cual se indica si
dicho elemento est o no incluido en ese conjunto.
En el siguiente fragmento de cdigo puede ver cmo partiendo de un
conjunto de das se realizan diversas operaciones, cuyos resultados
son almacenados en variables. Delante de cada expresin se ha incluido
un comentario indicando el resultado que se almacenar en la variable.
Type
{ Una enumeracin }
TDiaSemana = (Lunes, Martes, Mircoles, Jueves, Viernes,
Sbado, Domingo) ;
{ Un conjunto que tiene como base a esa enumeracin }
TDias = Set Of TDiaSemana;
Const
{ Dos constantes con tipo. La primera contiene los das de
consulta, y la segunda los dias de oficina }
Consulta: TDias = [Lunes, Mircoles, Jueves];
Oficina: TDias (Martes, Jueves, Viernes];
Var
{ Una serie de variables para almacenar los resultados }
Trabajados, SoloConsulta, Ambos: TDias;
Resultado: Boolean;
begin

{ Trabajados = Lunes, Martes, Mircoles, Jueves y Viernes }


Trabajados := Consulta + Oficina;
{ SoloConsulta = Lunes y Mircoles }
SoloConsulta := Consulta - Oficina;
{ Ambos = Jueves }
Ambos := Consulta * Oficina;
{ Resultado = False }
Resultado := Lunes In Ambos;
...
Operadores de trabajo con punteros
Object Pascal es un lenguaje muy flexible que, adems de permitir
trabajar con variables en la forma habitual existente en cualquier
otro lenguaje, tambin facilita el uso de punteros. Un puntero es una
variable especial, en el sentido de que el valor que almacena no es un
dato de nuestra aplicacin, sino una direccin de memoria en la cual
se encontrar ese dato.
Existen dos operadores que debemos conocer para poder trabajar con
punteros, que son @ y A. El primero de ellos, dispuesto delante del
identificador de una variable, obtiene la direccin de memoria en la
cual se encuentra almacenado el valor. Dicha direccin puede ser
almacenada en una variable puntero del mismo tipo que el valor. Por
ejemplo, suponga que tiene una variable de tipo Integer y desea
obtener y almacenar su direccin, para lo cual necesitar un puntero
de tipo Integer. La declaracin de este puntero y la posterior
asignacin se realizaran de la siguiente forma.
Var
N: Integer;
{ Esta variable es un puntero a un valor de tipo Integer, pero
no una variable numrica de ese tipo }
PunteroN: ^Integer;
begin
PunteroN := @N;
Observe la declaracin de la variable PunteroN. Delante del tipo,
Integer, hemos colocado el smbolo ^, lo que indica que esa variable
es un puntero a un valor de tipo Integer. Por lo tanto no podramos
asignar directamente a PunteroN un valor numrico, como s que podemos
hacer con la variable N. En la posterior asignacin se usa el operador
@ para obtener la direccin en la que almacena el valor la variable N,
asignndola al puntero.
El operador ^ nos servir en el momento en que necesitemos acceder al
valor cuya direccin est almacenada en un puntero. Suponga que desea
asignar un valor a la variable N, cuya direccin est almacenada en
PunteroN, podra hacerlo de cualquiera de las dos formas siguientes:

N := 5;
PunteroN^ := 5;
Las dos asignaciones son equivalentes y, de hecho, al asignar un valor
a N tambin lo estaremos asignando al valor a donde apunta PunteroN ya
que, en realidad, existe un slo valor entero al que estamos haciendo
referencia con dos variables.
4.5.5. Orden de prioridad
Cuando se escriben expresiones de una cierta complejidad, en la que
intervienen mltiples operadores incluso de tipos distintos, hay que
tener en cuenta un factor al que se denomina orden de prioridad o
preferencia de los operadores. Ser este factor el que determine el
orden en que se irn evaluando las diferentes subexpresiones,
generando resultados parciales que, a su vez, intervendrn como
operandos en otras expresiones, hasta finalmente generar un nico
resultado.
El orden de prioridad de los operadores de Object Pascal es el que se
indica en la tabla 4.7. Dicho orden puede ser alterado siempre que nos
interese mediante el uso de parntesis. Cualquier subexpresin que
est contenida entre parntesis ser evaluada antes que cualquier otra
que no lo est. Si existen varias subexpresiones entre parntesis,
stas sern evaluadas de izquierda a derecha. Tambin est permitido
el uso de varios niveles de parntesis, de tal forma que la evaluacin
siempre comenzar por el nivel ms interior.
Nivel

Operadores
1
2
3
4

Not, @
And, Shl, Shr, *, /, Div y Mod
Or, Xor, + y =, <, <=, >, >=, <>, in

Tabla 4.7. Nivel de prioridad de los operadores en Object Pascal.


Siempre que en una expresin existan varios operadores con el mismo
nivel de prioridad, las subexpresiones asociadas a stos sern
evaluadas de izquierda a derecha, a no ser que existan unos parntesis
que alteren este orden.
A la hora de componer una expresin compleja, tal y como se est
describiendo, hemos de tener en cuenta que la longitud mxima
permitida por Object Pascal es de 126 caracteres. Raramente
escribiremos una expresin de este tamao, pero en caso de que lo
necesitemos
nos
veremos
obligados
a
dividirla
en
varias
subexpresiones.

4.6. Estructuras de control


El cdigo de un programa no se ejecuta, por regla general, de forma
secuencial, desde la primera sentencia hasta la ltima. Lo habitual es
que en cada caso se ejecuten unas sentencias u otras, dependiendo de
ciertas condiciones, y tambin que algunas sentencias se ejecuten
cclicamente, creando bucles. Estos dos elementos, los condicionales y
los bucles son los que bsicamente nos permitirn controlar el flujo
de ejecucin de un programa.
Tradicionalmente en un entorno como DOS, el programa tena un control
absoluto del sistema y era responsable de todo el proceso por el cual
se ejecutaban unas sentencias u otras dependiendo de las pulsaciones
de teclado, o movimientos de ratn que se realizasen. En Windows y
entornos similares, es el propio sistema el que se ocupa de gran parte
del trabajo y el cdigo de nuestro programa se ejecuta cuando Windows
le transfiere el control.
Como se dijo anteriormente, la prctica totalidad del cdigo que
nosotros escribamos estar asociado a algn evento, por lo que su
ejecucin tendr lugar cuando dicho evento se produzca y no mientras
tanto. Ser en el interior de esos bloques de cdigo, procedimientos y
funciones,
en
los
cuales
nosotros
usaremos
las
siguientes
construcciones de control.
4.6.1. Condicionales
La estructura condicional por excelencia, existente en la prctica
totalidad de lenguajes de alto nivel, es la sentencia If..Then..Else.
En Object Pascal, adems, disponemos tambin de la construccin
Case..Of, de suma utilidad como veremos en un momento.
Para componer una sentencia condicional, en su versin ms simple,
tendremos que facilitar tras la palabra If una expresin cuyo
resultado sea de tipo Boolean, y tras la palabra Then una sentencia a
ejecutar en caso de que dicha expresin tenga como resultado el valor
True, o dicho de otra forma, cuando la expresin sea cierta.
Observe la siguiente sentencia condicional, muy simple, en la cual se
comprueba si el valor de una variable, llamada N, es mayor que cinco.
En caso de que la evaluacin de esta expresin d como resultado True,
porque efectivamente la variable contenga un valor mayor que cinco, se
ejecutar la llamada al procedimiento ShowMessage(), que ha sido
dispuesto detrs de la palabra Then.
If N > 5 Then ShowMessage('Invalido');
Aunque en este ejemplo se ha escrito en una sola lnea toda la
sentencia condicional, realmente una lnea lgica de cdigo no termina
hasta en tanto no se encuentre el punto y coma, por lo cual podramos
dividir la lnea anterior dejndola como se muestra a continuacin.

if N > 5 Then
ShowMessage('Invalido');
Aqu se ha usado lo que se conoce como identacin, escribiendo la
llamada a ShowMessage() algo ms adentro que la palabra If. Esto hace
que visualmente sea muy rpido darse cuenta de que esa lnea es
dependiente de la anterior y que, en este caso concreto, no se
ejecutar siempre, sino slo cuando la expresin sea cierta.
En el caso que se ha puesto como ejemplo tan slo se ejecuta una
sentencia cuando la condicin se cumple. En la prctica, es posible
que necesitemos ejecutar mltiples sentencias. En este caso tendremos
que crear un bloque, mediante las palabras Begin y End, delimitando
las sentencias que se habrn de ejecutar. A continuacin puede ver un
fragmento de cdigo en el que adems de mostrarse un mensaje, en caso
de que la condicin se cumpla, tambin se modifica el valor de N.
If N > 5 Then
Begin
ShowMessage('invalido');
N := 0;
End;
Las sentencias que en nuestro programa existan tras el condicional If
sern ejecutadas siempre, independientemente de que el resultado de la
expresin sea cierto o falso. Est claro que si detrs del cdigo
anterior escribimos cualquier otra sentencia, sta no se ver afectada
por la condicin, al encontrarse fuera del bloque.
A veces, sin embargo, puede interesamos que una o varias sentencias se
ejecuten slo en caso de que el resultado de la expresin sea falso.
Suponga que deseamos completar el cdigo de los ejemplos anteriores,
de tal forma que se muestre un mensaje si el valor es invlido y otro
cuando sea vlido. El siguiente cdigo podra parecer adecuado, pero
su funcionamiento no ser el esperado.
If N > 5 Then
ShowMessage('Invalido');
{ Esta sentencia se ejecutar siempre }
ShowMessage('Valido') ;
La segunda llamada a ShowMessage() se realizar siempre, por lo que
aun cuando N sea mayor que cinco y se haya mostrado el primer mensaje,
a continuacin se mostrar el segundo mensaje. La solucin a este
problema la encontraremos en la palabra Else, que como parte de una
sentencia condicional es la encargada de ejecutar el cdigo que le
sigue slo en caso de que la expresin haya sido False. De esta
manera, lo nico que necesitamos es realizar la modificacin
siguiente.

If N > 5 Then
ShowMessage('Invalido')
Else
ShowMessage('Valido');
Observe que se ha eliminado el punto y coma que haba tras la primera
llamada a ShowMessage(), ya que delante de la palabra Else no debe
existir punto y coma. Ahora el resultado de la ejecucin de este
cdigo s ser el esperado.
No existe ninguna restriccin en cuanto al
ir tras la palabra Then o la palabra Else,
vez otra sentencia de tipo condicional.
decisiones anidadas, como la que se muestra

tipo de sentencia que puede


por lo cual puede ser a su
Esto nos permitira crear
a continuacin.

If N > 5 Then
ShowMessage('Invalido')
Else If N > 3 Then
ShowMessage('Casi valido')
Else
ShowMessage('Valido');
Al crear construcciones de este tipo hemos de tener en cuenta que la
parte Else del condicional siempre pertenece al ltimo If que se haya
escrito, debindose delimitar adecuadamente, en caso necesario, cada
uno de los bloques a ejecutar mediante las palabras Begin y End.
Decisiones mltiples con operando comn
Cuando en
veces la
operandos,
propuesto
decisiones
Case..Of.

una sentencia condicional es necesario comprobar mltiples


misma expresin, modificando tan slo uno de los dos
como ocurre por ejemplo en el ltimo fragmento de cdigo
como ejemplo, es posible sustituir la secuencia de
anidadas por otra construccin mucho ms clara, como es

Tras la palabra Case deberemos disponer el identificador del selector,


nombre con el que se conoce al operando comn, que va a ser evaluado
respecto a mltiples operandos. A continuacin, tras la palabra Of,
crearemos una lista de valores constantes a comparar con el selector,
disponiendo tras cada uno de los elementos la sentencia a ejecutar en
caso de que la expresin sea cierta. La construccin finalizar con la
palabra End.
Al igual que con la sentencia If, Case tambin permite el uso de la
palabra Else para permitir la ejecucin de una o varias sentencias
que, en este caso, tomaran el control siempre que no se cumpliese
ninguna de las condiciones dispuestas en la lista. A continuacin
puede ver un ejemplo de uso de esta sentencia.

Case N 0f
0..3: ShowMessage('Vlido');
4, 5: ShowMessage('Casi vlido')
Else ShowMessage('Invlido');
End;
Si el valor N est comprendido entre cero y tres se mostrar el primer
mensaje, si es cuatro o cinco el segundo y en caso contrario el
tercero. Observe que el primer valor de la lista es un subrango y el
segundo una enumeracin. Obviamente tambin podemos disponer valores
simples, siempre que stos sean del mismo tipo que el selector,
debiendo ambos siempre pertenecer al grupo de los escalares.
4.6.2. Bucles
Un bucle es una estructura de control de repeticin que nos permite
ejecutar una misma sentencia mltiples veces. El nmero de veces que
se ejecuta un bucle puede ser conocido de antemano, en cuyo caso se
suele usar un bucle por contador, o bien no serlo, utilizndose
entonces un bucle condicional.
Al igual que ocurre con las sentencias condicionales que hemos
conocido en el punto anterior, podemos asociar varias sentencias a un
bucle delimitando un bloque, para lo cual dispondremos la palabra
Begin antes de la primera sentencia ejecutable y la palabra End detrs
de la ltima.
Bucles por contador
Para crear un bucle de este tipo usaremos la instruccin For,
existente tambin en otros lenguajes, como BASIC o C. A este bucle se
le llama as por estar controlado mediante una variable numrica, que
actuar como contador y cuyo identificador facilitaremos tras la
palabra For.
El nmero de veces que se repetir el bucle depender de los valores
inicial y final que asignemos al contador, sabiendo que ste se ir
incrementando o decrementando en una unidad a cada vuelta. La
estructura general de este tipo de bucle sera la siguiente:
For Contador := Inicio To Fin Do
SentenciaAEjecutar;
En caso de que el valor de inicio sea mayor que el de fin y, por
tanto,
el
contador
deba
ir
decrementndose
en
lugar
de
incrementndose, cambiaremos la palabra To por DownTo.
El contador de un bucle de este tipo debe ser necesariamente de tipo
escalar y haberse declarado como una variable local al bloque en el
que se va a ejecutar el bucle. Es decir, si vamos a crear un bucle en

el interior de un determinado procedimiento, no podremos utilizar como


contador una variable que est declarada al nivel de mdulo.
Bucles condicionales
Existen dos tipos diferentes de bucles condicionales, segn que la
expresin que va a controlar la ejecucin del bucle se evale al
principio, antes de entrar en l, o al final. Un bucle del primer tipo
tiene sentido cuando las sentencias slo han de ejecutarse en caso de
que la expresin sea cierta, de tal forma que si no es as no llegar
a ejecutarse ni una sola vez.
Un bucle en el que se compruebe la expresin al final, por el
contrario, ser ejecutado al menos una vez, ya que primero se ejecutan
las sentencias que hay en su interior y despus se comprueba si hay
que seguir o no.
La estructura del primer tipo de bucle condicional es la que se
muestra a continuacin. Como puede ver, tras la palabra While se
facilita la expresin condicional, de tal forma que mientras el
resultado sea True se estar ejecutando continuamente la sentencia a
ejecutar.
While expresin Do
SentenciaAEjecutar;
El segundo tipo se inicia con la palabra Repeat, tras la cual se
escribirn la sentencia o sentencias que van a formar parte del bucle.
Al final de ste facilitaremos la sentencia condicional, de tal forma
que el bucle terminar en el momento en que la expresin sea cierta.
Observe esta diferencia, ya que en el caso anterior el bucle se repite
mientras la expresin es cierta y en ste hasta que la expresin es
cierta.
Repeat
SentenciaAEjecutar;
Until expresin;
Control del bucle
Aunque en principio un bucle se estar ejecutando segn el nmero de
veces que se haya fijado, o bien basndose en el resultado de la
expresin condicional facilitada, el cdigo incluido en el bucle puede
alterar su ejecucin, haciendo que sta se reinicie con la siguiente
iteradn o bien que se abandone totalmente.
Mediante la instruccin Continu provocaremos que el resto de las
sentencias del bucle no se ejecuten, transfiriendo el control de nuevo
a la primera sentencia. Previamente se comprobar la condicin o se
actualizar el correspondiente contador, dependiendo del tipo de
bucle.

Desde el interior del bucle tambin podemos provocar su finalizacin,


simplemente usando la instruccin Break. Lgicamente esta instruccin,
al igual que la anterior, no ser introducida en el cdigo de un bucle
como sentencia independiente, sino que ir necesariamente asociada a
algn tipo de condicional. En el siguiente fragmento de cdigo puede
ver cmo se usan estas dos instrucciones. Suponiendo que deseamos
solicitar diez nmeros entre uno y nueve para sumarlos, hemos incluido
un condicional que permite la terminacin del bucle, en caso de que se
introduzca el valor cero, y otro que evita sumar nmeros mayores que
nueve.
Var
Contador, Dato, Suma: Integer;
begin
Suma := O;
For Contador := 1 To 10 Do
Begin
Dato := PideNumero;
{ Si el nmero es cero salimos del bucle }
If Dato = 0 Then
Break;
{ Si es mayor que nueve lo ignoramos }
If Dato > 9 Then
Continue;
{ En caso contrario lo acumulamos }
Suma := Suma + Dato;
End;
4.7. Procedimientos y funciones
Un procedimiento o una funcin es un conjunto de sentencias, de lneas
de cdigo, al cual se asigna un identificador, de tal forma que desde
cualquier otro punto del mdulo, o incluso de la aplicacin, es
posible ejecutar esas sentencias tan slo haciendo referencia al
identificador.
Tanto un procedimiento como una funcin pueden recibir parmetros que
le permitan al cdigo trabajar con los datos apropiados en cada caso.
Una funcin, adems, devuelve un parmetro mediante el cual es posible
facilitar un resultado.
Podemos decir que una funcin es un procedimiento capaz de devolver un
parmetro, siendo esa la nica diferencia entre ambos. En los puntos
siguientes se har referencia siempre a un procedimiento, pero todo es
aplicable tambin a las funciones.
4.7.1. Definicin
Para definir un procedimiento tendremos que usar la palabra Procedure,
tras la cual dispondremos el identificador por el que se va a conocer

al procedimiento. Si lo que deseamos crear es


una funcin,
utilizaremos la palabra Function en su lugar. La lnea ser terminada
con un punto y coma, que seguir al identificador.
Un procedimiento es un bloque en el cual es posible definir tipos,
declarar constantes y variables y escribir cdigo ejecutable. Los
apartados de definiciones y declaraciones se iniciarn con las
palabras Type, Const y Var que ya conocemos, mientras que el inicio
del bloque de cdigo se marcar con la palabra Begin, que ir
emparejada con su correspondiente End dispuesto al final del bloque.
Todas las definiciones de tipos y declaraciones de variables que se
efecten en el interior de un procedimiento son locales a dicho
procedimiento, por lo que no estarn accesibles desde ningn otro
punto del mdulo ni del programa. Este tema fue tratado anteriormente,
en el punto dedicado al mbito de los identifcadores.
La finalidad principal de un procedimiento es evitar la repeticin de
un cdigo que va a ser usado repetidas veces, aislndolo y asignndole
un nombre que facilite su ejecucin en cualquier punto en el que sea
necesario. Por ejemplo, imagine que est escribiendo un programa en el
que en ocasiones tiene necesidad de provocar una espera de cinco
segundos. En lugar de codificar las sentencias necesarias cada vez,
sera mucho ms eficiente la creacin del procedimiento siguiente.
{ Procedimiento que causa una espera de 5 segundos }
Procedure Espera;
Var
Ahora: Longint;
Begin
{ Tomamos el nmero de mi 11 segundos transcurridos desde el
inicio de Windows, devueltos por el procedimiento
GetTickCount }
Ahora := GetTickCount;
{ Mientras no hayan transcurrido 5 segundos }
While GetTickCount - Ahora < 5000 Do
{ estamos dando vueltas en el bucle sin hacer nada }
Continu;
y
End;
Una vez creado, un procedimiento puede ser llamado desde cualquier
punto del mdulo, si fue definido en la parte de implementacin, o
desde cualquier parte de la aplicacin, si se declar en la parte de
interfaz del mdulo. La sentencia de llamada es tan simple como la
siguiente.
Espera; { Esperamos cinco segundos }

4.7.2. Parmetros de entrada


Aunque existen procedimientos como el que acabamos de definir, cuyo
cdigo realiza siempre exactamente lo mismo en cada llamada, en muchas
ocasiones el funcionamiento del procedimiento deber adaptarse a unos
ciertos parmetros particulares, que sern facilitados en cada
llamada. Esto permite que un mismo procedimiento realice tareas
ligeramente diferentes, hacindole mucho ms flexible y til.
Por ejemplo, imagine que en su programa necesita realizar esperas de
cinco segundos, como se dijo anteriormente, pero en ciertos puntos
esas esperas deben ser de dos segundos.
Obviamente podramos definir un nuevo procedimiento, llamndole de
forma diferente, que se encargase de la nueva espera. Aunque esto
solucionara el problema en ese momento, desde luego no se trata de
una
solucin
definitiva,
porque
sera
necesario
escribir
un
procedimiento especfico para cada tiempo de espera, lo cual es
absurdo. Lo ms lgico sera enviar al procedimiento EsperaQ un
parmetro, indicndole el nmero de segundos que debe esperar.
Los parmetros que recibe un procedimiento han de declararse tras el
identificador, entre parntesis, siguiendo el mismo formato que
usaramos para declarar cualquier variable. Por tanto, tendramos que
facilitar el identificador y el tipo de cada parmetro, separando uno
de otro con un punto y coma, como si se encontrasen en lneas
distintas.
A continuacin puede ver cmo quedara el procedimiento Espera()
despus de haberle aadido un parmetro, que se utiliza en el cdigo
para controlar el fin del bucle de espera.
{ procedimiento que causa una espera de N segundos }
Procedure Espera(Segundos: Integer);
Var
Ahora: Longint;
Begin
{ Tomamos el nmero de mllisegundos transcurridos desde el
inicio de Windows, devueltos por el procedimiento
GetTickCount )
Ahora := GetTickCount;
{ Mientras no hayan transcurrido los N segundos }
While GetTickCount - Ahora < Segundos*1000 Do
{ estamos dando vueltas en el bucle sin hacer nada }
Continue;
End;
Ahora al llamar a este procedimiento tendramos que facilitar un
parmetro entero, indicando el nmero de segundos que deseamos

esperar. Este parmetro se dispondra entre parntesis, como puede ver


en la siguiente sentencia.
Espera(5); { Una espera de cinco segundos }

Parmetros por valor y por referencia


Tal y como hemos declarado nuestro procedimiento Espera(), ste recibe
un parmetro de tipo entero al que nosotros hemos llamado Segundos.
Este identificador, que en el procedimiento usamos como si se tratase
de una variable local, toma su valor automticamente, valor que es
facilitado en el momento en que se realiza una llamada al
procedimiento.
Sin embargo, lo que la variable Segundos contiene es en realidad una
copia del valor que se facilit. Obviamente en la llamada Espera(5);
lo que se pasa al procedimiento es una constante, y una copia de 5 es
5. Suponga que, por el contrario, llamamos a Espera() enviando como
parmetro una variable, a la que previamente hemos asignado el nmero
de segundos de espera.
SegundosAEsperar := 5;
Espera(SegundosAEsperar);
En este caso lo que recibe el procedimiento es una copia del contenido
de la variable, lo cual quiere decir que aunque nosotros modifiquemos
en EsperaQ el valor de Segundos, la variable SegundosAEsperar no se
ver afectada en ningn momento.
Para que un procedimiento tenga acceso a la variable que se ha pasado
como parmetro, con el fin de que pueda modificar su valor, al definir
la secuencia de parmetros que va a recibir dicho procedimiento habr
que disponer la palabra Var delante de aquellos parmetros que se
desean pasar por referencia, en forma de variables, y no por valor.
Observe la definicin del siguiente procedimiento, que recibe dos
parmetros: un entero por valor, del cual se calcular el cuadrado, y
otro entero por referencia, al cual se asignar el resultado. Si este
segundo parmetro no se hubiese pasado por referencia, la asignacin
que se realiza a Resultado no tendra sentido alguno. De esta forma,
sin embargo, esa asignacin modifica la variable que se pas
originalmente como parmetro, desde cualquier otro punto del programa.
{ Este procedimiento calcula el cuadrado del primer parmetro,
devolviendo el resultado en el segundo }
Procedure Cuadrado (Factor: Integer; Var Resultado: Integer);
Begin
Resultado := Factor * Factor;
End;

Al llamar a un procedimiento que cuenta con parmetros por referencia,


hemos de tener en cuenta que no es posible pasar una constante en su
lugar, ya que una constante no tiene una ubicacin en memoria, como
las variables. Por tanto, tendremos que declarar una variable para
poder pasarla como parmetro, tal y como se muestra a continuacin.
Var
N: Integer;
begin
Cuadrado(8, N);
Tras esta llamada la variable N contendra el valor 64, que ha sido
calculado y asignado en el procedimiento Cuadrado().

4.7.3. Parmetros de salida


Aunque, como acabamos de ver, un procedimiento puede devolver datos
mediante el uso de parmetros por referencia, siempre que es necesario
devolver un nico resultado lo normal es escribir una funcin y no un
procedimiento. Una funcin se caracteriza por devolver siempre un
valor, cuyo tipo se indica al final de la cabecera, tras el
identifcador y los parmetros, si es que existen. As, podramos
declarar una funcin llamada Cuadrado() de la siguiente forma.
Function Cuadrado(Factor: Integer): Integer;
La devoludn del valor se realiza mediante una asignacin a una
variable especial existente en toda funcin, cuyo nombre es Result.
Esta variable, que es del tipo que se ha indicado como retomo de la
funcin, puede ser usada a lo largo de todo el cdigo de la funcin
como cualquier otra variable local, sabiendo que su valor final ser
el que devuelva la funcin.
Segn esto, podramos definir la funcin y realizar una llamada tal y
como se muestra en el siguiente fragmento de cdigo. Est claro que si
una funcin necesita devolver ms de un parmetro, deber adems
utilizar la tcnica vista anteriormente de pasar parmetros por
referencia.
{ Este procedimiento calcula el cuadrado del primer parmetro,
devolviendo el resultado en el segundo }
Function Cuadrado(Factor: Integer): integer;
Begin
Result := Factor * Factor;
End;
procedure TForml.Form1Create(Sender: TObject);

Var
N: Integer;
begin
N := Cuadrado(8);
end;
5. Fundamentos de la Programacin Orientada a Objeto
5.1 Introduccin
Objetos, objetos y ms objetos, vivimos en un mundo de objetos. La
Programacin Orientada a Objetos no es nada nuevo, surgi hace ya
varios aos aunque por entonces no pudo, por sus necesidades de
potencia de computo, desplazar a la llamada programacin convencional.
Lenguajes como SIMULA y SmallTalk se consideraron entre los pioneros
en esta tendencia y comenzaron a brindar a los programadores nuevas y
deseadas caractersticas como robustez, verdadera modularidad y reuso,
as como un importante acercamiento entre el oscuro mundo de los bits
y el real mundo de los objetos. Hacia finales de los 80 el desarrollo
de la potencia de computo y la complejidad del software creci
trayendo consigo un redespertar en esta tendencia y provocando que
lenguajes de los llamados convencionales como C y Pascal se les
incluyera la posibilidad de los objetos surgiendo los llamados
Leguajes Hbridos como el popularsimo C++ y el Object Pascal motivo
de estudio en este libro.
El hecho de que muchos de nosotros trabajemos con objetos no quiere
decir que estemos programando Orientado a Objetos. Hay una diferencia
sustancial entre Programar usando objetos y Programar Orientado a
Objetos. En Visual Basic, por ejemplo, se suele trabajar con un
montn de objetos (Componentes) sin que ello signifique que estamos en
presencia de un lenguaje orientado a objetos. El lector podr
preguntarse entonces: cundo, realmente, programamos orientado a
objetos? Programamos orientado a objetos cuando somos capaces de
modelar el problema que se nos presenta en trminos de objetos y sus
relaciones. Es decir cuando cada entidad en nuestro software es un
objeto que brinda determinados servicios estrictamente definidos
siendo adems responsable de su integridad y funcionamiento ante
condiciones anormales.

5.2 Tipos de datos abstractos.


Cuando nos enfrentamos a un problema de la vida real generalmente
chocamos con la complejidad y la diversidad de esta, por lo que la
capacidad de distinguir las partes esenciales de las no esenciales se
convierte en algo extremadamente importante para que logremos xito en
nuestro propsito. Finalmente, cuando hacemos esto, obtenemos lo que
se llama un modelo abstracto del problema en cuestin y que no es ms
que el conjunto de representaciones propias de los elementos que
intervienen en la solucin de este. Es esto lo que llamamos
abstraccin.

El modelo abstracto en cuestin incluye los datos relevantes y las


operaciones identificadas que actan sobre ellos.
Vemos un ejemplo:
Suponga usted que su jefe le indica que debe realizar un programa para
controlar los empleados de su empresa. Los empleados en si encierran
muchas propiedades y de ellas unas pocas seran:
Nombre
Edad
Sexo
Fecha de Ingreso a la Empresa
Salario
Cargo
Color del pelo
Color de la piel
Estado Civil
Nmero de hijos
Usted encuentra que hay algunas que son irrelevantes para los
requerimientos del programa que su jefe le ha pedido y obtiene
finalmente un modelo abstracto de empleado que contiene aquellas y
solo aquellas propiedades que son relevantes al problema en cuestin
como pudieran ser en este caso:
Nombre
Edad
Fecha de Ingreso a la Empresa
Salario
Cargo
Por supuesto no vasta con enunciar las propiedades del empleado
abstracto sino que tambin hay que definir una serie de operaciones
inherentes a su comportamiento como podran ser: crear un empleado,
eliminar un empleado, calcular el salario atendiendo a su fecha de
ingreso y su cargo. Debes asegurarte adems que el acceso a los datos
ocurra nica y exclusivamente a travs de las operaciones definidas
garantizando con ello la integridad de estos. Por ejemplo no debe
permitirse nunca en este caso que el programador acceda directamente
al dato fecha sino que lo haga a travs de la operacin establecer
fecha que validar si la nueva fecha es aceptable.
Por tanto la estructura de datos solo puede ser accedida por medio de
operaciones definidas y al conjunto de estas operaciones se le suele
llamar interface.
Ya en la implementacin del modelo de solucin del problema se crean
instancias del tipo de datos y se llenan con datos reales.
Visto todo esto estamos en condiciones de definir formalmente lo que
en la literatura se conoce como Tipo de dato abstracto.

Llamamos Tipo de dato abstracto a una estructura de datos que es


nicamente accedida a travs de operaciones definidas.

5.3 Clases.
La Programacin Orientada a Objetos descansa en el concepto de clase.
Conceptualmente llamamos clase a un tipo de dato abstracto y su
parcial o total implementacin. Hablando menos formalmente una clase
es una plantilla que describe la representacin de un tipo de objeto y
su comportamiento, Consecuentemente, las clases definen las
propiedades y el comportamiento de conjuntos de objetos. Veamos, por
ejemplo, la declaracin de la clase Empleado atendiendo al ejemplo de
Tipo de Dato Abstracto visto anteriormente.
type
Empleado =
class
private
Nombre: string;
Edad: byte;
FechaIE: string;
Salario: real;
Cargo: string;
public
constructor Create( ANombre:string; AEdad:byte;
AFechaIE:string; ASalario:real; ACargo:string);
function CalculaSalario: real;
end;

5.4 Objetos
Ya hablamos previamente de instancias de la clase empleado y de sus
datos reales, es a estas intancias a lo que se le denomina objetos.
Un objeto es, por tanto, una instancia de la clase a la que se le
asocia un estado determinado relacionado con el valor de sus
propiedades.
En el fragmento de cdigo siguiente y a modo de ejemplo declaramos un
par de objetos (instancias) de la clase empleado:
...
var
Secretaria: Empleado;
Director: Empleado;
begin
// Creacin del objeto secretaria.
Secretaria := Empleado.Create(Neli, 20, 23/4/2000, 250.50,
Secreataria);
// Creacin del objeto director.

Director := Empleado.Create(Franklin, 27, 23/4/2000, 375,


Director)

end;
Tenemos hasta ahora dos conceptos fundamentales de la programacin
orientada a objetos, los conceptos de clase y objeto. La programacin
orientada
a objetos es entonces la implementacin de tipos de datos
abstractos, es decir, la implementacin de clases. Vale preguntarse
ahora cmo interactan los objetos?

5.5 Mensajes
En la programacin orientada a objetos un programa no es ms que una
coleccin de objetos interactuantes. Esa interaccin se produce a
travs de mensajes.
Un mensaje es un pedido al objeto de que ejecute uno de sus mtodos y
consta de nombre del objeto y nombre del mtodo a ejecutar. Un mensaje
podra ser Secretaria calclese el salario lo que en Object Pascal
sera :
...
Salario := Secretaria.CalculaSalario;
...
Donde secretaria es el nombre del objeto y CalculaSalario es el
nombre del mtodo invocado. Ver un programa como una coleccin de
objetos que interactan entre s envindose mensajes y cambiando su
estado durante la ejecucin es en extremo importante para poder
entender como funciona el paradigma de los objetos.

5.6 Relaciones
Supongamos, con propsitos ilustrativos, que queremos construir un
programa de dibujo y consideremos dos clases inicialmente, la clase
Punto y la clase crculo:

type
Punto =
class
private
x, y: real;
public
constructor Create( Ax, Ay: real );
procedure SetX( Ax: real );
// Cambia los valores de x
procedure SetY( Ay: real );
// Cambia los valores de y
end;
Crculo =
class

private
x, y, Radio: real;
public
constructor Create(
procedure SetX( Ax:
procedure SetY( Ay:
procedure SetRadio(
end;

Ax, Ay, ARadio: real );


real );
// Cambia los valores de x
real );
// Cambia los valores de y
ARadio: real ); // Cambia el valor del radio

Comparando ambas definiciones de clase notamos que las propiedades que


definen
el
punto
(x,y)
se
repiten
en
ambos
casos.
En
el
correspondiente al punto definen el punto en s y en el crculo
definen el centro. Ambas clases adems definen un procedimiento
llamado set que nos permite cambiar los valores de los datos.
Lo realmente interesante aqu es que la clase crculo aade la
propiedad radio a la definicin de punto. Es decir modelando este
problema en particular para nosotros un crculo es un punto al que
se le ha aadido un radio. Esto define lo que se llama una relacin
del tipo es un.
Desde el momento en que se define una relacin de este tipo ( B es un
A ) entonces las instancias(objetos) de la clase B tambin se
comportarn como instancias de la clase A. Para el caso de nuestro
ejemplo el crculo tambin se comportar como un punto.
En otros casos sern necesarias las relaciones del tipo es parte de.
Definamos ahora la clase de tipo rectngulo:

Type
Rectngulo =
Class
Private
VSI: Punto;
// Vrtice superior izquierdo
VID: Punto;
// Vrtice inferior derecho
public
Constructor Create( xsi, ysi, xii, yii: real );
End;

El punto VSI es parte de el rectngulo y el punto VID es parte de


el rectngulo as podemos ver que hay clases que se componen de otras.
Invirtiendo el sentido de esta relacin obtenemos entonces que el
rectngulo tiene un Punto VSI y tiene un punto VID definiendo esta
vez lo que se conoce como relacin del tipo tiene un.

5.7 Herencia
Con la herencia podemos hacer uso de la relacin del tipo es un.
Hagamos entonces que el crculo herede del punto.
...

type
Punto =
class
private
x, y: real;
public
constructor Create( Ax, Ay: real );
procedure SetX( Ax: real );
// Cambia los valores de x
procedure SetY( Ay: real );
// Cambia los valores de y
end;
Circulo =
class( Punto )
private
Radio: real;
public
constructor Create( Ax, Ay, ARadio: real );
procedure SetRadio( ARadio: real );
valores del radio.
end;

// Cambia los

// Implementacin del Punto


constructor Punto.Create( Ax, Ay: real );
begin
x := Ax;
y := Ay;
end;
procedure Punto.SetX( Ax: real );
begin
x := Ax;
end;
procedure Punto.SetY( Ay: real );
begin
y := Ay;
end;
// Implementacin del crculo
constructor Circulo.Create( Ax, Ay, ARadio: real );
begin
inherited Create( Ax, Ay );
// Se llama al constructor heredado.
Radio := ARadio;
end;
procedure Circulo.SetRadio( ARadio: real );
begin
Radio := Radio;
end;

Ntese que esta vez para definir la herencia se aade entre parntesis
a la palabra reservada class el nombre de la clase de la cual queremos
heredar y de esta manera:
Circulo =
class(Punto)

end;
La clase crculo por tanto, hereda todas la propiedades y mtodos de
la clase punto siendo innecesario rescribirlos. A nivel de objetos
ahora podemos usar el crculo como si fuese un punto:
var
C: Circulo;
begin
...
C := Circulo.Create(2,2,8);

C.SetX( 7 );
heredado del punto
C.SetY( 5 );
heredado del punto
C.SetRadio( 10 );

end.

// Se invoca al mtodo SetX


// Se invoca al mtodo SetY
//

Aadido por el Crculo

Definamos ms formalmente la herencia:


Llamamos herencia al mecanismo que permite que un objeto B herede
propiedades de una clase A. Los objetos de la clase B tienen entonces
acceso a
los atributos y mtodos de la clase A sin necesidad de
redefinirlos.
Otros trminos muy usados son los de Subclase y Superclase. Si B
hereda de A entonces A se conoce como superclase de B y B como
subclase de A. Se puede encontrar tambin en la literatura trminos
como clases padre, clases hijas y otras denominaciones.

5.8 Asignacin dinmica de memoria.


Object Pascal es un lenguaje fuertemente tipificado pues en l toda
variable ha de ser declarada antes de usarse. Ello implica que al
declarar la variable automticamente el compilador reserva espacio
para ella. La declaracin:
var
i: integer;

tendr como resultado que se reserve el espacio correspondiente a un


entero y se enlace el nombre i a un tipo integer. Todo esto le
brinda al compilador la facilidad de chequear la consistencia de los
tipos de datos antes de la ejecucin. Una expresin como esta sera
declarada ilegal por el compilador:
...
i := cadena;
...
por estar asignando a i un tipo de dato incompatible con el integer.
A este tipo de asignacin de memoria es a la que se le llama
asignacin esttica.
Por otro lado existen lenguajes de programacin que no obligan a
declarar las variables antes de usarlas permitiendo introducirlas
cuando se necesiten. As cuando tecleamos:
i = 4
el interprete es capaz de darse cuenta que como a la variable i se
esta asignando un entero, el tipo de i debe ser entero por tanto
estos casos el tipo de i se conoce en el momento en que su valor
establecido. A este tipo de asignacin de memoria es a la que se
llama asignacin dinmica.

le
en
es
le

5.8 Polimorfismo
El polimorfismo le permite a una entidad ya sea una variable, una
funcin u objeto, adoptar una variedad de representaciones. Un ejemplo
sencillo de polimorfismo en variables ocurre en un lenguaje que no es
fuertemente tipificado cuando utilizamos las siguientes sentencias:
...
i = 49
...
i = i + 1
I = casa

rem utilizamos a i como un nmero entero.

rem cambiamos a cadena.

Para las funciones ocurre cuando tenemos una funcin que realiza
diferentes tareas bajo un mismo nombre. A esto se le suele llamar
sobrecarga de funciones, veamos un ejemplo.
Supongamos que tenemos una funcin rea que calcula el rea de un
crculo. El cdigo del ejemplo est escrito atendiendo a la sintaxis
de c++ por ser este un lenguaje que soporta sobrecarga de funciones.

double area(double radio )


// El tipo de datos double equivale a un
nmero real.
{
return (3.14*radio*radio);
};

y luego una funcin rea ms


rectgulo:

adelante que calcula el

rea de un

...
double area( double a, double b )
{
return a * b;
};
Debido a que la lista de parmetros de la funcin es diferente el
compilador puede deducir el uso correcto de la funcin chequeando los
tipos reales de estos.
...
double ac;
double ar;

ac = area( 4.6 );
correspondiente al crculo.
ar = area( 6.8, 90 );
correspondiente al rectngulo.
...

// Se usa la funcin rea


// Se usa la funcin rea

En el caso de los objetos el polimorfismo permite que un objeto escoja


los mtodos correctos. Definamos una nueva funcin llamada rea para
las clases Punto y Circulo:
type
Punto =
class

public

function area: real;


end;
type
Circulo =
class( Punto )

public

function area: real;


end;

function Punto.area;
begin
Result := 0;
end;
...

virtual;

override;

function Circulo.area;
begin
Result := 3.14*Radio*Radio;
end;
...
La inclusin de la palabra virtual a continuacin de la funcin area
del punto significa que el cdigo de dicha funcin se anexar en
tiempo de ejecucin del programa. Lo mismo ocurre con lo herederos
de la clase punto que reimplementen esa funcin haciendo uso de la
sentencia override. Sin una declaracin del tipo virtual en este caso
sera imposible ejecutar un cdigo como este:
...
var
i: byte;
P: Punto;
C: Circulo;
List: TList;
begin
P := Punto.Create(2,2);
C := Circulo.Create(3,3,10);
List := TList.Create;
List.Add( P );
List.Add( C );
for i := 0 to List.Count - 1 do
begin
writeln( Punto(List.Items[i]).Area );
end;
readln;
end.
Ntese que para este ejemplo hemos utilizado la clase TList incluida
en la unit classes de la versin 5.0 de Delphi que permite manipular
una lista polimrfica (Objetos diferentes) y que contiene una
propiedad llamada items por la que se puede acceder a los objetos en
su interior mediante un ndice (Ejemplo: List.Items[1] accede al
objeto # 1). A la lista se le han insertado mediante el mtodo
List.Add
un
objeto
Punto
y
uno
Crculo.
La
lnea
writeln(
Punto(List.Items[i]).Area ); es la que exhibe el comportamiento
polimrfico. Cuando en la ejecucin se recorre la lista primero se
imprimir 0 que es el resultado de invocar la funcin area del punto y
luego 314 como resultado de invocar la funcin rea para el circulo.
La sentencia Punto( List.Items[i].Area ) hace lo que se llama una
reinterpretacin de tipos permitiendo que todo objeto de la lista se
interprete como una instancia de Punto o descendiente de este en el
rbol jerrquico.
El Polimorfismo es entonces en trminos de objetos la posibilidad de
que la variable que representa la instancia (en el ejemplo anterior

List.Items[i] ) represente a objetos de diferentes tipos todos creados


mediante una definicin esttica.
6. Manipulacin de componentes
6.1. Introduccin
En los tres captulos anteriores, dedicados al entorno, los elementos
de un proyecto y el lenguaje Object Pascal, hemos adquirido todos los
conocimientos necesarios para comenzar a desarrollar programas con
Delphi.
Ya sabemos cmo crear un proyecto y gestionar los elementos contenidos
en l. Tambin hemos aprendido a gestionar los componentes de un
formulario, editar propiedades y escribir el cdigo asociado a los
eventos. Para escribir este cdigo utilizaremos el lenguaje Object
Pascal, cuyos fundamentos tambin hemos conocido.
Lo nico que nos falta, por tanto, es ir tratando los diferentes
componentes con que cuenta Delphi, conociendo la finalidad de cada uno
de ellos, sus propiedades, eventos y mtodos. Sin embargo, antes de
proceder con este trabajo, que abordaremos en el prximo captulo,
vamos a tratar en el presente las generalidades comunes a la mayor
parte de los componentes Delphi.
De lo que se trata en este captulo es de conocer las propiedades ms
habituales, los eventos y los mtodos que estn disponibles en
prcticamente todos los componentes. Esto nos permitir, por una
parte, aprender a utilizar cualquier componente con una gran facilidad
y, por otra, nos evitar tener que repetir los mismos conceptos con
cada componente.
6.2.Tipos de componentes
En una aplicacin Delphi es posible utilizar tanto componentes Delphi,
conocidos como VCL, como componentes ActiveX, tambin llamados OCX o
componentes OLE. En la etapa de diseo, mientras estamos trabajando
con los componentes en el formulario no notaremos diferencia alguna
entre unos componentes y otros.
Existe una diferencia fundamental entre un componente VCL y un
ActiveX, y es que mientras el cdigo del primero pasa a formar parte
del ejecutable que genera Delphi, con lo cual el componente est
incluido en la propia aplicacin, el segundo se mantiene en un archivo
separado, con extensin OCX o DLL, que es necesario distribuir e
instalar junto con la aplicacin. La mayor parte de los componentes
que encontraremos en la Paleta de componentes de Delphi son del tipo
VCL.
6.3. Instalacin de un componente

Adems de los componentes que encontramos en el entorno de Delphi una


vez completada la instalacin, es posible aadir cualquier otro
componente que nos interese utilizar. Hay miles de componentes
freeware y shareware que podemos instalar en Delphi.
El proceso de instalacin de un componente es muy simple y se inicia
seleccionando la opcininstall component del men Component. En la
ventana que aparece, similar a la mostrada en la figura 6.1,
pulsaremos el botn Browse para seleccionar el mdulo en que se
encuentra el componente.

Figura 6.1. Instalacin de un nuevo componente


Si el componente a instalar es ActiveX, entonces usaremos la opcin
Import ActiveX control, que dar paso a la ventana mostrada en la
figura 6.2. En la lista que ocupa la parte superior aparecen todos los
controles ActiveX registrados en el sistema. Bastar con seleccionar
el que deseamos instalar para que debajo aparezcan los nombres de
clase. Aunque inicialmente estos componentes se alojarn en la pgina
ActiveX de la Paleta de componentes, podemos indicar cualquier otra
pgina como destino.

6.4. Propiedades
Desde el punto de vista del usuario de un componente, que es el
nuestro, las propiedades son como los miembros de un registro, es
decir, son elementos pertenecientes a un objeto. Por tanto, para
acceder a una propiedad de un componente usaremos la notacin que ya
conocemos, en la cual el punto acta como separador entre el nombre
del componente y el de la propiedad.
Aunque la mayora de las propiedades son de lectura y escritura,
existen algunas que son de slo lectura y, ms raramente, algunas de
slo escritura. Tambin hay que distnguir entre las propiedades que

estn disponibles tanto en la fase de diseo como en ejecucin y


aquellas que tan slo lo estn en ejecucin, no apareciendo en el
Inspector de objetos mientras estamos diseando. Por regla general,
las propiedades de slo lectura estn disponibles slo en ejecucin.

Figura 6.2. Instalacin de un control ActiveX


6.4.1. Acceso a los miembros de un objeto
Cuando es necesario acceder desde el cdigo de un programa a mltiples
propiedades, eventos o mtodos de un mismo componente, en lugar de
disponer repetidamente el nombre de ste, seguido de un punto y el
identificador que corresponda, podemos utilizar la sentencia With.
Esta sentencia nos permite ahorrar bastante "tecleo", ya que
disponiendo tras ella el identificador de un objeto, ya sea componente
o un registro, podemos a continuacin hacer referencia a sus miembros
sin necesidad de volver a escribir el nombre de dicho objeto.
Utilizando la sentencia With, el fragmento de cdigo del captulo
anterior en el que se asignaban valores a varios miembros de un
registro, llamado UnaFicJia, quedara de la forma siguiente:
var
UnaForm: TFormAgenda;

Begin
With UnaForm Do
Begin
Nombre := 'Pedro Garca';
Direccion := 'Avda. de la Paz, 24';
Telefono := '348123';
Personal := True;
End;
6.4.2. Posicin y dimensiones del componente
Tal y como se comentaba al principio de este captulo, vamos a conocer
a continuacin las propiedades ms habituales de \a mayora de los
componentes, lo que nos permitir, en captulos posteriores, tratar
los elementos especficos de cada componente sin necesidad de repetir
varias veces lo mismo. Comencemos tratando las propiedades en las que
se almacena la informacin de posicin y dimensiones del componente.
Todos los componentes estn colocados en una determinada posicin del
formulario, incluso aquellos que en ejecucin no estarn visibles. La
posicin de un componente se almacena en las propiedades Left,
columna, y Top, fila. El contenido de estas dos propiedades ser un
nmero entero cuya unidad de medida es el punto de pantalla, que
contiene la coordenada horizontal y vertical, respectivamente, en que
se haya situado el componente. Estas coordenadas son relativas al
espacio o superficie del formulario, en el cual el punto 0,0 es la
esquina superior izquierda.
Los componentes visuales, a los que se conoce como controles, adems
de una posicin tambin cuentan con un tamao, segn el cual ocupan un
espacio ms o menos amplio en el formulario. El ancho y alto del
control, expresado tambin en (puntos, se almacena en las propiedades
Width y Height, respectivamente.
Cuando en la fase de diseo se mueve o modifica el tamao de un
componente,
automticamente
se
actualiza
el
contenido
de
las
propiedades que se acaban de citar. De igual forma, puede editar el
contenido de estas propiedades, en el Inspector de objetos,
modificando la posicin y las dimensiones del componente.
Aunque el punto en el que aparece un control y su tamao es algo que
se suele fijar durante el diseo, tambin podemos alterar estas
propiedades durante la ejecucin. De esta forma, con una simple
asignacin,
podemos
establecer
la
posicin
y
dimensiones
del
componente.
En caso de que la aplicacin que se desarrolla vaya a utilizarse en
distintos sistemas, usando diferentes resoluciones de pantalla, adems
de unas dimensiones fijas, facilitadas en las propiedades Width y
Height, tambin pueden establecerse unos lmites de tamao. Esta es la
finalidad de la propiedad Constraints que, como ver en el Inspector

de objetos, cuenta con cuatro subpropiedades: MaxHeight, MaxWidth,


MinHeight y MinWidth. Las dos primeras contendrn el alto y ancho
mximos, mientras que las segundas indicarn el alto y ancho mnimos.
Por defecto los controles no cambian de tamao automticamente, por lo
que en principio el contenido de la propiedad Constraints no parece
ser de mucha utilidad. Ser en combinacin con la propiedad Anchors
cuando encontremos el sentido. Dicha propiedad es un conjunto que
puede
tener
los
valores
akLeft,
akTop,
akRight
y
akBottom,
especificando los puntos a los que estar "anclado" el control. Por
defecto los controles se anclan de forma relativa a su lado izquierdo
y el margen superior, es decir, la propiedad Anchors contiene los
valores akLeft y akTop. Esto provoca que mantenga fija su posicin en
el interior del formulario, a pesar de que las dimensiones de ste se
modifiquen arrastrando la esquina superior izquierda. Si damos el
valor True a las subpropiedades akRight y akBottom de Anchors
anclaremos el control de forma relativa tambin a los otros de
mrgenes del contenedor, de tal forma que al cambiar su tamao
automticamente se redimensiona tambin el control, utilizndose como
valores lmite los entregados en la propiedad Constraints.
El formulario, al ser un componente visual, cuenta tambin con las
propiedades que se acaban de explicar, incluidas Constraints y
Anchors.
6.4.3. Ttulos, colores y tipos de letra
Todos aquellos componentes que cuentan con un ttulo, como puede ser
el formulario, un botn, un grupo, etc., disponen de una propiedad
llamada Caption en la que se almacena una cadena de caracteres
conteniendo dicho ttulo. Esta propiedad es de lectura y escritura y
podemos acceder a ella tanto durante el diseo como durante la
ejecucin. Asignando un valor a la propiedad Caption de un formulario,
por poner un ejemplo, alteraremos el ttulo que aparece en la barra de
ttulo de la ventana.
El color que se utiliza para el fondo de los controles es un aspecto
tambin configurable, gracias a la propiedad Color. Esta propiedad
almacena un valor de tipo TColor, mediante el cual podemos obtener o
fijar el color que nos interese.
Existen una serie de constantes ya definidas representando a los
colores ms habituales. Si queremos que nuestro formulario tenga el
fondo blanco, por ejemplo, no tenemos mas que asignar el valor clWhite
a la propiedad Color, ya sea durante el diseo o la ejecucin.
La mayora de los sistemas actuales son capaces de representar miles e
incluso millones de colores para los cuales, obviamente, no existe una
constante definida. Podemos componer cualquier color durante la
ejecucin mediante la macro RGB, a la que pasaremos tres parmetros
enteros indicando la intensidad d rojo, verde y azul. Cada uno de los
componentes del color podr tener una intensidad comprendida entre O y

255, permitindonos as crear ms de diecisis millones de colores o


tonalidades diferentes.
Durante el diseo tambin podemos acceder a toda la paleta de colores
disponible. Para ello, en lugar de seleccionar uno de los valores de
la lista desplegable, haremos doble clic en el valor de la propiedad
Color, en el Inspector de objetos, lo que causar la aparicin de una
ventana de seleccin de color.
En caso de que el componente con el que estamos trabajando disponga de
una propiedad Caption oText, habitualmente tambin contar con una
propiedad llamada Font que sirve para seleccionar el tipo de letra a
utilizar. La propiedad Font es en s misma un objeto y, como tal,
cuenta con una serie de propiedades, que se enumeran en la tabla 6.1.
En el Inspector de objetos podemos acceder a estas propiedades de la
forma que se explic en el captulo 2, desplegando las subpropiedades
de Font. En ejecucin la propiedad Font ser un objeto con otras
propiedades, por lo que para acceder a ellas usaremos el operador de
cualificacin, el punto, o bien la sentencia With vista anteriormente.
Propiedad

Contenido

Color
Height

Color del texto.


Altura de la letra.
Nombre del tipo o
fuente.
Tipo de espaciado.
Tamao en puntos.
Estilo.

Name
Pitch
Size
Style

Tabla 6.1. Propiedades de un objeto TFont


La propiedad Style es un conjunto mediante el cual es posible definir
el estilo para el texto. Este conjunto puede contener los valores
fsBod, fsitalic, fsUnderline y fsStrikeQut, activando el estilo de
negrita, cursiva, subrayada o tachada, respectivamente.
6.4.4. Estado visual y de acceso
Un componente
varios estados
aunque en modo
estar activo o
l.
Mediante la
visibilidad
conteniendo
Bastar dar

visual, un control, puede aparecer en ejecucin en


diferentes. De principio puede estar o no visible,
de diseo siempre sea visible. Adems el control puede
no, segn lo cual el usuario podr interactuar o no con

propiedad Visible podemos saber y alterar el estado de


de un control. Esta propiedad es de tipo Boolean,
el valor True en caso de que el control sea visible.
el valor False para hacerlo no visible. |

La propiedad Enabled tambin es de tipo Boolean y es la que determina


si el control est o no accesible para el usuario del programa. El
valor True, que es el que esta propiedad toma por defecto, indica que
el control est activo. Por regla general, aquellos controles que no
estn accesibles se muestran en la ventana de forma diferente, por
ejemplo con un color de texto ms claro.
6.4.5. Orden de acceso a los controles
Cuando en una ventana existen mltiples controles, normalmente el
usuario puede pasar de unos a otros mediante la tecla <Tab>. Es el
programador, usted, el que establece, normalmente durante el diseo,
cual ser el orden de acceso a esos controles.
La propiedad TabOrder, con la que cuentan todos los controles capaces
de tener el foco de entrada de Windows, contiene un entero comprendido
entre cero y el nmero de controles de ese tipo existentes en el
formulario menos uno. Cuando la ventana sea mostrada el foco lo tendr
aquel control que tenga el TabOrder cero y, al pulsar la tecla <Tab>,
se pasar el foco al control siguiente segn el valor de esta
propiedad.
A medida que se van insertando controles en un formulario, Delphi va a
asignando
automticamente
los
valores
oportunos
a
la
propiedadTabOrder, de tal forma que, inidalmente, el orden de acceso a
los controles en ejecucin ser el orden en que se han insertado en el
formulario en la fase de diseo. Podemos modificar este orden
alterando el contenido de la propiedad TabOrder directamente o bien
usando la opcin Tab Order del men emergente del formulario. AI
seleccionar esta opcin aparecer una ventana como la que se muestra
en la figura 6.3, en la que mediante el ratn podremos fcilmente
establecer el orden de acceso.
No todos los controles del formulario tienen por qu estar accesibles
en la forma que se ha descrito, de forma secuencial mediante la tecla
<Tab>. Dando el valor False a la propiedad TabStop podemos excluir
cualquier control de la secuencia de acceso.

Figura 6.3. Orden de acceso a los controles de un formulario


6.4.6. Contenedores y contenidos acoplables
En un captulo previo vimos que algunas ventanas del entorno de
Delphi, como el Explorador de cdigo o el Inspector de objetos, podan
ser acopladas dentro de otras, como el Editor de cdigo. Esta
mecnica, en la que unas ventanas actan como contenedores de otras
que son contenidas de forma acoplada, puede ser usada tambin en
nuestras propias aplicaciones.
Para que una ventana o un cierto control acte como contenedor de
ventanas acopladas es necesario dar el valor Truc a la propiedad
DockSite. Disponen de esta propiedad el formulario y los controles que
son capaces de actuar como contenedores, como puede ser TPanel.
Cualquier ventana o control que pueda ser acoplado en un contenedor
deber asignar el valor dkDock a la propiedad DragKind y el valor
dmAutomatic a la propiedad DragMode. Slo con esto el control podr
ser arrastrado, durante la ejecucin, de un contenedor a otro o del
interior de un contenedor a una ventana independiente.
6.5. Eventos
Los eventos, al igual que las propiedades, son miembros de un objeto,
concretamente de un componente y, por tanto, es posible acceder a
ellos de igual forma, disponiendo el identificador del componente, el
operador de cualificacin y el identificador que corresponde al
evento, al que es posible asignar un valor. La diferencia entre una
propiedad y un evento es que este ltimo contiene referencias a
procedimientos y no valores enteros, cadenas o conjuntos.

La referencia al procedimiento que se almacena en un evento es usada


en un determinado momento, cuando se produce ese evento, para realizar
una llamada, lo que permite que nuestro programa ejecute el cdigo que
proceda. No todos los eventos son iguales y, por ello, los
procedimientos que utilicemos para responder a un evento tampoco lo
sern. La diferencia siempre la encontraremos en los parmetros que
toma dicho procedimiento.
Todos los procedimientos asociados a eventos reciben, como primer
parmetro, un objeto TObject llamado Sender. Esta variable es una
referencia al objeto que ha generado el evento, variable que podemos
usar para acceder a sus propiedades, eventos y mtodos. La existencia
de este parmetro permite que un mismo procedimiento sea usado por
mltiples eventos de distintos objetos.
El tipo de evento ms habitual es TNotifyEvent, que se caracteriza por
no tomar ningn parmetro adicional al que se acaba de describir. En
los puntos siguientes conoceremos algunos de los eventos ms comunes.
6.5.1. El evento OnClick
ste es el evento ms comn que podemos encontrar, existiendo en la
mayora de los controles. Se produce al realizarse una pulsacin, que
puede venir del ratn o del teclado. Cada vez que se pulsa el botn
izquierdo del ratn sobre cualquier punto del formulario, se elige una
opcin de men, se pulsa la barra espadadora o la tecla <Intro> sobre
un botn, etc., se genera un evento OnClick.
Al igual que otros muchos eventos, ste es de tipo TNotifyEvent, por
lo que tan slo recibe el parmetro Sender comentado en el punto
anterior.
6.5.2. Eventos de ratn
El ratn es sin duda el dispositivo de entrada por excelencia en
Windows, ya que mediante l es posible controlar prcticamente la
totalidad de las funciones de una aplicacin, si exceptuamos la
entrada de datos tales como textos. Cada vez que movemos el ratn,
pulsamos o liberamos cualquiera desus botones estamos generando un
evento.
E1 evento OnMouseMove lo recibe un control cuando el puntero del ratn
se est desplazando sobre l. Este evento, de tipo TMouseMoveEvent,
cuenta con tres parmetros adicionales mediante los cuales podemos
saber el estado de ciertas teclas especiales, como <Mays>, <Control>
o <Alt> y la posicin del puntero del ratn, relativa al rea del
control que recibe el evento.
Al pulsar y liberar un botn cualquiera del ratn se Generan dos
eventos,
llamados
OnMouseDown
y
OnMouseUp.
Ambos
son
de
tpoTMouseEvent y adems de los parmetros comentados para el evento

anterior reciben tambin


cual podemos saber cual ha
tomar los valores mbLeft,
botn izquierdo, derecho o

un parmetro, llamado Button, mediante el


sido el botn pulsado. Este parmetro puede
mbRight o mbMiddIe, segn que se trate del
medio.

El ltimo evento asociado exclusivamente al ratn es OnDblClick, que


se produce cuando se hace doble clic sobre un componente con el botn
izquierdo del ratn. Este evento es de tipo TNotifyEvent, no
disponiendo, por tanto, de ningn parmetro adicional.
Una sola actuacin sobre el ratn puede generar mltiples eventos. Ha
de tenerse en cuenta que al pulsar el botn izquierdo del ratn sobre
el formulario, por ejemplo, adems del evento OnMouseDown, de
pulsacin y el evento OnMouseUp, de liberacin, tambin se generar un
evento OnClick.
6.5.3. Eventos de teclado
Algunos controles, como el formulario o el componente TEdit, tienen la
capacidad de recibir eventos tambin del teclado. Estos eventos nos
permiten, por ejemplo, interceptar las pulsaciones de tecla evitando
la introduccin de caracteres invlidos.
Cada vez que se pulsa una tecla que se corresponde directamente con un
carcter, como puede ser una letra, nmero, signo de puntuacin, la
tecla <Intro>, etc., se genera un evento OnKeyPress. El procedimiento
que aseciemos a este evento recibir un parmetro de tipo Char,
llamado Key, conteniendo el carcter pulsado. Este parmetro se recibe
en forma de variable, lo que nos permite modificarlo en el
procedimiento.
Existen muchas teclas que no generan un evento OnKeyPress, porque no
estn asociadas a un carcter. Entre estas teclas estn, por ejemplo,
las de funcin y las de edicin, como <Insert> o <Supr>. Estas teclas,
al igual que las que s generan un evento OnKeyPress, siempre generan
un evento OnKeyDown al ser pulsadas y un evento OnKeyUp al ser
liberadas. Estos eventos tambin reciben un parmetro llamado Key,
aunque en este caso de tipo Word. Este parmetro contiene lo que se
conoce como cdigo virtual de tecla, un cdigo nico que nos permite
saber qu tecla es la que se ha pulsado. Existen una serie de
constantes definidas para representar a los cdigos virtuales de
tecla, que podr encontrar en la ayuda que Delphi incorpora sobre la
API de Windows. Adems se recibe otro parmetro, llamado Shift,
mediante el cual podremos saber si estn pulsadas las teclas <Mays>,
<Control>, <Alt> o alguno de los botones del ratn.
6.5.4. Otros eventos
Anteriormente se describi el mtodo por el cual era posible pasar de
un control a otro, mediante la tecla <Tab>, haciendo activo uno de los
controles del formulario. Tambin podemos dar el foco de entrada a un

control seleccionndolo directamente, mediante el ratn o una tecla de


acceso rpido.
Cada vez que un control se convierte en el componente activo del
formulario, ste recibe el evento OnEnter. De igual forma, el control
que deja de estar activo recibe el evento OnExit. Ambos eventos son de
tipo TNotifyEvent, lo que significa que no cuentan con ningn
parmetro adicional.
Una de las operaciones ms habituales en Windows es la de arrastrar y
soltar, tcnica por la cual es posible copiar un archivo, abrir un
programa con un cierto documento, eliminar un cierto elemento, etc.
Nuestros programas Delphi tambin pueden realizar operaciones de
arrastrar y soltar, existiendo mltiples eventos relacionados con
ello.
Cuando se inicia una operacin de arrastrar y soltar, el control que
va a ser arrastrado recibe un evento OnStartDrag, que se puede
utilizar para permitir o no tal operacin. A
medida que el
control va siendo arrastrado, todos los controles sobre los que se va
desplazando reciben un evento OnDragOver.
Respondiendo adecuadamente a este evento cada control puede indicar,
mediante el cambio del icono del cursor, si permite o no que el objeto
sea soltado sobre l. En el momento en que finalmente el objeto es
soltado, el control sobre el que se ha soltado recibe un evento
OnDragDrop, mientras que el control que se arrastr recibe un evento
OnEndDrag.
6.6. Mtodos
Un mtodo es un procedimiento o funcin perteneciente a un objeto, en
este caso a un componente. Por tanto, para llamar a ese mtodo es
necesario especificar primero el nombre del objeto al que pertenece,
de igual forma que lo hacemos al acceder a una
propiedad o a un evento. Conozcamos los mtodos ms comunes,
existentes prcticamente en todos los componentes.
Anteriormente conocimos una propiedad, llamada Visible, mediante la
cual podamos saber si un cierto control estaba visible o no, as como
modificar ese estado. Los componentes que disponen de esta propiedad
tambin cuentan habitualmente con los mtodos Show() y Hide(), que nos
permiten mostrar y ocultar, respectivamente, el control de igual forma
que si asignsemos los valores True o False a la propiedad Visible.
Tambin en un punto anterior hablbamos sobre el orden de acceso a los
controles de un formulario y cmo pasar el foco de entrada, haciendo
activo un determinado control, mediante la tecla <Tab>. Todos los
controles cuentan con un mtodo, llamado CanFocus(), que nos permite
saber si ese control puede tomar o no el foco de entrada. Si este
mtodo devuelve el valor True eso quiere decir que el control puede

tomar el foco, caso ste


<Tab>, una pulsacin de
mtodo SetFocus(). Este
nosotros deseemos y la
continuacin.

en que podemos acceder a l mediante la tecla


ratn o bien mediante cdigo, llamando al
ltimo mtodo hace activo el control que
llamada es tan simple como se muestra a

Button1.SetFocus;
Los controles en un formulario cuentan, adems de con una posicin y
unas dimensiones, con un orden en el eje Z o de profundidad, segn el
cual al superponer dos o ms controles unos aparecen sobre otros. Este
orden, establecido en modo de diseo, puede ser modificado en
ejecucin mediante los mtodos BringToFront() y SendToBack(). El
primero de ellos lleva el control al primer nivel, situndolo sobre
todos los dems, mientras que el segundo tiene el efecto contrario, y
sita el control debajo de todos los dems.
7. Componentes ms habituales
7.1. Introduccin
Los primeros cinco captulos de esta gua han servido para sentar las
bases necesarias para comenzar a desarrollar programas con Delphi. En
este captulo vamos a conocer los componentes ms habituales de
Delphi, aquellos que se utilizan con ms frecuencia en la mayora de
las aplicaciones.
Partiendo de que ya conocemos las propiedades, eventos y mtodos ms
comunes, cuya existencia o disponibilidad podemos comprobar en el
Inspector de objetos y ayuda de Delphi, acometeremos directamente las
particularidades de cada uno de los componentes, tras lo cual se
propondr un ejemplo prctico de su uso.

7.2.Trabajar con el formulario


Uno de los componentes ms importantes, existente por regla general en
todas las aplicaciones, es el formulario, que representa a la ventana
en la que desarrollar la acdn del programa. Este componente no
tenemos que insertarlo, forma parte de los elementos del proyecto y ya
en un captulo anterior aprendimos a crear nuevos formularios,
seleccionarlos del Depsito de objetos, etc.
El formulario acta como un contenedor en el que podemos insertar
componentes. Algunos de estos componentes pueden, a su vez, ser
contenedores, almacenando otros componentes. Veamos en los siguientes
puntos cules son los apartados principales que debemos conocer acerca
de los formularios.
7.2.1. Aspectos visuales del formulario

El formulario es un elemento visual, una ventana, que cuenta con un


ttulo, unos botones en la parte superior, un borde, un color de
fondo, etc. Todos estos elementos tienen su correspondencia en una
serie de propiedades, algunas de las cuales ya conocemos. El ttulo
del formulario se almacena en la propiedad Caption, su posicin en las
propiedades Left yTop, sus dimensiones en Width y Height, su estado en
Visible y Enabled, el color de fondo en la propiedad Color y el tipo
de letra en la propiedad Font.
El resto de los aspectos visuales de un formulario encuentran su
reflejo en otras propiedades, cuyos valores y funcionamiento vamos a
conocer a continuacin.
Botones de la ventana
Los botones que aparecen en la parte superior del formulario, cuya
finalidad es facilitar ciertas operaciones como cerrar la ventana,
maximizarla o minimizarla, pueden o no aparecer dependiendo del valor
que asignemos a la propiedadBorderIcons.
Esta propiedad es un conjunto, que puede contener ninguno, uno, varios
o todos los valores que se muestran en la tabla 7.1. Para evitar que
aparezcan los botones de maximizar y minimizar, deberemos excluir las
constantes biMinimize y biMaximize del conjunto, ya que excluyendo
slo una de ellas, los botones aparecern, aunque el que se ha
excluido aparecer desactivado.
Constante
biMinimize
biMaximize
biSystemMenu
biHelp

Icono que representa al


botn
Minimizar
Maximizar
Cerrar y men de sistema
Ayuda

Tabla 7.1 Valores del conjunto BorderIcons


El icono correspondiente al botn de ayuda, representado por un signo
de interrogacin, slo es mostrado en caso de que no estn visibles
los de maximizar y minimizar.
Borde de la ventana
El rea o espacio que ocupa el formulario en pantalla se encuentra
delimitada por un borde que, adems de ser un elemento meramente
visual cuya finalidad es trazar esos lmites, tambin desempea otras
funciones, ya que dependiendo del tipo de borde que tenga el
formulario, en ejecucin ser posible o no modificar su tamao.
Al igual que los botones, el tipo de borde es un elemento que se suele
establecer en modo de diseo, seleccionando en el Inspector de objetos

el valor adecuado para la propiedad BorderStyle. Los valores posibles,


enumerados en la tabla 7.2, aparecern en la lista desplegable. Al
modificar esta propiedad, al igual que ocurre con Bordericons, no
observaremos cambio alguno en el formulario en modo de diseo, ser al
ejecutar el programa cuando aparezca el tipo de borde seleccionado.
Constante
bsNone
bsSingle
bsSizeable
bsDialog
bsToolWindow
bsSizeToolWin

Tipo de borde
Sin
borde.
La
ventana
no
puede
ser
redimensionada, adems no tendr barra de ttulo
ni botones en la parte superior.
Borde simple que no permite redimensionar.
Borde grueso que permite redimensionar.
Borde grueso que no permite redimensionar.
Borde simple que no permite redimensionar y que
cuenta con una barra de ttulo ms pequea.
Borde grueso que permite redimensionar y que
cuenta con una barra de ttulo ms pequea.

Tabla 7.2. Posibles valores para la propiedad BorderStyle

Los estilos bsToolWindow y bsSizeToolWin estn enfocados a la creacin


de ventanas especiales, como cajas de herramientas o paletas
flotantes. Se caracterizan porque la barra de ttulo es ms estrecha
que la normal.
Estilo del formulario
Cada vez que se inicia un nuevo proyecto o se aade un formulario con
la opcin New Form, el formulario creado tiene el estilo normal o por
defecto, representado por la constante fsNormal. Este estilo de
formulario es el de una ventana independiente, que no acta como
contenedor de otras ni est contenida en otra ventana, que adems es
solapable, es decir, que puede ser ocultada total o parcialmente por
otras ventanas.
La propiedad FormStyle es la que determina el estilo del formulario y,
como se acaba de decir, el valor por defecto que toma es fsNormal.
Adems de ste, esta propiedad puede tomar tres valores ms.
El estilo fsStayOnTbp nos ser til cuando deseamos crear una ventana
que siempre se visualizar sobre todas las dems, no siendo posible
ocultarla. Por regla general, las ventanas que cuentan con este estilo
estn en pantalla durante un breve espacio de tiempo, por ejemplo
mostrando una presentacin de entrada al programa.
Los otros dos estilos existentes sonfsMDIForm yfsMDIChild, cuya
finalidad es permitir la creacin de aplicaciones MDI. El trmino MDI
(Mltiple Document Interface/nteraz de documento mltiple) hace

referencia a un tipo de aplicacin muy comn en Windows, compuesta por


una ventana principal, a la que se denomina principal o padre, capaz
de contener en su interior mltiples ventanas, a las que se denomina
hijas. La ventana que va a actuar como padre tendr el estilo
fsMDIForm y tan slo puede existir una en el proyecto, mientras que
cada una de las ventanas hija tendr el estilo fsMDIChild.
Posicin inicial del formulario
Aunque por defecto, al ejecutar un programa Delphi, la ventana
principal aparece en la misma posicin y con las mismas dimensiones
fijadas en la fase de diseo, esto no tiene por qu ser necesariamente
as. Tanto la posicin inicial como el tamao vendrn determinadas por
el valor que asignemos a la propiedad Position, que puede ser
cualquiera de los mostrados en la tabla 7.3. El valor tomado por
defecto es poDesigned.
Constante
poDefault
poDesigned
poDefaultPosO
nly
poDefaultSize
Only
poScreenCente
r
poDesktopCent
er

Posicin y tamao inicial de la ventana


Determinados automticamente por Windows.
Los establecidos en modo de diseo.
Posicin determinada por Windows, tamao
en modo de diseo.
Tamao determinado por Windows, posicin
en modo de diseo.
Tamao original y posicin centrada
pantalla.
Tamao original y posicin centrada
escritorio.

fijado
fijada
en

la

en

el

Tabla 7.3. Posibles valores para la propiedad Position


Mediante el valor poScreenCenter podemos conseguir que el formulario
aparezca siempre en el centro de la pantalla, an cuando sta tenga
unas dimensiones diferentes a las que tena en modo de diseo, lo que
suele ocurrir cuando el programa se ejecuta en un ordenador distinto
del que se utiliz para su desarrollo. En caso de que se trabaje en un
sistema con varios monitores, el monitor en que se centrar la ventana
depender del valor que se d a la propiedad DefautMonitor. Los
valores posibles son dmDesktop, dmPrimary, dmMainForm y dmActiveForm,
segn se desee ignorar la existencia de varios monitores, colocar la
ventana en el monitor primario, en el monitor en que se encuentre el
formulario principal o en el monitor en que se encuentre el formulario
activo, respectivamente.
Otra propiedad que tambin afecta a la posicin y dimensiones del
formulario es WindowState, cuyos posibles valores se enumeran en la
tabla 7.4. El valor por defecto, wsNormal, permite que el formulario
sea mostrado segn la propiedad Position, mientras que los otros dos
valores causarn que la ventana aparezca ocupando todo el espacio

disponible en
wsMinimized.

pantalla,

wsMaximized,

Constante
wsNormal
wsMaximized
wsMinimized

bien

en

forma

de

icono,

Estado inicial de la
ventana
Normal
Maximizada
Minimizada

Tabla 7.4. Posibles valores para la propiedad WindowState


Icono del formulario
En caso de que el formulario cuente con un men de sistema o control,
en la parte superior izquierda de la ventana aparecer un pequeo
icono que, al ser pulsado, desplegar un men de opciones. Este mismo
icono representar al formulario en caso de que este sea minimizado.
Por defecto Delphi utiliza el mismo icono para todos los formularios,
a no ser que nosotros asignemos uno diferente mediante la propiedad
Icon. Esta propiedad es en realidad un objeto de tipo Tlcon, que
cuenta con sus propiedades, eventos y mtodos.
En modo de diseo podemos asignar un icono diferente de una forma muy
fcil, usando la ventana de edicin de la propiedad Icn. En esta
ventana podremos recuperar cualquier icono con la simple pulsacin de
un botn, icono que pasar a formar parte de nuestro programa.
Tambin podemos alterar el icono de la ventana en ejecucin,
recuperando un icono de un archivo en disco o un recurso del programa.
El objeto Tlcon, al que accedemos mediante la propiedad Icn, cuenta
con un mtodo llamado LoadFromFile() que nos permite recuperar un
icono de un archivo estndar ICO. La siguiente sentencia, por ejemplo,
establecera como icono del formulario Form1 el contenido del archivo
ALARMA.ICO.
Form1.Icon.LoadFromFile('ALARMA.ICO');
7.2.2. Eventos de un formulario
Adems de los eventos generales, como los generados por el ratn y el
teclado, un formulario cuenta con otros eventos especficos que
debemos conocer para poder aprovecharlos. Todos estos eventos cuentan
como primer parmetro con el TObject llamado Sender, que en este caso
representa al formulario que recibe el evento.
Cuando se crea un formulario, antes de ser visualizada, sta recibe el
evento OnCreate. El mtodo asociado a este evento podemos usarlo para
realizar
cualquier
proceso
de
inicializacin
previo
a
la

visualizacin, como puede ser establecer la posicin dependiendo de


las dimensiones de la pantalla, asignar el ttulo, etc.
Tras la creacin, lo normal es que el formulario sea visualizado,
momento en el que se genera el evento OnShow. De forma anloga, cuando
el formulario es ocultado, ya sea alterando el valor de la propiedad
Visible o utilizando el mtodo Hide(), se genera un evento OnHide. A
diferencia del evento OnCreate, que se produce slo cuando el
formulario es creado, los dos eventos anteriores pueden producirse
mltiples veces, en caso de que el formulario sea alternativamente
mostrado y ocultado.
En Windows es posible trabajar simultneamente con ms de un programa
y cambiar de una ventana a otra en el momento en que nos interese. En
el momento en que un formulario se convierte en la ventana activa se
genera un evento OnActivate. De forma similar, cuando el formulario
deja de estar activo, porque cambiemos a otro programa, se produce un
evento OnDeactivate.
Generalmente las ventanas disponen en la parte superior un botn
conteniendo una X, que el usuario puede usar para cerrarla en
cualquier momento. Cuando esta accin se produce, el formulario recibe
una
secuencia
de
varios
eventos,
entre
los
cuales
se
encuentranOnCloseQuery y OnClose. El primero de ellos se produce antes
de hacer efectivo el cierre de la ventana.
Lo podemos usar para realizar cualquier tarea previa a esta operacin,
pudiendo incluso impedirla. Adems del parmetro Sender, este evento
tambin est acompaado de un evento de tipo Boolean, llamado Candse,
mediante el cual podemos impedir el cierre de la ventana. Por defecto
el valor de este parmetro es True, pero nosotros podemos asignarle el
valor False cancelando la operacin de cierre.
En caso de que el cierre de la ventana se lleve a trmino, tras el
evento OnCloseQuery se produce un evento OnClose. Este evento recibe
tambin un parmetro adicional, llamado Action, al que podemos asignar
cualquiera de los valores mostrados en la tabla 7.5, indicando as la
accin que deseamos llevar a cabo.
Constante

Accin a llevar a cabo

caNone

Ninguna, no se cierra la ventana.


Ocultar la ventana, que puede hacerse
visible de nuevo.
Destruir la ventana liberando la memoria
ocupada.
Minimizar la ventana, pero no cerrarla.

caHide
caFree
caMinimize

Tabla 7.6. Valores posibles para el parmetro Action

En caso de que el tipo de borde que hayamos establecido lo permita, el


usuario podr alterar el tamao de la ventana redimensionndola, para
lo cual la tomar con el cursor del ratn por uno de los bordes y la
estirar o encoger. Cuando esta operacin de cambio de tamao haya
terminado, el formulario recibir un evento OnResize, que nosotros
podemos aprovechar para realizar cualquier operacin de ajuste, por
ejemplo reposicionando los controles del formulario.
Un formulario Delphi cuenta con un rea de trabajo, el fondo del
formulario, que puede ser utilizada como superficie de dibujo. En caso
de que deseemos dibujar algo en ese espacio, nos interesa el evento
OnPaint, que se genera cada vez que Windows comunica al formulario que
debe dibujarse a s mismo.
7.2.3. Mtodos de un formulario
Adems de los mtodos generales comentados en el captulo anterior,
como Show(), Hide(), SetFocus(), etc., un formulario cuenta con
bastantes ms mtodos, gran parte de ellos dedicados a la gestin de
los componentes que contiene en su interior.
Una forma alternativa de mostrar un formulario, que estudiaremos ms a
fondo en el captulo 8, consiste en utilizar el mtodo ShowModalQ, que
muestra un formulario en un estado al que se denomina modal. En este
estado la ventana impide el acceso a cualquier otra ventana del mismo
programa, de tal forma que el usuario se ve forzado a cerrarla antes
de poder continuar. El propio entorno de Delphi cuenta con muchas
ventanas de este tipo, como podr comprobar. Si selecciona la opcin
New del men File, haciendo aparecer el Depsito de objetos, ver que
no le es posible acceder al formulario o a la ventana de cdigo, hasta
en tanto no cierre el Depsito de objetos. Esto es una ventana modal.
7.2.4. En la prctica
Veamos en la prctica el uso de algunos de los apartados que hemos
conocido hasta ahora, principalmente en lo que respecta a los eventos
del formulario. Para ello vamos a escribir un programa simple en el
que el formulario se visualizar, sin ningn componente en su
interior, y podr ser redimensionado y cerrado. Abra la pgina de
eventos en el Inspector de objetos y haga doble clic sobre el evento
OnResize. Esto provocar la apertura del Editor de cdigo, en el que
el cursor aparecer posicionado en el interior del procedimiento
correspondiente a ese evento, que quedar como se muestra a
continuacin.
procedure TForm1.FormResize(Senders TObject);
begin
Caption := IntToStr(Width) + ', ' +IntToStr(Height);
End;

La nica lnea que escribimos nosotros es la asignacin a la propiedad


Caption, ya que la cabecera y finalizacin del mtodo son generados
automticamente por Delphi.
Observe que delante de la propiedad Caption no se ha facilitado el
identificador de ningn componente y, sin embargo, estamos haciendo
referencia a la propiedad Caption del formulario. En este caso podemos
omitir el nombre del formulario, Form1, porque estamos haciendo
referencia a sus propiedades desde un mtodo que pertenece al propio
formulario. Observe que en la cabecera del mtodo, tras la palabra
Procedure, encontramos el nombre de tipo del formulario y el nombre
del mtodo.
En este procedimiento lo que hacemos es mostrar como ttulo de la
ventana las dimensiones actuales que tiene sta. Para ello tomamos el
contenido de las propiedades Width y Height, que es numrico, y lo
convertimos a cadena mediante la funcin lntToStr(). Las dos cadenas
resultantes son concatenadas, mediante el operador +, generando una
nica cadena que es la que se asigna a la propiedad Caption.
Haga ahora doble clic sobre el evento OnDbIClick, en el Inspector de
objetos, creando el procedimiento siguiente, en el que simplemente se
muestra una ventana con un mensaje indicando que se ha realizado una
doble pulsacin sobre el formulario.
procedure TForm1.FormDblClick(Sender: TObject);
begin
ShowMessage('Has hecho una doble pulsacin');
end;
Por ltimo vamos a crear el mtodo correspondiente al evento
OnCloseQuery, para lo cual deber hacer doble clic sobre ese evento en
el Inspector de objetos. En este caso de lo que se trata es de
preguntar al usuario si realmente quiere salir del programa,
evitndolo en caso de que su respuesta sea "no". Para hacer esta
pregunta vamos a usar el mtodo MessageBox() del objeto Application.
La variable Application, que es un objeto, representa a nuestra
aplicacin y es creada automticamente por Delphi cuando se inicia el
programa. Mediante Application podemos acceder a mltiples propiedades
y mtodos, entre ellos al mtodo MessageBox(). ste permite mostrar
una ventana con una serie de botones y devuelve un valor indicando el
botn que puls el usuario. En el cdigo siguiente puede ver cmo se
muestra una ventana con dos botones. S y No, asignando al parmetro
Candse el valor False en caso de que la respuesta sea No.
procedure TForm1.FormCloseQuery(Sender: Tobject);
var
CanClose: Boolean;
begin
If Application.MessageBox('Desea salir?', 'Prueba',
MB_YESNO) = ID_NO Then

CanClose := False;
end;
Al ejecutar el programa observe que en la parte superior aparecen las
dimensiones del formulario, ya que el evento OnResize se produce cada
vez que sta cambia de tamao, hecho que ocurre tambin en el momento
en que el formulario es creado. Si modifica el tamao del formulario
podr comprobar que los valores de las propiedades Width y Height son
mostrados en la barra de ttulo. Haga doble clic sobre el formulario
para comprobar que el evento OnDbIClick funciona adecuadamente. Por
ltimo pulse sobre el botn de cierre y conteste negativamente a la
pregunta de si desea salir. Como ver, la ventana no se cierra, ya que
al asignar el valor False al parmetro CanClose del evento
OnCloseQuery lo estamos impidiendo.

Figura 7.1. El programa de ejemplo preguntando si se desea salir


7.3. Botones
Entre los controles ms habituales que podemos encontrar en una
ventana, junto con los mens, tenemos los botones que el usuario puede
pulsar para realizar una determinada accin. Estos botones aparecen
como un rea rectangular tridimensional, con un ttulo en su interior.
En Delphi el botn est representado por el componente TButton, que
encontramos en la pgina Standard de la Paleta de componentes. Al
insertar un control de este tipo en el formulario, el ttulo,

almacenado en la propiedad Caption, ser el nombre del componente, que


se almacena en la propiedad Name.
Podemos modificar dicho ttulo estableciendo el que a nosotros nos
interese, simplemente editando el valor de la propiedad Caption en el
Inspector de objetos.
7.3.1. Tecla de acceso rpido
Los botones, al igual que otros controles que cuentan con un ttulo,
pueden contar con una tecla de acceso rpido que, utilizada junto con
la tecla <Alt> permite, en este caso, pulsar el botn sin necesidad de
desplazarse hasta l.
La tecla de acceso rpido ha de ser necesariamente uno de los
caracteres que forma parte del ttulo. Para indicar al control qu
carcter ser el seleccionado le antepondremos a ste el carcter &.
Al hacerlo, observe que en el botn ese carcter aparece con un
subrayado, indicando as que se trata de la tecla de acceso rpido.
7.3.2. El evento de pulsacin
Si disponemos un botn en un formulario, sin ms, su funcionalidad es
prcticamente nula ya que, aunque el usuario puede pulsarlo y
visualmente aparecer pulsado, no se producir ninguna operacin en
consecuencia. Lo normal es que asociemos un mtodo al evento OnClick
del botn, ejecutando el cdigo que proceda en el momento en que el
usuario lo pulse.
El evento OnClick es el evento principal de un botn y se produce
cuando ste es pulsado, indistintamente de cmo se haya hecho. Podemos
pulsar el botn utilizando el cursor del ratn, la tecla de acceso
rpido, desplazndonos hasta l con la tecla <Tab> y pulsando la barra
espadadora, con la tecla <Intro> si es el botn por defecto o con la
tecla <Esc>, si es el botn de cancelacin. En todos estos casos se
generar el evento igualmente.
Como ya sabemos, el evento OnClick es un evento de notificacin, que
tan slo cuenta con el parmetro Sender general a todos los eventos.
Este parmetro ser una referencia al botn que ha sido pulsado y nos
ser muy til en caso de que compartamos un mismo mtodo entre varios
botones.
7.3.3. Botn por defecto y de cancelacin
En un formulario pueden existir mltiples controles TButton, tantos
como deseemos, que pueden ser pulsados segn los mtodos comentados en
el punto anterior. De todos ellos dos pueden ser activados de una
forma especial, que consiste en pulsar la tecla <Intro> o la tecla
<Esc>.

Se
denomina
botn
por
defecto
a
aquel
que
ser
pulsado
automticamente, generando el correspondiente evento OnClick, en el
momento en que pulsemos la tecla <Intro>, independientemente del
control que est activo en ese mo-mento. De esta forma, podemos
encontramos en un control TEdit, por ejemplo introduciendo un valor, y
pulsar la tecla <Intro> para pulsar el botn por defecto.
Para que un botn acte como botn por defecto habremos de dar el
valor True a la propiedad Default. Por defecto el valor de esta
propiedad es False, lo cual es lgico, ya que no tendra sentido la
existencia de mltiples botones por defecto en el mismo formulario, ya
que al pulsar la tecla <Intro> no se sabra cul pulsar.
El botn de cancelacin es aquel que se pulsa, adems de por los
mtodos normales, mediante la tecla <Esc>. Para que un botn acte
como botn de cancelacin deberemos dar el valor True a la propiedad
Cancel, que por defecto es False.
7.3.4. En la prctica
Para ver en funcionamiento el uso del control TButton, vamos a
insertar en un formulario un control TEdit, cuyas caractersticas
conoceremos posteriormente, y tres controlesTButton, con los ttulos y
teclas de acceso rpido que se pueden ver en la figura 7.2. El primer
botn no tiene ninguna caracterstica especial, mientras que el
segundo es el botn por defecto, para lo cual hemos dado el valor True
a la propiedad Default, y el tercero es el botn de cancelacin, por
lo cual la propiedad Cancel tiene ese mismo valor.

Figura 7.2. Aspecto del formulario con los tres controles TButton

Una vez que haya insertado los cuatro componentes, los haya situado
adecuadamente
y
asignado
los
valores
correspondientes
a
las
propiedades Caption, Default y Cancel, vamos a proceder a la escritura
del cdigo que se habr de ejecutar con la pulsacin de cada uno de
los botones.
Como lo nico que deseamos comprobar es cul de los tres botones se ha
pulsado, bastar con mostrar una ventana con un mensaje que bien
podra ser el propio ttulo del botn. Para mostrar esta ventana
usaremos el procedimiento ShowMessage() que conocimos anteriormente.

Por tanto, el cdigo de los tres mtodos correspondientes al evento


Click de cada uno de los botones sera prcticamente idntico, ya que
en los tres casos nos limitaramos a llamar al procedimiento
ShowMessage() pasando como parmetro el contenido de la propiedad
Caption del botn que se haya pulsado.
Puesto que todos los eventos vienen acompaados de un primer
parmetro, llamado Sender, que hace referencia al objeto que ha
generado el evento, lo lgico es que, en lugar de escribir tres
mtodos, escribamos slo uYio, compartido por los tres botones, en el
cual usemos el mencionado parmetro para obtener el ttulo del botn.
El parmetro Sender es de tipo TObject, un tipo del que estn
derivados todos los objetos de Delphi, incluidos los componentes y
controles. TObject es, por tanto, un ascendiente comn, y por eso se
utiliza para representar a cualquier objeto de forma genrica. Al
utilizar este parmetro, sin embargo, es necesario realizar una
conversin previa al tipo que corresponda, con el fin de poder acceder
a sus miembros, en este caso a sus propiedades.
Para realizar una conversin de un tipo de objeto a otro, realizando
las comprobaciones necesarias, usaremos el operador As. Este operador
es binario, tomando por lo tanto dos operandos. El primero de ellos,
dispuesto a la izquierda, ser el identificador del objeto a
convertir, mientras que el segundo, dispuesto a la derecha, ser el
tipo al que se desea convertir. En caso de que la conversin sea
satisfactoria el valor obtenido podr ser usado sin mayor problema,
como si Sender fuese realmente del tipo que a nosotros nos interesa.
En caso de que la conversin no fuese vlida se generara una
excepcin.
Haga doble clic sobre el primer botn, abriendo as la ventana de
cdigo y creando el mtodo correspondiente al evento por defecto de un
TButton, que es el evento OnClick. Escriba el cdigo que se muestra a
continuacin.
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage((Sender As TButton).Caption);
end;
Observe que la conversin de Sender al tipo TButton, mediante el
operador As, se ha encerrado entre parntesis, ya que la prioridad del
operador de cualificacin, el punto, es mayor que la del operador As,
lo que causara que la expresin no fuese vlida.
Para terminar seleccione en el formulario los otros dos botones de
forma conjunta, pulsando sobre uno y luego sobre el otro mientras
mantiene pulsada la tecla <Mays>, abra la pgina de eventos en el
Inspector de objetos y despliegue la lista adjunta al evento OnClick,

seleccionando de ella el nico mtodo existente en este momento. De


esta forma lo que hacemos es compartir el mtodo entre los tres
controles. Cuando el usuario pulse un botn cualquiera se llamar
siempre al mismo mtodo, pero pasando un valor diferente para el
parmetro Sender.
Ya puede ejecutar el programa, pulsando <F9>, y realizar diversas
pruebas con l. Estando el foco de entrada en el control TEdit, que
fue el que insertamos en primer lugar, pulse la tecla <Intro> o la
tecla <Esc>, con el fin de comprobar el funcionamiento del botn por
defecto y de cancelacin.
Puede tambin pulsar conjuntamente la tecla <Alt> junto con las teclas
<N>, <D> y <C>, pulsando cada uno de los botones mediante su tecla de
acceso rpido. Lgicamente tambin puede desplazar el puntero del
ratn hasta situarlo sobre un botn y pulsarlo, el resultado ser
siempre el mismo.
7.4. Etiquetas de texto
El control que acabamos de conocer, al igual que otros muchos, cuenta
con una propiedad Caption que nos permite mostrar un ttulo. Este
sirve para que el usuario del programa sepa qu funcin es la que
desempea el botn. Otros controles, como puede ser el TEdit que
utilizamos en el ejemplo anterior, no cuentan con esta propiedad.
Si necesitamos adjuntar un ttulo a un control que no dispone de la
propiedad Caption, o si simplemente deseamos disponer un texto
cualquiera en el formulario, podemos utilizar el control TLabel. Este
control, que se distingue del anterior en que no puede tomar el foco
de entrada, cuenta con una propiedad Caption a la que podemos asignar
el texto que deseamos mostrar.
Adems de las propiedades particulares que se van a comentar a
continuacin, este control cuenta tambin con muchas de las
propiedades generales que ya conocemos. A pesar de ser un control que
no puede tomar el foco de entrada, no podemos acceder a l mediante la
tecla <Tab>, TLabel si recibe eventos de ratn.
7.4.1. Tamao del control
Al igual que todos los controles, TLabel tiene unas dimensiones que se
almacenan en las propiedades Width y Height. Estas dimensiones las
podemos fijar nosotros, tanto en la fase de diseo como de ejecucin,
o bien podemos dejar que sea la propia etiqueta la que establezca el
tamao en proporcin al texto que se desea mostrar.
La propiedad AutoSize, que por defecto toma el valor True, es la que
controla este comportamiento del control TLabel. Con su valor por
defecto.True, el tamao de la etiqueta se ajusta automticamente al
contenido de la propiedad Caption, algo que puede comprobar fcilmente

en modo de diseo modificando dicho contenido, podr


lmites del control se amplan o reducen adecuadamente.

ver

que

los

Si damos el valor False a la propiedad AutoSize, las dimensiones del


control TLabel sern siempre las que nosotros establezcamos, y en
ningn momento se realizar un ajuste automtico a no ser que nosotros
asignemos de nuevo el valor True.
7.4.2. Alineacin del texto
En caso de que las dimensiones del control TLabel no sean exactamente
las necesarias para mostrar el ttulo, es decir, si la propiedad
AutoSize tiene el valor False, podemos seleccionar mediante la
propiedad Alignment la alineacin del texto en el espacio disponible.
Esta propiedad puede tomar cualquiera de los valores enumerados en la
tabla 7.6, siendo taLeftJustify el tomado por defecto.
Alineacin del
texto

Constante
taLeftJustify
taRightJustif
y
taCenter

A la izquierda
A la derecha
Al centro

Tabla 7.6. Valores posibles para la propiedad Alignment


7.4.3. Otras propiedades de TLabel
Por defecto, el control TLabel muestra el contenido de la propiedad
Caption en una sola lnea, lo que en ciertas ocasiones puede ser
insuficiente para nuestras necesidades. Si lo deseamos podemos indicar
al control que el texto se divida automticamente en varias lneas,
respetando el ancho que nosotros asignemos. Para ello bastar con dar
el valor True a la propiedad WordWrap.
Al igual que otros controles, TLabel cuenta con un color de fondo, que
especificamos en la propiedad Color, y un color de texto, que vendr
dado por la propiedad Color de la propiedad Font. Si deseamos que la
etiqueta de texto, nombre con el que se conoce habitualmente al
control TLabel, sea transparente, de tal forma que no se borre el
fondo sobre el que se va a dibujar el texto, deberemos dar el valor
True a la propiedad Transparent, que por defecto tiene el valor False.
A pesar de que, como se ha dicho antes, el control TLabel no puede
tomar el foco de entrada, s que es posible asignarle una tecla de
acceso rpido, precediendo cualquiera de los caracteres del ttulo con
el carcter &, tal y como se explic anteriormente para los botones.
Esto tiene sentido slo cuando la etiqueta de texto se est usando
como ttulo de otro control, de tal forma que al pulsar la tecla de
acceso rpido, el control que tomar el foco ser el que est asociado

al TLabel y no el TLabel en s. Para que la etiqueta de texto sepa a


qu control debe pasar el foco cuando se pulse la tecla de acceso
rpido, deberemos asignar a la propiedad FocusControl el nombre de
dicho control.
7.4.4. En la prctica
Vamos a ver cmo podemos usar el control TLabel con un pequeo
ejemplo. Comenzaremos insertando en un formulario tres controles
TLabel y dos controles TEdit, tal y corri se muestra en la figura
7.3. Asigne los valores adecuados a la propiedad Caption de cada
control TLabel, teniendo en cuenta las teclas de acceso rpido de los
dos primeros.

Figura 7.3. Aspecto del formulario para probar el control TLabel


Asigne a la propiedad FocusControl de la primera etiqueta, Label1, el
nombre del controlTEdit que tiene debajo, Edit1, y haga lo mismo con
la segunda etiqueta, asignando a la propiedad FocusControl el nombre
del segundo TEdit.
D el valor False a la propiedad AutoSize de la tercera etiqueta y
modifique su tamao de tal forma que ocupe prcticamente todo el
formulario, de extremo izquierdo a extremo derecho. A continuacin
haga
doble
clic
sobre
la
etiqueta,
para
abrir
el
mtodo
correspondiente al evento OnClick, y escriba el cdigo siguiente.
procedure TForm1.Label3Click(Sender: TObject);
begin
With Label3 Do // Asumir la referencia a Label3
Case Alignment 0f // Segn el valor de la propiedad
// asignamos otro distinto
taLeftJustify: Alignment := taCenter;
taCenter: Alignment := taRightJustify;
taRightJustifyrAlignment := taLeftJustify;
End;
end;

Como puede ver, lo que se hace


Alignment del formulario, de tal
saltando del extremo izquierdo al
extremo derecho y de ah de nuevo

es alterar el valor de la propiedad


forma que en ejecucin el texto ir
centro, de ah al
al izquierdo con cada pulsacin.

Ejecute el programa y compruebe cmo mediante la tecla de acceso


rpido de la etiqueta de texto puede pasar de un control TEdit a otro.
Observe tambin el comportamiento del TLabel que hay en la parte
inferior del formulario, que cambia su alineacin con cada pulsacin
de ratn.
7.5. Peticin de datos
La finalidad del control TEdit, que hemos usado en dos ejemplos
anteriores, es permitir la entrada de un dato por parte del usuario.
Este dato, en forma de cadena de caracteres, se almacenar en la
propiedad Text, a la cual es posible dar un valor inicial durante el
diseo. A diferencia de los dos controles anteriores, TButton y
TLabel, el control TEdit no cuenta con una propiedad Caption, por lo
cual se suele disponer una etiqueta de texto adjunta que sirve como
ttulo.
Cuando durante la ejecucin el usuario modifica el contenido de un
TEdit, la propiedad Modified de ste toma el valor True. Desde el
cdigo de nuestro programa podemos comprobar el valor de esta
propiedad y, en caso de que proceda, recuperar la entrada realizada
por el usuario leyendo la propiedad Text.
7.5.1. Longitud del texto
Por defecto el control TEdit no pone ningn lmite a la cantidad de
texto que el usuario puede introducir y, en caso de que sea necesario,
desplazar el contenido actual del control a medida que se introducen
nuevos caracteres.
Si lo deseamos, podemos limitar el nmero de caracteres que es posible
introducir en un TEdit mediante la propiedad MaxLength. Esta
propiedad, de tipo entero, contiene por defecto el valor cero,
indicando que no hay un lmite establecido. Asignando cualquier otro
nmero estaremos fijando la longitud mxima de la propiedad Text.
7.5.2. Seleccin de texto
Mientras se edita el contenido de un control TEdit, el usuario puede
marcar una porcin del texto, mediante la combinacin de la tecla
<Mays> y los cursores o bien con el ratn, con el fin de realizar
alguna operacin que le afecte, como puede ser eliminarlo o copiarlo
al portapapeles.
En cualquier momento podemos saber qu texto es el que hay
seleccionado en el control, para lo cual disponemos de las propiedades

SelStart, SelLength y SelText. La primera de ellas contiene el


carcter a partir del cual se ha marcado, sabiendo que el primero de
los existentes es el carcter cero. La segunda propiedad contiene el
nmero de caracteres que hay marcados, mientras que la tercera
contiene el texto.
El valor de estas propiedades tambin puede ser establecido por el
cdigo de nuestro programa, seleccionando automticamente el texto que
nos interese. Si deseamos marcar todo el texto contenido actualmente
en el control, en lugar de editar las propiedades SelStart y SelLength
podemos realizar una simple llamada al mtodo SelectAII().
Las operaciones de copiar, cortar y pegar con el portapapeles, que se
realizan mediante teclado con unas combinaciones de teclas que ya
conocemos, pueden ser tambin realizadas mediante cdigo gracias a la
existenda de varios mtodos al efecto. El mtodo ClearSelection()
elimina el texto que hay seleccionado, de igual forma que si el
usuario hubiese pulsado la tecla <Supr>.
El mtodo CopyToClipboard() copia el texto al portapapeles, mientras
que CutToClipboard() lo copia al portapapeles y lo elimina del TEdit.
PasteFromClipboard(), finalmente, nos permite recuperar el texto que
hay en el portapapeles, insertndolo en el TEdit en la posicin actual
del cursor.
El texto que hay seleccionado en un control TEdit se distingue del
resto por estar con los colores invertidos, efecto que desaparece en
el momento en que abandonamos el control, dando el foco de entrada a
cualquier otro de los existentes en el formulario. Al volver de nuevo
al control TEdit, la marca del texto vuelve a aparecer. Este
comportamiento se debe a que por defecto la propiedad HideSelection
tiene el valor True, indicando al control TEdit que oculte la
seleccin de texto cuando no est activo. Si damos a esta propiedad el
valor False, el texto seleccionado estar siempre destacado del resto,
an cuando el control no est activo.
7.5.3. Texto de slo lectura y oculto
Aunque, por regla general, el contenido de un control Tedit puede ser
editado por el usuario durante la ejecucin, en ocasiones nos puede
interesar usar este control slo para mostrar un valor y no para
permitir su edicin. Para conseguir esto bastar con asignar el valor
True a la propiedad ReadOnly, haciendo as que el control TEdit sea de
slo lectura.
Este control puede ser usado para solicitar cualquier tipo de dato,
pero a veces lo deseable es que el dato que se est introduciendo no
sea visible para terceras personas que puedan existir alrededor del
usuario. Esto ocurre, por ejemplo, cuando se solicita una clave de
entrada a una aplicacin, que debe ser algo confidencial. Mediante la
propiedad PasswordChar podemos conseguir que el control TEdit vaya

representando cada uno de los caracteres que introduce el usuario


mediante un cierto smbolo, como puede ser un asterisco, una
interrogacin, etc. En realidad podemos asignar a PasswordChar
cualquier carcter, el que deseemos.
7.5.4. Otras propiedades de TEdit
Dependiendo del valor que demos a la propiedad AutoSelect, que por
defecto es True, al acceder a un control TEdit, por ejemplo mediante
la tecla <Tab>, el contenido actual ser automticamente seleccionado
o no. Si deseamos que al seleccionar un texto esta seleccin se
mantenga an cuando nos desplacemos a otros controles, deberemos dar
el valor False a esta propiedad.
Al igual que el control TLabel, TEdit tambin dispone de una propiedad
AutoSize, aunque su funcionamiento es ligeramente diferente, ya que
asignndole el valor True no conseguimos que el control adecu su
tamao al del texto que contiene, sino que lo que indicamos es que la
altura del Tedit se ajuste a la necesaria para poder mostrar el tipo
de letra que se haya seleccionado. Por defecto la propiedadAutoSize
tiene el valor True, por lo que si modificamos la propiedad Font,
alterando el tamao de letra, no tendremos que preocupamos de ajustar
apropiadamente el alto del control.
La introduccin de ciertos datos puede requerir que todas las letras
sean facilitadas en maysculas, o en minsculas, con el fin de evitar
posteriores fallos de comparacin. Mediante la propiedad CharCase, que
puede tomar los valores mostrados en la tabla 7.7, podemos forzar que
todos los caracteres aparezcan en maysculas o en minsculas. El valor
por defecto para esta propiedad es ecNormal, lo que permite una
combinacin de ambas.
Constante
ecNormal
ecUpperCase
ecLowerCase

Indica
Se permiten tanto maysculas como
minsculas.
Todas las letras son convertidas a
maysculas.
Todas las letras son convertidas a
minsculas.

Tabla 7.7. Posibles valores para la propiedad CharCase


7.5.5. Control de la entrada
El componente TEdit no realiza ningn tipo de comprobacin previa a la
admisin de los caracteres que el usuario pueda introducir, ni cuenta
con propiedad alguna que nos permita indicar qu caracteres son los
vlidos. ste es, sin embargo, un aspecto que podemos controlar
nosotros mismos, gracias a que cada vez que el usuario pulsa una
tecla, antes de que el correspondiente carcter sea almacenado en la

propiedad Text del TEdit, se genera un evento OnKeyPress, en el que


nosotros podemos realizar las comprobaciones que sean necesarias.
El evento OnKeyPress, que ya
recibe un parmetro en forma
saber qu carcter es el que
modificarlo, realizando una
carcter nulo.

fue comentado en el captulo anterior,


de variable, lo que nos permite no slo
se ha pulsado, sino que adems podemos
conversin, o anularlo, asignando el

Tambin podemos usar el evento OnKeyDown para detectar la pulsacin de


ciertas teclas especiales, a las que haremos referencia mediante los
cdigos de tecla virtual, un cdigo que no tiene nada que ver con el
cdigo ASCII de cada carcter.
7.5.6. En la prctica
Veamos en la prctica algunos de los apartados que hemos conocido
sobre el control TEdit en los puntos anteriores. Vamos a partir
insertando en un formulario tres controles TEdit, que estarn
encabezados por tres TLabel, y tres TButton. El aspecto del formulario
ser el que se muestra en la figura 7.4.
El
primer
control
TEdit
lo
utilizaremos
para
comprobar
el
funcionamiento de las propiedades MaxLength, a la que Figura 7.4.
Formulario para comprobar el funcionamiento de Tedit vamos a asignar
el valor 10, y PasswordChar, a la que asignaremos el valor *. De esta
forma, en este control podremos introducir un mximo de diez
caracteres que, adems, no sern visibles siendo sustituidos por
asteriscos.

Figura 7.4. Formulario para comprobar el funcionamiento de TEdit


A continuacin tenemos un TEdit que vamos a utilizar para ver cmo
podemos controlar la entrada de caracteres, permitiendo tan slo la
introduccin de dgitos numricos. Abra la pgina de eventos en el
Inspector de objetos y haga doble clic sobre el evento OnKeyPress,
escribiendo el cdigo que se muestra a continuacin. En l se

comprueba que el carcter sea un dgito numrico o bien la tecla de


borrado hacia atrs, a la que corresponde el cdigo ocho, asignando al
parmetro Key el valor #0 en caso contrario, ignorando as la
pulsacin. Observe cmo se usa un conjunto y el operador In para
simplificar esta comprobacin.
procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
begin
// Si no es un carcter permitido
If Not (Key In ['0'. .'9', #8]) Then
Key := #0; // lo ignoramos
end;
El ltimo control TEdit que hemos insertado lo usaremos para probar
los mtodos de copiar, borrar y pegar el texto seleccionado. A la
propiedad AutoSelect del control TEdit vamos a asignar el valor False,
para evitar que la seleccin del texto se pierda al pulsar un botn o
cambiar a otro de los TEdit que hay en el formulario. Ser al pulsar
cualquiera de los tres botones que hemos dispuesto debajo cuando se
realice la operacin de copiado, borrado o pegado, gracias al cdigo
que asociaremos al evento OnClick de cada uno de los botones, como se
muestra seguidamente.
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit3.CopyToClipboard; // Copiarnos al portapapeles
Edit3.SetFocus; // y devolvemos el foco al TEdit
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Edit3.ClearSelection; // Borramos el texto marcado
Edit3.SetFocus;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
Edit3.PasteFrom Cllpboard; // Copiamos del portapapeles
Edit3.SetFocus;
end;
Observe que tras realizar la operacin que proceda se hace una llamada
al mtodo SetFocus(), con el fin de devolver el foco de entrada al
control TEdit. Dados todos los pasos anteriores, no tiene mas que
pulsar la tecla <F9> para ejecutar el programa y comprobar su
funcionamiento.
7.6. Entrada de texto
El control TEdit es el de uso ms habitual cuando en un programa es
necesario solicitar una entrada del usuario, pero este control tiene

una limitacin: la entrada no puede exceder de una lnea, a pesar de


que esa lnea puede tener una longitud superior al tamao del propio
control en el formulario.
Cuando necesitemos solicitar una entrada de texto ms amplia, en
varias lneas, en lugar de un TEdit podemos usar un control TMemo.
Este control es muy similar al que acabamos de conocer en los puntos
anteriores y cuenta con muchas propiedades que ya hemos visto, como
ReadOnly, MaxLength, Text, SelStart, etc., as como con los mtodos
relacionados con las operaciones del portapapeles y los mismos eventos
que ya conocemos.
7.6.1. Barras de desplazamiento
A pesar de que un control TMemo puede tener unas dimensiones tales que
le permitan mostrar mltiples lneas de texto, es difcil saber de
antemano cuantas lneas van a existir, con el fin de adecuar la
altura, y, en cualquier caso, no siempre podremos dar al control el
tamao necesario como para poder mostrar todo el texto, ya que el
espacio disponible en la pantalla es limitado.
Cuando en una ventana se desea mostrar algo que excede de las
dimensiones mximas disponibles, lo que se hace es mostrar unas barras
de desplazamiento, en el eje horizontal, vertical o ambos, cuya
finalidad es permitir el movimiento de la ventana sobre la informacin
a mostrar, o el desplazamiento de la informacin al interior de la
ventana, segn deseemos verlo.
Un control TMemo tambin puede contar con barras de desplazamiento,
permitiendo trabajar con lneas ms largas que el espacio horizontal
disponible y con ms lneas de las que es posible mostrar de forma
simultnea. La existencia o no de las barras de desplazamiento
depender del valor que asignemos a la propiedad ScrollBars, que ser
uno de los mostrados en la tabla 7.8. El valor tomado por defecto es
ssNone, por ello inicialmente el TMemo no cuenta con barras de
desplazamiento.
Constante
ssNone
ssVertical
ssHorizontal
ssBoth

Barras de desplazamiento a
mostrar
Ninguna
Vertical
Horizontal
Vertical y Horizontal

Tabla 7.8. Posibles valores para la propiedad ScrollBars


En caso de que el control no disponga de una barra de desplazamiento
horizontal, lo habitual es que el texto que se va introduciendo sea
dividido automticamente, saltando de una lnea a otra. Esto ocurrir

a no ser que demos el valor False a la propiedad WordWrap, que por


defecto es True.
7.6.2. Trabajando con lneas de texto
El texto
propiedad
un mtodo
lo que en

almacenado en un control TMemo es accesible mediante la


Text, al igual que en un control TEdit. Existe, sin embargo,
mediante el cual podemos acceder a ese texto lnea a lnea,
ciertas situaciones puede ser mucho ms til.

El control TMemo cuenta con una propiedad, llamada Lines, que es un


objeto de tipoTStrings. Este objeto cuenta con una serie de
propiedades y mtodos que nos permiten acceder a cualquiera de las
lneas de texto, aadir nuevas lneas, eliminarlas, etc.
La propiedad ms interesante del objeto TStrings es seguramente
Strings, una matriz de cadenas mediante la cual podemos acceder
individualmente a las lneas de texto. Podemos saber cuantas lneas de
texto hay en un determinado momento mediante la propiedad Count. La
propiedad Strings es la propiedad por defecto del objeto TStrings al
que hace referencia Lines, lo que quiere decir que podemos acceder a
una lnea de texto simplemente disponiendo su ndice, entre corchetes,
tras la propiedad Lines, sin necesidad de especificar nada ms. De
esta forma, las dos sentencias siguientes seran equivalentes.
Texto := Memo1.Linea.Strings[1];
Texto := Memol.Lines[1] ;
Los mtodos Clear(), Add(), Append() e Insert() nos permiten eliminar
todas las lneas de texto, aadir una nueva lnea o insertarla,
respectivamente. Dos de los mtodos ms tiles de un TStrings son
SaveToFile() y LoadFromFile(), que permiten guardar y recuperar las
lneas de texto en un archivo en disco. Los dos mtodos toman como
nico parmetro el nombre del archivo en el que se va a guardar o del
que se va a recuperar.
Durante el diseo podemos acceder al contenido de la propiedad Lines
mediante un editor especfico, en el que podremos introducir las
lneas de texto que deseemos mostrar inicialmente en el control.
7.6.3. Otras propiedades de TMemo
Al editar mltiples lneas de texto en un control, podemos necesitar
la insercin de ciertos caracteres cuyas teclas tienen
un significado especial en una ventana. La pulsacin de la tecla
<Intro> normalmente activa el botn por defecto, si es que ste
existe, pero tambin se puede utilizar en un control Tmemo para
producir un salto de lnea. De forma similar, la tecla <Tab> se usa
para pasar de un control a otro de la ventana, pero en un TMemo puede
ser usado para insertar un fabulador.

La funcin de las dos teclas citadas, <Intro> y <Tab>, mientras est


activo un control TMemo depender de los valores que contengan las
propiedades WantReturns y WantTabs. La primera de ellas tiene por
defecto el valor True, mientras que la segunda tiene el valor False.
Asignando a WantReturns el valor True conseguiremos que la pulsacin
de la tecla <mtro> en el interior de un TMemo produzca un salto de
lnea, no la pulsacin del botn por defecto que pueda haber en el
formulario. Para pulsar dicho botn previamente tendremos que
abandonar el TMemo, o bien utilizar directamente el puntero del ratn
o la tecla de acceso rpido.
De forma anloga, la asignacin del valor True a la propiedad WantTabs
tendr como resultado que la pulsacin de la tecla <Tab> en el
interior de un TMemo no produzca la activacin del siguiente control,
segn el orden de acceso, sino la insercin en el texto de un
fabulador.
7.6.4. En la prctica
Como en casos anteriores, vamos a servirnos de un pequeo programa
ejemplo que nos ilustre el uso de este nuevo control que acabamos de
conocer, con el fin de ver cmo podemos aprovechar sus posibilidades.
Inserte en un formulario un control TMemo, ocupando la mayor parte del
espacio disponible, y a continuacin inserte a su derecha tres
botones, a los que vamos a asignar los ttulos Borrar, Guardar y
Recuperar. D el valor True a la propiedad WantTabs del TMemo, a fin
de que podamos insertar fabuladores.
A continuacin tendremos que hacer un doble clic sobre cada uno de los
tres botones, escribiendo el cdigo que deseamos ejecutar cuando sean
pulsados en ejecucin. A continuacin se muestran los mtodos
asociados al evento OnClick de cada botn. Como puede ver, simplemente
se realizan tres llamadas, a los mtodos Clear(), SaveToFile() y
LoadFromFile().
procedure TForm1.Button1Click(Sender:TObject);
begin
Memo1.Lines.Clear; // Eliminamos el contenido
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// Guardamos el contenido actual
Memol. Lines.SaveToFile ('memo.txt' );
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
// Recuperamos el contenido del archivo

Memol.Lines.LoadFromFile( 'memo.txt' );
end;
Una vez escrito el cdigo ya puede ejecutar el programa e introducir
cualquier texto en el TMemo, que podr guardar en un archivo,
recuperar y eliminar pulsando los botones adecuados. En la figura 7.5
se muestra el aspecto del programa en funcionamiento, mostrando un
texto recuperado del archivo MEMO.TXT.

Figura 7.5. Aspecto del programa en funcionamiento


7.7. Seleccin de opciones
Aunque, como se indicaba anteriormente, el control Tedit es el ms
usado en Windows a la hora de solicitar informacin al usuario de un
programa, no es el nico. Cuando lo que se espera del usuario es una
respuesta tan simple como s o no, verdadero o falso, activado o
desactivado, en lugar de un control TEdit podemos usar un TCheckBox.
El control TCheckBox es adecuado para mostrar y permitir la entrada de
cualquier informacin de tipo Boolean, que es posible representar con
tan slo dos estados. Estos dos estados se muestran visualmente
mediante una casilla, que puede contener o no en su interior una
marca.
La propiedad Checked es la ms importante de este control, ya que ella
nos permite tanto saber el estado actual del control como modificarlo.
El tipo de esta propiedad es Boolean y contendr el valor True, en
caso de que el control est marcado, o el valor False, en caso
contrario.
En realidad un control TCheckBox puede tomar tres estados diferentes,
en caso de que demos el valor True a la propiedad AllowGrayed, que por
defecto es False. Estos tres estados son activado, desactivado e
indeterminado, que se visualizan como el recuadro con la marca, sin la
marca y con un relleno gris. Para comprobar cul es el estado actual
del control o modificarlo deberemos utilizar la propiedad State, que
tomar cualquiera de los valores mostrados en la tabla 7.9.
Constante
cbChecked
cbUnchecked
cbGrayed

Estado del
control
Activado
Desactivado
Indeterminado

Tabla 7.9 Posibles valores para la propiedad State.


7.7.1. En la prctica
Como acabamos de ver, el funcionamiento de un control TCheckBox es
bastante simple y basta con que conozcamos la propiedad Checked para
actuar en consecuencia. Veamos con un pequeo programa de ejemplo cmo
podemos usar en la prctica este control.
Inserte en un formulario tres controles TCheckBox, a los que vamos a
asignar los ttulos 'Botn de maximizar', 'Botn de minimizar' y 'Men
de sistema', modificando en el Inspector de objetos el contenido de la
propiedad Caption. El tercer TCheckBox tendr inicialmente su
propiedad Checked a True, ya que el formulario va a contar de
principio con un men de sistema. Las otras dos, por el contrario, no
estarn activas ya que modificaremos la propiedad Bordericons del
formulario para ocultar los botones de maximizar y minimizar. A
continuacin hacemos un doble clic sobre cada uno de los controles,
para abrir el mtodo correspondiente al evento OnClick de cada uno de
ellos, escribiendo el cdigo que se muestra a continuacin.
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
{ Si est marcada la opcin }
If CheckBox1.Checked Then
{ Activamos el botn de maximizar }
BorderIcons := BorderIcons + [biMaximize]
Else
{ en caso contrario lo desactivamos }
BorderIcons := BorderIcons - [biMaximize];
end;
procedure TForm1.CheckBox2Click(Sender: TObject);
begin
{ Lo mismo con el botn minimizar }
If CheckBox2.Checked Then
BorderIcons := BorderIcons + [biMinimize]
Else
BorderIcons := BorderIcons - [biMinimize];
end;
procedure TForm1.CheckBox3Click(Sender: TObject);
begin
{ Y el men de sistema }
If CheckBox3.Checked Then
BorderIcons := BorderIcons + [biSystemMenu]
Else
BorderIcons := BorderIcons - [biSystemMenu];
end;

Como puede ver, lo que hacemos es aadir o eliminar de la propiedad


Bordericons el elemento correspondiente al TCheckBox que se ha
pulsado, segn que la propiedad Checked contenga el valor True o
False. Al ejecutar el programa, podr ver cmo en el formulario
aparecen o desaparecen los botones en la parte superior, segn las
opciones que nosotros activemos. En la figura 7.6 se muestra el
programa en funcionamiento.
7.8. Seleccin de opciones exclusivas
Al realizar pruebas con el ejemplo anterior, habr podido comprobar
que es posible desactivar todos los TCheckBox o activarlos los tres de
forma simultnea. Esto quiere decir que las opciones que representan
esos controles no son exclusivas entre s, es decir, la existencia de
un men de sistema en la ventana, no impide que sta tenga tambin un
botn para maximizar.

Figura 7.6. El programa de ejemplo en funcionamiento


En ocasiones, sin embargo, nos puede interesar representar opciones
que son exclusivas entre s, de tal forma que slo sea posible
seleccionar una de ellas, al tiempo que obligatoriamente una debe
estar activa. Suponga, por ejemplo, que desea modificar el programa
anterior para que le permita seleccionar el tipo de borde del
formulario, segn lo cual asignar un valor u otro a la propiedad
BorderStyle. Est claro que siempre deber existir un valor
seleccionado, ya que esa propiedad ha de contener un valor, y tambin
es lgico que no sea posible la seleccin de ms de un valor de forma
simultnea, ya que tan slo puede existir un tipo de borde en el
formulario.
Para solicitar una informacin como la descrita, en lugar de usar el
control TChecRBox deberemos usar el control TRadioButton, que es muy
similar tanto visualmente como en lo referente a su funcionamiento.
Este control tambin cuenta con una propiedad Checked, en la que se
almacena el estado del control, y a diferencia de un TCheckBox tan
slo son posibles dos estados, por lo que no existen las propiedades
AllowGrayed yState. Por lo dems, unTRadioButton funciona de forma muy

similar a un TCheckBox, si exceptuamos el hecho de que al activar uno


automticamente se desactiva el que en ese momento estuviese activo.
7.8.1. En la prctica
Para ver en funcionamiento el control TRadioButton, vamos a insertar
en un formulario cuatro controles de este tipo, asignando a la
propiedad Caption los ttulos 'bsNone', 'bsSingle', 'bsSizeable' y
'bsDialog'. El tipo de borde inicial del formulario ser simple, por
lo que seleccionaremos el valor bsSingle de la lista desplegable
adjunta a la propiedad BorderStyle. El TRadioButton activo por defecto
ser el que tiene por ttulo ''bsSingle', por lo que daremos el valor
True a su propiedad Checked.
Haga doble clic sobre el primerTRadioButton, con el fin de abrir el
Editor de cdigo por el mtodo correspondiente al evento OnClick, y
escriba el cdigo que se muestra a continuacin, en el cual se
comprueba qu TRadioButton es el que est activo, asignando a la
propiedad BorderStyle del formulario el valor apropiado.
procedure TForm1.RadioButton1Click(Sender: TObject);
begin
{ Segn el control que est pulsado }
If RadioButton1.Checked Then
{ asignamos un valor u otro a BorderStyle }
BorderStyle := bsNone
Else If RadioButton2.Checked Then
BorderStyle := bsSingle
Else If RadioButton3.Checked Then
BorderStyle := bsSizeable
Else
BorderStyle := bsDialog;
end;
A continuacin seleccione en el formulario los otros tres TRadioButton
de forma conjunta, abra la pgina de eventos del Inspector de objetos
y despliegue la lista adjunta al evento OnClick, seleccionando el
nico elemento que aparece. De esta forma conseguiremos que el evento
OnClick de los cuatro controles compartan un mismo procedimiento.
Ya puede ejecutar el programa. Observe cmo cambia el
tipo de borde a medida que selecciona un TRadioButton u
otro. Compruebe que no le es posible activar dos opciones al
mismo tiempo, lo que s era posible con eITCheckBox. sta es
la principal diferencia entre ambos controles.

Figura 7.7. Aspecto del programa con los controles TRadioButton


7.9. Grupos de opciones exclusivas
Conociendo ya el funcionamiento del control TRadioButton,
nos puede
surgir una cuestin de forma inmediata. Qu ocurre si deseamos
solicitar varios datos diferentes, cada uno de los cuales tiene una
serie de opciones exclusivas entre s?.
Suponga, por ejemplo, que en el programa anterior adems de
seleccionar
el
tipo
de
borde,
tambin
quiere
permitir
el
establecimiento del estado del formulario, seleccionando el valor
adecuado para la propiedad WindowState. Si simplemente aadimos tres
nuevos controles TRadioButton, asignando los ttulos apropiados, nos
encontraremos con un problema, y es que al seleccionar un tipo de
borde se desactivar el estado de la ventana que hubiese seleccionado
y viceversa. Es decir, las opciones de borde y de estado, que no son
exclusivas, no pueden seleccionarse de forma simultnea.
Para evitar este problema tendramos que agrupar de alguna manera los
controles TRadioButton del tipo de borde, por una parte, y los del
estado de la ventana por otra. Esto se puede hacer mediante los
controles TGroupBox o TPanel, que conoceremos despus. Existe, sin
embargo, un mtodo an ms simple, que consiste en utilizar el control
TradioGroup en lugar del control TRadioButton.
Un control TRadioGroup es capaz de almacenar mltiples elementos, cada
uno de los cuales se muestra como un TRadioButton independiente. Su
gestin, sin embargo, se realiza de forma conjunta y mucho ms
eficiente. Los elementos de un TRadioGroup se delimitan con un borde
en cuya parte superior puede existir un ttulo general, que podemos
establecer modificando el valor de la propiedad Caption.
7.9.1. Opciones existentes y opcin activa
Para establecer las opciones existentes en un control TRadioGroup
tendremos que editar el contenido de la propiedad tems. Esta
propiedad es un objeto TStrings, cuyo funcionamiento ya conocemos por
haberlo tratado anteriormente, al explicar las propiedades del control
TMemo.

En modo de diseo basta con hacer doble clic sobre la propiedad tems
para abrir el editor especfico con el que cuenta, aadiendo los
ttulos de las opciones que deseemos mostrar. En ejecucin, podremos
usar los mtodos Add(), Append(), Insert() y Clear() para aadir o
eliminar elementos.
Los elementos existentes en un control TRadioGroup se numeran con un
ndice, cuyo punto de partida es el cero. Este ndice nos servir para
saber qu opcin es la que est activa o bien para establecerla,
mediante la propiedad Itemindex. Este mtodo de activar una opcin o
comprobar qu opcin es la que est activa es mucho ms eficiente que
el visto anteriormente para el control TRadioButton, en el que era
necesario ir comprobando el valor de la propiedad Checked de cada
control hasta saber cul de ellos era el que estaba activo.
En caso de que el nmero de elementos contenidos en el grupo sea muy
extenso, podemos optar por dividirlos en varias columnas. Para ello
bastar con que asignemos a la propiedad Columns el nmero de columnas
que deseamos.
7.9.2. En la prctica
Con el fin de ver en la prctica cmo podemos utilizar un control
TRadioGroup, vamos a insertar en un formulario dos controles de este
tipo, asignando a la propiedad Items los elementos que se pueden ver
en la figura 7.8. El primero contiene las opciones de tipo de borde
para el formulario, mientras que el segundo almacena las opciones
relativas a los estados de la ventana. El orden en que se han
dispuesto estos valores no es aleatorio, corresponde al orden que
ocupa cada una de las constantes en las enumeraciones TFormBorderStyle
y TWindowState.

Figura 7.8. Aspecto del formulario con los dos controles TRadioGroup

Modifique la propiedad Itemindex del primer grupo, asignndole el


valor 1, y la del segundo grupo, asignndole el valor 0. Establezca
tambin el tipo de borde inicial para el formulario, que ser

bsSingle. A continuacin haga doble clic sobre un TRadioGroup y luego


sobre el otro, escribiendo el cdigo siguiente.
{ Al seleccionar cualquiera de las opciones del primer grupo )
procedure TForm1.RadioGrouplClick(Sender: TObject);
begin
{ Asignar el valor apropiado a BorderStyle }
BorderStyle : = TFormBorderStyle(RadioGroup1.Itemindex);
end;
{ Al seleccionar una opcin del segundo grupo }
procedure TForm1.RadioGroup2Click(Sender: TObject);
begin
{ Modificamos el valor de WindowState }
WindowState := TWindowState (RadioGroup2.Itemindex);
end;
Observe cmo se asigna a las propiedades BorderStyle y WindowState
directamente un valor que es entero, contenido en la propiedad
Itemindex de cada TRadioGroup, realizando previamente la conversin
necesaria. Esta asignacin es posible porque las opciones han sido
dispuestas en el orden en que fueron definidas las constantes de los
tipos TForm1BorderStyle y TWindowState, de tal forma que el valor O en
la propiedad ItemIndex del primer grupo se corresponde con la
constante bsNone, el valor 1 con la constantebsSingle, y as
sucesivamente.
Ejecute el programa, pulsando la tecla <F9>, y realice diversas
pruebas. Observe cmo al modificar el estado de la ventana sta se
maximiza o minimiza, y cmo toma el tamao que tena originalmente
cuando se selecciona el estilo normal. El tamao de la ventana puede
ser modificado, simplemente estableciendo un tipo de borde bsSizeable.

7.10. Listas de elementos


Otro de los controles que nos permite mostrar listas de elementos de
los cuales es posible seleccionar uno o varios, aunque de forma
ligeramente diferente, es TListBox. Este control es lo que se conoce
habitualmente como una lista, un recuadro en el cual aparecen una
serie de lneas de texto siendo posible la seleccin de una o varias
de ellas.
El funcionamiento del control TListBox es parecido al del control
TRadioGroup que acabamos de conocer, aunque visualmente su aspecto es
bastante diferente.
7.10.1. Contenido de la lista
Los elementos con los que cuenta una lista estn contenidos en la
propiedad tems, que es un objeto de tipo TStrings, al igual que la

propiedad del mismo nombre del control TRadioGroup. Por tanto, ya


sabemos cmo gestionar los elementos en la fase de diseo, mientras
que durante la ejecucin usaremos los mtodos siguientes:
Add(): Toma como parmetro una cadena de texto, aadindola como
nuevo elemento al final de la lista.
lnsert(): Toma dos parmetros, indicando el primero la posicin en
la que se desea insertar el elemento, y el segundo el texto a aadir.
Delete(): Este mtodo nos permite eliminar un elemento de la lista,
para lo cual deberemos facilitar su ndice.
Clear(): No necesita
existentes en la lista.

parmetros,

elimina

todas

las

cadenas

lndex0f(): Toma como parmetro una cadena, devolviendo el ndice que


sta ocupa en la lista o -1 en caso de no encontrarse.
Move(): Facilita el desplazamiento de un elemento de una posicin a
otra, para lo cual deberemos facilitar el ndice en que se encuentra
actualmente y el ndice correspondiente al punto al que se desea
mover.
Exchange(): Este mtodo es similar al anterior, tomando como
parmetros dos ndices con el fin de intercambiar las posiciones de
los elementos correspondientes.
SaveToFile(): Guarda el contenido de la lista a un archivo en disco,
cuyo nombre hemos de facilitar.

LoadFromFile():
Este
mtodo
es
complementario
al
anterior,
permitiendo recuperar la lista de elementos del archivo cuyo nombre se
facilita como parmetro.
Aunque mediante los mtodos Add(), lnsert(), Move() y Exchange() es
posible establecer la posicin de cada uno de los elementos segn nos
interese, dicha posicin tambin depender del valor que tenga la
propiedad Sorted del control TListBox. Si dicha propiedad tiene el
valor True los elementos de la lista estarn ordenados, de tal forma
que, por ejemplo, al aadir un nuevo elemento ste no va al final de
la lista, sino a la posicin que le corresponde segn el orden
establecido.
7.10.2. Elementos seleccionados
En una lista puede haber seleccionado un slo elemento o varios,
dependiendo del valor que asignemos a la propiedad MultiSelect. Por
defecto esta propiedad contiene el valor False, indicando as que no
es posible seleccionar varios elementos. Dndole el valor True
activaremos esta posibilidad.

Si se activa la posibilidad de seleccionar mltiples elementos de la


lista, nos encontramos con dos mtodos diferentes de realizar esta
seleccin. El mtodo a utilizar depender del valor dado a la
propiedad ExtendedSelect, que tambin es de tipo Boolean. El valor
True en esta propiedad indica que se usar la seleccin extendida, lo
que significa que el usuario puede utilizar el botn izquierdo del
ratn junto con las teclas <Mays> y <Control> para realizar la
seleccin, de forma similar a como se hara, por ejemplo, en el
Explorador de Windows. Si la propiedad ExtendedSelect tiene el valor
False, la seleccin de los elementos se realizar simplemente pulsando
sobre ellos con el botn izquierdo del ratn, pudiendo eliminar la
seleccin de igual forma.
El mtodo por el cual podremos saber qu elemento o elementos hay
seleccionados depender de que est permitida o no la seleccin
mltiple. Si la propiedad MultiSelect tiene el valor False, el ndice
del nico elemento seleccionado posible se encontrar en la propiedad
Itemindex, al igual que ocurra con el control TRadioGroup. El valor 1 indica que no hay en ese momento ningn elemento seleccionado. En
caso de que est permitida la seleccin mltiple, mediante la
propiedad SelCount podremos saber cuntos elementos hay seleccionados,
mientras que en la propiedad Selected, que es una matriz de enteros,
encontraremos los ndices de cada uno de los elementos.
7.10.3. Otras propiedades de TListBox
Cuando una lista contiene ms elementos de los que le es posible
mostrar de forma simultnea, automticamente aparece una barra de
desplazamiento vertical que nos permite acceder al contenido completo
de la propiedad Items. Podemos determinar y fijar cul es el primer
elemento que est visible en un determinado momento, en la parte
superior de la ventana, mediante la propiedad Topindex, que almacena
el ndice de dicho elemento.
Al desplazar los elementos que contiene la lista, podr observar
posiblemente que el elemento que est en la parte superior o el
situado en la parte inferior aparecen cortados, vindose slo un trozo
del texto. Esto es debido a que por defecto el alto de la lista no es
un mltiplo de la altura de cada elemento, ya que la propiedad
IntegralHeight contiene el valor False. Podemos dar el valor True a
esta propiedad si deseamos evitar el citado efecto.
7.10.4. En la prctica
El programa ejemplo que vamos a construir en este caso nos permitir
aadir elementos a la lista, durante la ejecucin, con
el texto que nosotros facilitemos. Tambin podremos eliminar un
elemento que hayamos previamente seleccionado o bien vaciar totalmente
la lista. Los elementos podrn aparecer en el orden en que se van
aadiendo o bien ordenados.

Iniciaremos el trabajo insertando en un formulario los controles que


puede ver en la figura 7.9. Un TListBox y un TEdit, ambos precedidos
de un TLabel que le sirve como ttulo, tres controles TButton para
permitir las diferentes acciones y un TCheckBox, mediante el cual
indicaremos si deseamos o no que los elementos estn ordenados. Edite
el orden de acceso mediante la tecla <Tab>, haciendo que el primer
control en activarse sea el TEdit. A continuacin d el valor True a
la propiedad Default del primer botn, haciendo as que la pulsacin
de la tecla <Intro> tenga como resultado la insercin en la lista del
elemento cuyo texto se haya introducido en el TEdit. Por ltimo, en
cuanto a propiedades se refiere, asigne el valor False a la propiedad
Enabled del segundo botn, ya que la funcin de borrado de un elemento
slo debe estar activa en caso de que haya un elemento seleccionado,
lo que en principio no ocurrir puesto que la lista estar vaca.
La pulsacin del botn Aadir, que se producir al pulsar la tecla
<Intro> ya que es el botn por defecto, tendr como resultado que el
texto introducido por nosotros en el control TEdit, disponible en la
propiedad Text, sea aadido como un elemento ms a la lista. Para ello
tendremos que escribir el cdigo siguiente en el mtodo asociado al
evento OnClick de este botn.

Figura 7.9. Aspecto del formulario para probar el control TListBox


Observe que tras aadir el nuevo elemento se realiza una llamada al
mtodo SelectAII() del TEdit, con el fin de seleccionar todo su
contenido y facilitar as la introduccin de un nuevo valor.
{ Al pulsar el botn Aadir }
procedure TForml.Button1Click(Sender: TObject);
begin
{ Aadimos a la lista el texto existente en el control TEdit }
ListBox1.Items.Add(Edit1.Text);
{ y marcamos todo el contenido de dicho control }
Edit1.SelectAll;

end;
Inicialmente el botn Borrar estar desactivado, activndose slo
cuando al pulsar sobre la lista seleccionemos un elemento. Por ello
deberemos controlar el evento OnClick deI TListBox, asignando a la
propiedad Enabled del botn el valor True o False, dependiendo de que
exista o no un elemento seleccionado en ese momento, lo que sabremos
inspeccionando el valor de la propiedad Itemindex, que deber ser
distinto de -1.
{ Al pulsar en la lista }
procedure TForml.ListBox1Click(Sender: TObject);
begin
{ Activamos o desactivamos el botn de Borrar segn haya o no
seleccionado un elemento }
Button1.Enabled := ListBox1.Itemindex <> -1;
end;
Una vez que el botn est activado podremos pulsarlo, provocando el
borrado del elemento seleccionado en la lista. Para ello bastar con
realizar una llamada al mtodo Delete() de la propiedad tems, pasando
como parmetro el ndice del elemento a borrar, que al ser el elemento
seleccionado encontraremos en la propiedad tem ndex.
{ Al pulsar el botn Eliminar }
procedure TForml.Button2Click(Sender: TObject);
begin
{ Eliminamos el elemento seleccionado }
ListBoxI.Items.Delete(ListBox1.Itemindex);
{ y desactivamos el botn de borrar }
Button2.Enabled := False;
end;
El cdigo asociado al botn Vaciares el ms simple, ya que consta de
una simple llamada al mtodo Clear(), que elimina todo el contenido
del objeto TStrings, o lo que es lo mismo, de la lista.
{ Al pulsar el botn Vaciar }
procedure TForml.Button3Click(Sender: TObject);
begin
{ Dejamos vaca la lista }
ListBox1.Items.Clear;
end;
Por ltimo tendremos que controlar la pulsacin sobre el TCheckBox,
activando o desactivando el orden de los elementos en la lista. Para
ello bastar con asignar a la propiedad Sorted el valor que contenga
la propiedad Checked del TCheckBox, como puede ver a continuacin.
( Al activar o desactivar la opcin Ordenada }
procedure TForm1.CheckBox1Click(Sender: TObject);

begin
{ Damos el valor adecuado a la propiedad Sorted }
ListBox1.Sorted := CheckBox1.Checked;
end;
Al ejecutar el programa lo primero que deber hacer ser aadir
algunos elementos a la lista, introduciendo un texto en el TEdit y
pulsando la tecla <Intro>. A continuacin puede pulsar sobre el
TCheckBox para activar la ordenacin de los elementos. Si deja
activada esta opcin, al aadir nuevos elementos stos se colocarn
directamente en las posiciones que le correspondan segn el orden
establecido. Pruebe tambin a seleccionar un elemento de la lista,
momento en que se activar el botn Borrar, y eliminarlo.

7.11. Listas desplegables


En el programa de ejemplo anterior hemos usado un control TEdit
conjuntamente con un TListBox, permitiendo as la insercin de
elementos en la lista. Existe un control, conocido como lista
combinada, que es la unin de un TEdit con un TListBox, al que Delphi
llama TComboBox.
Bsicamente, un TComboBox incorpora las funciones de ambos controles
y, por tanto, cuenta con propiedades que ya conocemos, como Text,
MaxLength,
tems,
Itemindex,
etc.
Tanto
el
aspecto
como
el
funcionamiento de una lista combinada depender del estilo que tenga,
segn el valor que se asigne a la propiedad Style.
El estilo por defecto es csDropDown, que corresponde al de un campo de
edicin en el que es posible introducir texto como si de un TEdit se
tratase, con un botn en el extremo derecho que despliega una lista
con los elementos contenidos actualmente.
Si deseamos que el usuario pueda seleccionar un valor de la lista,
desplegndola, pero no que pueda introducir un texto, el estilo a
utilizar es csDropDownList. Con este estilo el botn que despliega la
lista aparece totalmente unido al recuadro de edicin.
Por ltimo tenemos el estilo csSimple, en el cual la lista combinada
aparece como un TEdit sin botn ni lista desplegable adjunta. En un
TComboBox con este estilo es posible utilizar las teclas de cursor
arriba y abajo para recorrer los elementos de la lista, ya que sta
existe aunque no sea visible directamente.
7.11.1 En la prctica
Para comprobar el funcionamiento del control TComboBox, vamos a
disear un programa en el que podamos aadir elementos a la lista
introduciendo el texto directamente en el propio control, sin
necesidad de un TEdit auxiliar. Sobre el TComboBox vamos a situar un
control TLabel, que utilizaremos para ir indicando el nmero de

elementos que contiene la lista en cada momento. Debajo de la lista


combinada vamos a insertar un TButton cuya finalidad ser eliminar
todo el contenido, con una llamada al mtodo Clear() de la propiedad
tems.
Por ltimo, a la derecha del TComboBox vamos a insertar un control
TRadioGroup con tres elementos, que nos van a permitir cambiar en
ejecucin el estilo de la lista combinada, lo cual nos servir para
observar las diferencias entre uno y otro.
Puesto que el texto de los nuevos elementos se va a introducir usando
el propio TComboBox, deberemos controlar cada pulsacin de tecla,
mediante el evento OnKeyPress, para que en el momento en que se
detecte la pulsacin de la tecla <Intro> se proceda a la insercin del
texto en la lista, actualizando el contador que mostraremos en el
TLabel e ignorando la pulsacin. El cdigo que deberemos escribir es
el siguiente.
{ Con cada pulsacin de tecla en el ComboBox }
procedure TForm1.ComboBox1KeyPress (Sender: TObject; var
Key: Char);
begin
If Key = #13 Then { Si la tecla es <Intro> }
With ComboBox1 Do
Begin
Items.Add(Text); { Aadimos el nuevo elemento }
{ Mostramos el nmero de elementos }
Label1.Caption :=IntToStr (Items. Count) + ' elementos';
SelectAll; { Seleccionamos el texto }
Key := #0; {e ignoramos la pulsacin de tecla }
End;
end;
El nico botn existente en el formulario, titulado Vaciar, nos
permitir dejar vaca la lista combinada, para lo cual bastar con
realizar una llamada al mtodo Clear(). Tambin modificaremos la
propiedad Caption deITLabel, con el fin de indicar el nmero de
elementos existentes en ella.
{ Al pulsar el botn Vaciar }
procedure TForm1.Button1Click(Sender: TObject);
begin
{ Dejamos vaca la lista }
ComboBox1.Items.Clear;
Label1.Caption := '0 elementos';
end;
Por ltimo tendremos que controlar el evento OnClick del control
TRadioGroup, con el fin de establecer el estilo adecuado para la lista
combinada segn la opcin que se seleccione. Como hicimos en un

ejemplo anterior, esta asignacin se realizar de forma directa,


llevando a cabo una conversin de tipo, como puede ver a continuacin.
{ Al seleccionar un elemento del TRadioGroup }
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
{ Fijamos el estilo que corresponda }
ComboBox1.Style : =TComboBoxStyle(RadioGroup1.Itemindex);
end;
Ya puede ejecutar el programa, pulsando <F9>, y realizar pruebas con
el control TComboBox. Aada elementos y compruebe su existencia
desplegando la lista. Modifique el estilo y observe las diferencias
existentes entre uno y otro. En la figura 7.10 puede ver el aspecto
del programa en funcionamiento.

Figura 7.10. Aspecto del programa en funcionamiento

7.12. Controles contenedores


Todos los controles que hemos conocido hasta ahora, si exceptuamos el
control TLabel, tienen como finalidad interactuar de alguna forma con
el usuario, permitindole seleccionar una opcin o introducir algn
tipo de informacin, ya sea teclendola o bien seleccionndola de una
lista.
Cuando en un formulario existen muchos controles, lo normal, con el
fin
de
aclarar
la
visualizacin,
es
que
se
creen
grupos,
delimitndolos de forma clara. En este apartado es donde nos pueden
ayudar los controles TGroupBox y TPanel. Tanto uno como otro son
controles que actan como contenedores, lo que les permite alojar en
su interior a otros controles.
Los controles que deseemos que formen parte de un grupo, ya est
construido en base a un TGroupBox o a un TPanel, deben ser insertados
directamente en el interior del control contenedor. No sirve de nada,
por tanto, tomar un control que ya est en el formulario y desplazarlo
hasta situarlo sobre el contenedor, ya que lo que estamos haciendo es

superponerlo, pero no incluirlo. Es fcil saber cundo un cierto


control est o no insertado en un contenedor, ya que basta con mover
el TGroupBox o TPanel. Todos aquellos controles que estn insertados
tambin se desplazarn, mientras que los que no lo estn quedarn
inalterados.
Tanto el control TGroupBox como el TPanel, cuentan con una propiedad
Caption a la que podemos asignar un ttulo. La diferencia est en que
mientras el primero muestra ese ttulo en la parte superior del
control, en el borde, el segundo lo hace en el interior, por defecto
en el centro del control.
7.12.1. Alineacin del contenedor
Los controles que actan como contenedores, como TGroupBox y TPanel,
cuentan con una propiedad, llamada Align, mediante la cual es posible
mantenerlos
alineados
en
una
cierta
posicin
del
formulario,
ajustndose automticamente en caso de que sta cambie de tamao, ya
sea durante el diseo o la ejecucin.
En la tabla 7.10 puede ver los valores que puede tomar la propiedad
Align. Todos ellos implican algn cambio en el tamao del control,
puesto que ste se ha de ajustar a un cierto margen del formulario, o
bien ocupando todo el espacio disponible en sta.
Constante
alNone
alTop
alBottom
alLeft
alRight
alClient

El control se ajusta a ...


Nada, mantiene se posicin y dimensin
originales.
El margen superior de la ventana.
El margen inferior de la ventana.
El margen izquierdo de la ventana.
El margen derecho de la ventana.
Todo el espacio disponible en la
ventana.

Tabla 7.10. Posibles valores para la propiedad Align


Una modificacin de la propiedad Align durante la ejecucin,
realizando una simple asignacin, tiene como consecuencia el cambio
inmediato de la posicin del control.
7.12.2. Elementos de realce
El control TPanel es ms atractivo, visualmente hablando, que el
control TGroupBox, ya que cuenta con un borde cuyo aspecto y anchura
podemos configurar. La existencia o no del borde depender del valor
que tome la propiedad BorderStyle, que ser bsNone o bsSingle.

El borde del control puede contar un biselado exterior y otro


interior, que puede aparecer resaltado o hundido. Mediante las
propiedades BevelOuter y Bevelinner podremos seleccionar el tipo de
biselado, mientras que con la propiedad BevelWidth estableceremos su
anchura. En la tabla 7.11 se muestran los valores que pueden tomar las
propiedades BevelOuter y Bevelinner.
Constante

Tipo de biselado

bvNone
bvRaised
bvLowered

Ninguno
Resaltado
Hundido

Tabla 7.11. Valores para las propiedades BevelOuter y Bevelinner


7.12.3. En la prctica
Realmente, los dos controles que acabamos de conocer son ms elementos
de interfaz que elementos con los que sea posible interactuar en
ejecucin y, si exceptuamos la propiedad Align, no hay prcticamente
nada ms relevante en estos controles. Por ello, el programa que vamos
a hacer a continuacin estar centrado en demostrar el uso de la
propiedad Align, permitiendo desplazar un TPanel de un margen a otro
del formulario.
Inserte en un formulario un control TPanel y ajuste las propiedades de
realce, vistas en el punto anterior, segn sus propias preferencias.
D a la propiedad Align el valor alBottom, haciendo as que el control
se ajuste a la parte inferior del formulario.
Para permitir el movimiento del TPanel en ejecucin vamos a usar una
tcnica muy habitual en Windows, como es la de arrastrar y soltar.
Para ello lo primero que haremos ser dar el valor dmAutomatic a la
propiedad DragMode del TPanel, lo que nos permitir iniciar la
operacin sin necesidad de tener que llamar al mtodo BeginDrag(). A
continuacin escribiremos el cdigo siguiente, que ir asociado a los
eventos OnDragOver y OnDragDrop del formulario.
{ Al arrastrar un objeto sobre el formulario }
procedure TForm1.FormDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
begin
{ Si el objeto es un TPanel }
If Source Is TPanel Then
Accept := True; { lo aceptamos }
end;
( Al soltar el TPanel sobre el formulario }
procedure TForm1.FormDragDrop(Sender, Source: TObject; X,
Y: Integer);

begin
{ Segn el punto en que se haya soltado }
If x < 50 Then
{ establecemos una alineacin u otra }
Panel1.Align := alLeft
Else If X > Width - 50 Then
Panel1.Align := alRight
Else If Y < 50 Then
Panel1.Align := alTop
Else If Y > Height - 50 Then
Panel1.Align := alBottom;
end;
El evento OnDragOver se produce cuando un objeto est siendo
arrastrado sobre un control. En este caso, el evento lo recibe el
formulario cuando el panel se arrastra sobre el. En el mtodo asociado
a este evento primero comprobamos si el objeto que est siendo
arrastrado, que se recibe en el parmetro Source, es del tipo TPanel,
para lo cual utilizamos el operador Is. En caso afirmativo damos el
valor True al parmetro variable Accept, indicando as que aceptamos
ese objeto. Esto provoca que el icono del puntero del ratn cambie,
indicando la nueva situacin.
Cuando el objeto es soltado, el control que lo recibe, que en este
caso es el formulario, provoca un evento OnDragDrop. En ese momento
comprobamos el punto en que ha sido soltado el panel y, de acuerdo con
l, asignamos un valor u otro a la propiedad Align, haciendo que el
TPanel se ajuste al margen apropiado.
Ejecute el programa, en cuyo formulario tan slo existe el panel en la
parte inferior. Pnchelo y arrstrelo hasta los bordes del formulario,
soltndolo en cada uno de ellos. Podr comprobar cmo automticamente
se ajusta al margen que corresponda. En la figura 7.11 puede ver el
programa en ejecucin.

Figura 7.11. El programa con el TPanel en ejecucin

7.13. Barras de desplazamiento


En algunos de los ejemplos que hemos usado para comprobar el
funcionamiento de ciertos controles, hemos podido ver la existencia de
barras de desplazamiento. Los controles TMemo y TListBox, por ejemplo,
las utilizan para permitir el desplazamiento de los datos cuando la
informacin a mostrar es ms extensa que el espacio disponible en el
control.
No todos los controles cuentan con barras de desplazamiento, pero
mediante el control TScrollBar nosotros podemos aadirlas. Obviamente,
en estos casos el desplazamiento de la informacin no se producir de
forma automtica, seremos nosotros los que deberemos ocupamos de este
trabajo.
Una barra de desplazamiento puede ser tanto horizontal como vertical,
aspecto que fijaremos mediante la propiedad Kind del TScrollBar, a la
que asignaremos el valor sbVertical o sbHorizontal, segn las
necesidades que tengamos.
7.13.1. Lmites y posicin de la barra
Una barra de desplazamiento cuenta con un cursor en su interior, que
marca la posicin actual dentro de un rango cuyos extremos estn
representados por los extremos de la propia barra. Tanto la posicin
del cursor en la barra como sus lmites tienen una correspondencia con
valores numricos, que sern los que nosotros usemos en nuestros
programas.
Los valores extremos, mnimo y mximo, entre los cuales se desplazar
el cursor de la barra habremos de asignarlos a las propiedades Min y
Max, respectivamente. La posicin del cursor en un determinado momento
depender del valor de la propiedad Position, que deber encontrarse
dentro del rango delimitado por los lmites anteriores.
La posicin en una barra de desplazamiento puede modificarse mediante
cdigo, asignando un valor a la propiedad Position, o bien por una
actuacin del usuario sobre la barra. Este cambio genera un evento
OnChange, que nosotros podemos aprovechar para en consecuencia
realizar los ajustes u operaciones que sean necesarias.
7.13.2. Incrementos grandes y pequeos
Trabajando con una barra de desplazamiento es posible alterar la
posicin actual de varias formas, tanto con el ratn como con el
teclado. Una de las formas consiste en pulsar sobre las flechas que
hay en los extremos, lo que equivale a pulsar las teclas de
desplazamiento del cursor. En ambos casos se produce un incremento o
decremento en la posicin del cursor en la barra, cuya magnitud vendr
determinada por el valor de la propiedad SmallChange.

Tambin podemos pulsar en el interior de la barra, con el puntero del


ratn, a un lado u otro de donde se encuentra el cursor en ese
momento. Esto equivale a utilizar las teclas <RePg> y <AvPg>, que
producen un incremento o decremento de tantas unidades como se haya
especificado en la propiedad LargeChange.
Inicialmente las propiedadesSmallChange y LargeChange contienen el
mismo valor, pero lo normal es dar a la segunda un valor superior al
de la primera, de tal forma que sea posible avanzar o retroceder en la
barra de desplazamiento bien lnea a lnea, o pgina a pgina.
7.13.3. En la prctica
Para ver en funcionamiento este nuevo control vamos a insertar en un
formulario un TGroupBox, que nos servir como contenedor. En su
interior insertaremos dos controles TScrollBar, uno horizontal y otro
vertical, que situaremos adecuadamente en la parte inferior y derecha
del recuadro.
Tambin vamos a situar en el interior del grupo un control
TRadioButton, asignando a su propiedad Caption una cadena vaca.
Fuera del TGroupBox, por ejemplo a su derecha, vamos a insertar cuatro
controles TLabel. Los dos primeros sern simplemente unos ttulos, que
contendrn las cadenas 'Posicin X' y 'Posicin Y'. Los otros dos nos
servirn, en ejecucin, para mostrar la columna y lnea en que se haya
posicionado el TRadioButton en el interior del TGroupBox.
La finalidad de las barras de desplazamiento, en este caso, ser
permitimos desplazar el TRadioButton al punto que nos interese. Por
tanto, la primera barra de desplazamiento, que ser la horizontal,
tendr como valor mximo el ancho disponible en elTGroupBox, mientras
que el mximo de la segunda vendr dado por la altura. Estos valores,
que podramos obtener en la fase de diseo realizando algunos
clculos, pueden ser asignados en ejecucin de una forma mucho ms
cmoda.
Haga doble clic sobre el fondo del formulario, en un punto en el que
no
exista
control
alguno,
con
el
fin
de
abrir
el
mtodo
correspondiente al evento OnCreate que, como sabemos, se produce al
crear el formulario. ste es el punto adecuado para calcular los
valores mximos de las barras de desplazamiento, adems de dar el
valor adecuado a la propiedad Position dependiendo de la posicin en
que se encuentre en ese momento el control TRadioButton. El cdigo
necesario es el que se muestra a continuacin.
{ Al crear el formulario }
procedure TForm1.FormCreate(Sender: TObject);
begin
{ Calculamos el valor mximo para las dos barras de
desplazamiento }

ScrollBar1.Max := GroupBox1.Width - ScrollBar2.Width RadioButton1.Width;


ScrollBar2.Max := GroupBox1.Height ScrollBar1.Height RadioButton1.Height;
{ y fijamos su posicin inicial, que ser la que tenga el
TRadioButton en el interior del TGroupBox }
ScrollBar1.Position := RadioButton1.Left;
ScrollBar2.Position := RadioButton1.Top;
end;
Cada vez que se produzca una modificacin en cualquiera de las dos
barras de desplazamiento, deberemos automticamente actualizar la
posicin del TRadioButton, as como mostrar la nueva posicin en las
etiquetas que hemos dispuesto a tal efecto.
En este caso utilizaremos el eventoOnChange de ca daTScrollBar y el
cdigo necesario es el siguiente.
{ Cada vez que se produzca un cambio en una barra de
desplazamiento }
procedure TForm1.ScrollBar2Change(Sender: TObject);
begin
{ Actualizamos la posicin del TRadioButton }
RadioButton1.Top := ScrollBar2.Position;
{ y mostramos la nueva coordenada }
Label3.Caption := IntToStr(ScrollBar2.Position);
end;
{ Lo mismo con la otra barra de desplazamiento }
procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
RadioButton1.Left := ScrollBar1.Position;
Label4.Caption := IntToStr(ScrollBar1.Position);
end;
Al ejecutar el programa observar que el cursor de la barra de
desplazamiento que ha insertado en primer lugar parpadea, indicando
que tiene el foco de entrada. En ese momento podemos utilizar el
teclado para desplazarnos, aunque como es lgico tambin tenemos la
posibilidad de utilizar el ratn.
En la figura 7.12 puede ver el programa en funcionamiento. Compruebe
los diversos mtodos por los cuales puede modificar la posicin en la
barra de desplazamiento.

Figura 7.12. El programa con los controles TScrollBar

7.14. Elementos grficos


A diferencia de los controles con los que hemos estado trabajando
hasta ahora, que se encontraban en la primera pgina de la Paleta de
componentes, el control TShape se encuentra en la pgina siguiente,
llamada Additional. Mediante dicho control podremos insertar en un
formulario elementos grficos, tales como rectngulos, cuadrados,
valos o crculos. Estas entidades grficas cuentan con un borde y un
fondo, cuyos atributos podemos tambin modificar.
7.14.1. Figura a dibujar
Con el mismo control TShape es posible representar diversas figuras o
formas, dependiendo del valor que se d a la propiedad Shape. En la
tabla 7.12 se enumeran los valores existentes, indicndose la figura
que se dibujar en cada caso.
Constante
stRectangle
stSquare
stRoundRect
stRoundSquare
stEllipse
stCircle

Figura a dibujar
Rectngulo
Cuadrado
Rectngulo
con
redondeadas.
Cuadrado
con
redondeadas.
Elipse.
Crculo.

las
las

esquinas
esquinas

Tabla 7.12. Valores posibles para la propiedad Shape

La propiedad Shape puede ser establecida tanto en modo de diseo,


seleccionando uno de los valores de la lista desplegable adjunta a la
propiedad, o bien en ejecucin, realizando una simple asignacin.
7.14.2. Brocha y lpiz
El tipo de trazo y color del borde, as como el color y trama de
relleno que se utilizan, son aspectos que dependen de dos propiedades,
Pen y Brush, que contienen una referencia a un objeto de tipo TPen y
TBrush, respectivamente, a los que se conoce habitualmente como lpiz
y brocha.
El lpiz es el que se utiliza para trazar el borde, mientras que la
brocha se usa para pintar el relleno. Como objetos que son, estas
propiedades cuentan con otras propiedades, que sern las que nos
permitan establecer los atributos que a nosotros nos interesen.
Un objeto TPen dispone de una propiedad Color, mediante la cual
podemos especificar el color, una propiedad Mode, que sirve para
facilitar la realizacin de operaciones lgicas, una propiedad Style,
en base a la cual seleccionaremos el tipo de trazo, y una propiedad
Widh, cuya finalidad es indicar el grueso del lpiz. Los valores
posibles para la propiedad Style son los que se enumeran en la tabla
7.13.
Constante

Tipo de trazo

psSolid
psDash
psDot

Slido.
Guionado.
Punteado.
Guionado
y
punteado
alternativamente.
Guionado
y
punteado
alternativamente.
Ninguno.
Slido en el interior de la
figura.

psDashDot
psDashDotDot
psClear
psInsideFrame

Tabla 7.13. Posibles valores para la propiedad Style de TPen


Las dos propiedades con que cuenta un objeto de tipo TBrush son Color
y Style, mediante las cuales podremos indicar el color y tipo de
relleno que deseamos. En la tabla 7.14 se enumeran los estilos o
tramas de relleno que podemos utilizar.
Constante
bsSolid
bsClear

Trama de relleno
Slida.
Ninguna.

bsHorizontal
bsVertical
bsFDiagonal
BsBDiagonal
bsCross
bsDiagCross

Lneas horizontales.
Lneas verticales.
Lneas diagonales en sentido \.
Lneas diagonales en sentido /.
Lneas
horizontales
y
vertivales cruzadas.
Lneas diagonales cruzadas.

Tabla 7.14. Posibles valores para la propiedad Style de TBrush


7.14.3. En la prctica
La mejor forma de hacemos una idea de las posibilidades de este
control, consiste en probar todos los posibles valores para las
propiedades Shape y Style de la brocha y lpiz. Esto es lo que haremos
en parte en el programa que se propone como ejemplo, para el cual
insertaremos en un formulario un control TShape, un TRadioGroup con
todos los valores de la tabla 7.12 y un segundo TRadioGroup
conteniendo los valores de la tabla 7.14. Tendremos que asignar el
valor 0 a la propiedad Itemindex de ambos controles, con el fin de que
aparezca seleccionada por defecto la primera opcin en cada caso.
Cada vez que se modifique, en ejecucin, una de las opciones de los
TRadioGroup,
el
cdigo
de
nuestro
programa
deber
modificar
adecuadamente la propiedad Shape del TShape o bien la propiedad Style
de la brocha. Para ello tendremos que utilizar los eventos OnClick de
los dos controles TRadioGroup, en cuyos mtodos escribiremos las dos
sentencias siguientes.
{ Al cambiar de figura }
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
{ Dar a la propiedad Shape el valor adecuado }
Shape1.Shape := TShapeType(RadloGroup1.ItemIndex);
end;
{ Al cambiar el tipo de relleno }
procedure Tform1.RadioGroup2Click(Sender: TObject);
begin
{ Asignamos a la propiedad Style del objeto Brush el valor
correspondiente }
Shape1.Brush.Style : = TBrushStyle(RadioGroup2.ItemIndex);
end;
Tan slo con esto ya podemos ejecutar el programa, cuyo aspecto se
muestra en la figura 7.13, y comprobar el aspecto que toma el control
TShape a medida que vamos seleccionando las distintas opciones
disponibles.

Figura 7.13. Aspecto del programa con el control TShape

7.15. Imgenes de mapas de bits


No todos los elementos grficos son tan simples como para poder ser
representados mediante un control TShape, si exceptuamos las entidades
ms normales, como son los cuadrados, rectngulos y crculos. Suponga,
por ejemplo, que desea dibujar algo ms complejo, o simplemente que
desea mostrar en el formulario el contenido de un archivo grfico.
Estas son funciones para las cuales no le ser til el control TShape.
Mediante el control TImage podemos mostrar una imagen en el
formulario, bien recuperndola de un archivo en disco, que puede estar
en formato BMP, ICO o WMF, o bien dibujndola nosotros mismos en
ejecucin. La imagen que se muestra es el contenido de la propiedad
Picture, que es un objeto de tipo TPicture, mientras que la superficie
de trabajo, en la que podemos dibujar, est representada por la
propiedad Canvas, que es un objeto de tipo TCanvas.
7.15.1. Mostrar imgenes contenidas en archivos
El objeto TPicture al que hace referencia la propiedad Picture del
control TImage, cuenta con los mtodos LoadFromFileQ y SaveToFile()
que ya conocemos de otros objetos. La diferencia es que, en este caso,
estos mtodos estn encaminados a recuperar y guardar imgenes, en
lugar de lneas de texto. Por tanto, para recuperar un archivo que se
encuentra en disco lo nico que tendremos que hacer ser una llamada
al mtodo LoadFromFile(), pasando como nico parmetro una cadena
conteniendo el nombre del archivo a recuperar.
Una vez que hemos recuperado una imagen, las propiedades Height y
Width del TPicture nos sirven para conocer sus dimensiones originales.

Estas dimensiones no tienen por qu ser coincidentes con las


control TImage, caso ste en que se pueden seguir varios caminos.

del

Por defecto, cuando se recupera una imagen sta se visualiza con su


tamao original, partiendo de la esquina superior izquierda del
control TImage. En caso de que la imagen sea ms pequea que el
control, parte de ste quedar vaco. Si es la imagen la que cuenta
con unas dimensiones mayores, slo ser visible parcialmente, en la
medida de lo que sea posible mostrar en el control.
Si damos el valor True a la propiedad AutoSize del control TImage,
conseguiremos que ste ajuste automticamente sus dimensiones a las de
la imagen que va a mostrar. El efecto contrario, que sea la imagen la
que adecu su tamao al del control, lo conseguiremos dando el valor
True a la propiedad Stretch. Por ltimo, podemos dar el valor a la
propiedad Center si deseamos que la imagen se muestre con su tamao
original pero centrada en el control.
7.15.2. La superficie de dibujo
El rea de dibujo representada por un control TImage es accesible a
travs de la propiedad Canvas, que contiene una referencia a un objeto
TCanvas. Este tipo de objeto cuenta con una serie de propiedades y
mtodos que facilitan las operaciones de dibujo.
Entre las propiedades de un objeto TCanvas encontramos dos, llamadas
Pen y Brush, que representan al lpiz y la brocha usadas para dibujar.
Ya conocemos el funcionamiento de estas dos propiedades, que hemos
tratado anteriormente al trabajar con el control TShape.
Tambin contamos con una propiedad Font, cuyo funcionamiento tambin
conocemos, que nos servir para fijar los atributos de texto en caso
de que deseemos imprimir algo en el rea de dibujo.
Para dibujar en el interior de un TCanvas, adems de fijar las
caractersticas del lpiz, brocha y letra, tendremos que utilizar sus
mtodos de dibujo. Los ms habituales son los que siguen:
MoveTo(X,Y): Establece el punto de dibujo en la posicin indicada
por X,Y. Esta posicin queda como punto de partida para otras
operaciones posteriores que no indiquen una posicin de inicio.
LineTo(X,Y): Traza una lnea desde el punto actual hasta X,Y.
Rectangle(Xl,Yl,X2,Y2): Traza un rectngulo segn las coordenadas
facilitadas.
RoundRect(Xl,Yl,X2,Y2,X3,Y3): Traza un rectngulo con una esquina en
X1,Y1 y la opuesta en X2,Y2, redondeando los vrtices como si fuesen
cuartos de una elipse con el ancho de X3 y el alto de Y3.

TextOut(X,Y,cadena): Imprimir la cadena de texto en la posicin


indicada.
7.15.3. En la prctica
Para ver en funcionamiento este nuevo control, vamos a sear un
programa que nos permita dibujar a mano alzada sobre una pequea
superficie, facilitando el almacenamiento
y recuperacin de los
dibujos. Inserte en el formulario un control TPanel, dando el valor
alBottom a la propiedad Align, con el fin de alinearlo en el margen
inferior. A continuacin inserte un control TImage y d el valor
alClient a la misma propiedad, consiguiendo as que ocupe todo el
resto del espacio disponible
En el control TPanel vamos a insertar un TEdit, con el que podremos
facilitar el nombre y camino del archivo a recuperar o guardar, y dos
botones, con los ttulos Guardar y Recuperar, que sern los encargados
de realizar esas dos acciones.
Cuando se pulse el botn izquierdo del ratn sobre el rea de dibujo,
deberemos entrar en el estado de dibujo, de tal forma que a medida que
se mueva el ratn vayamos dibujando lneas continuas. Este proceso
finalizar en el momento en que se libere el botn del ratn. Para
controlar el estado en el que nos encontramos en cada momento, vamos a
definir al nivel de mdulo una variable a la que vamos a llamar
Dibujando, de tipo Boolean. A continuacin escribiremos el cdigo
siguiente en los mtodos correspondientes a los eventos OnMouseDown,
OnMouseMove y OnMouseUp del control TImage.
// Al pulsar un botn del ratn
pocedure TForm1.Image1MouseDown(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
// Si es el botn izquierdo
If Button = mbLeft Then
Begin
Dibujando := True; // Activamos el dibujo
// y fijamos el punto inicial
Image1.Canvas.MoveTo(X, Y) ;
End;
end;
// Al liberar el botn del ratn
procedure TForm1.Image1MouseUp(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
// Si es el botn izquierdo
If Button = mbLeft Then Dibujando := False; // desactivamos
dibujo
end;

el

//A medida que el ratn se mueve


procedure TForml.Image1MouseMove(Sender: TObject; Shift:
TShiftState; X, Y: Integer);
begin
// Si estamos dibujando trazamos una lnea hasta la nueva posicin
If Dibujando Then Image1.Canvas.LineTo(X, Y);
end;
Cuando se pulse el botn Guardar realizaremos una llamada al mtodo
SaveToFile() de la propiedad Picture del control TImage, pasando como
parmetro la cadena de texto contenida en la propiedad Text del
control TEdit. De forma anloga, al pulsar el botn Recuperar
llamaremos al mtodo LoadFromFile(), tal y como se muestra a
continuacin.
// Al pulsar el botn Salvar
procedure Tform1.Button1Click(Sender: TObject);
begin
Image1.Picture.SaveToFile(Edit1.text);
end;
// Al pulsar el botn Cargar
procedure TForm1.Button2Click(Sender: TObject);
begin
Image1.Picture.LoadFromFile(Edit1.text);
end;
Ya puede ejecutar el programa, que en principio mostrar un rea de
dibujo con el mismo color de fondo que el formulario. Puede optar por
facilitar el nombre de un archivo en disco, recuperando una imagen ya
existente, o bien por iniciar un dibujo desde cero. En la figura 7.14
puede ver el programa en funcionamiento, mostrando el contenido de un
archivo BMP.

Figura 7.14. Aspecto del programa de dibujo en ejecucin

7.16. Listas de unidades, carpetas y archivos


En varios de los ejemplos que hemos utilizado hasta ahora, ha sido
necesario facilitar el nombre de un archivo en disco, con el fin de
guardar o recuperar de l alguna informacin. En estos ejemplos hemos
optado porque el nombre del archivo sea fijo o bien por solicitarlo en
un control TEdit. Este mtodo, sin embargo, no es el ms cmodo a la
hora de buscar un archivo, ya que obliga, concretamente al usuario del
programa, a utilizar otra aplicacin para poder componer la secuencia
de directorios que forman el camino hasta llegar al archivo deseado.
Mediante los controles que vamos a conocer en los apartados
siguientes, podremos permitir la seleccin de una de las unidades
disponibles en el sistema, el desplazamiento entre directorios y la
seleccin de un archivo, todo ello de forma Visual, sin necesidad de
tener que escribir nada. Los tres controles se encuentran en la pgina
Win 3.1 de la Paleta de componentes.
Los tres controles que vamos a conocer a continuacin son derivados de
TComboBox o TListBox, contando con muchas propiedades que ya
conocemos, como Items, Itemindex, Text, etc. En los siguientes puntos
slo se tratarn las propiedades especficas de cada control, dando
por asumidas las dems.
7.16.1. Una lista de unidades
El control TDriveComboBox es una lista combinada en la que se muestran
las unidades de disco disponibles en el sistema, pudiendo seleccionar
cualquiera de ellas. Este control es en realidad un derivado
deTComboBox, que toma sus elementos automticamente en el momento de
la creacin, inspeccionando el sistema.
Como cualquier otra lista, podemos obtener el texto de cada uno de los
elementos accediendo a ellos mediante la propiedad tems y saber qu
elemento es el que est seleccionado a travs de Itemindex. Sin
embargo, la propiedad que ms nos interesar de este control ser
Drive, de tipo Char, que contiene la letra correspondiente a la unidad
seleccionada en cada momento. Esta letra podr ser mayscula o
minscula, dependiendo del valor que asignemos a la propiedad
TextCase, que puede ser tcLowerCase o tcUpperCase.
Un
control
TDriveComboBox
puede
estar
asociado
con
un
TDirectoryListBox, cuyo funcionamiento se trata en el apartado
siguiente, de tal forma que en el momento en que seleccionemos una
nueva unidad en el primero, automticamente se cambie a dicha unidad
en el segundo. Para ello lo nico que hemos de hacer es asignar a la
propiedad DirList del TDriveComboBox el nombre del TDirectoryListBox.

7.16.2. Una lista de carpetas


Para mostrar una lista de directorios o carpetas, tendremos que usar
el controlTDirectoryListBox, que es un derivado de TListBox. Este
control muestra la jerarqua de directorios correspondiente a la
unidad facilitada en la propiedad Drive, permitiendo el cambio de un
directorio a otro. La propiedad ms interesante de este control es
Directory, ya que mediante ella podemos recuperar el camino completo
que est actualmente seleccionado en el TDirectoryListBox, sin
necesidad de tener que acceder a los elementos individuales de la
lista. Este directorio puede ser mostrado automticamente en un
control TLabel si lo deseamos, simplemente asignando a la propiedad
DirLabel el nombre de dicho control.
Al
igual
que
unTDriveComboBox
se
puede
asociar
con
un
TDirectoryListBox, ste puede asociarse con un TFileListBox, de tal
forma que al cambiar de directorio automticamente se muestren los
archivos contenidos en l. Para ello deberemos asignar a la propiedad
FileList el nombre del TFileListBox a asociar.
7.16.3. Una lista de archivos
El ltimo de los tres controles, TFileListBox, nos permite ver los
archivos existentes en un cierto camino, que habremos de facilitar en
la propiedad Directory. Este valor se toma automticamente si este
control est asociado a un TDirectoryListBox. Aunque por defecto se
muestran todos los archivos que hay en el directorio, nosotros podemos
limitar esta seleccin modificando el contenido de la propiedad Mask,
a la que asignaremos una cadena conteniendo una o ms referencias de
seleccin. En caso de que sean varias las referendas, deberemos
separar unas de las otras mediante un punto y coma.
Tambin podemos limitar los archivos mostrados en el TFiieListBox
segn sus atributos, mediante la propiedad FileType. Esta propiedad es
un conjunto que puede contener los valores que se muestran en la tabla
7.15, segn los cuales se seleccionarn unos archivos u otros.
Constante
ftNormal
ftReadOnly
ftSystem
ftHidden
ftArchive
ftDirectory
ftVolumeID

Tipo del archivo


Normal.
De slo lectura.
De sistema.
Oculto.
Archivado.
Directorio.
Identificador
volumen.

de

Tabla 7.15. Valores posibles en el conjunto FileType

El nombre del archivo que se encuentra seleccionado en la lista puede


ser obtenido de forma fdl mediante la propiedad FileName, que adems
contiene todo el camino completo, unidad y directorio incluidos. Si
deseamos obtener slo el nombre del archivo, podemos usar las
propiedades tems e Itemindex.
7.16.4. En la prctica
Veamos con un pequeo ejemplo lo simple que es utilizar estos tres
controles de forma conjunta, en este caso con el fin de construir un
visor de archivos grficos, que nos permita ir explorando el sistema y
visualizando el contenido de los archivos BMP, ICO y WMF.
Insertaremos en el formulario un control TDriveComboBox, en la parte
superior izquierda; un TDirectoryListBox, debajo del anterior y
ocupando el resto de la parte izquierda; un TFileUstBox, a la derecha
del primero, y un control TImage, justo debajo de la lista de
archivos. Asocie la lista de unidades con la de directorios, dando el
valor adecuado a la propiedad DirList, y haga lo mismo asociando la
lista de directorios con la de archivos, en este caso con la propiedad
FileList.
Con el fin de mostrar en la lista de archivo tan slo aquellos que
podemos abrir, vamos a asignar a la propiedad Mask la cadena
'*.bmp;*.ico;*.wmf'. Por ltimo, d el valor True a la propiedad
Stretch del control TImage, con el fin de que las imgenes que se
recuperen ajusten su tamao al del control, permitindonos ver la
imagen completa.
Cada vez que se seleccione, en ejecucin, uno de los archivos
mostrados en el TFileListBox, ste generar un evento OnClick, que
nosotros aprovecharemos para abrir el archivo y mostrar su contenido.
Para ello tendremos que escribir el cdigo que se muestra en el mtodo
siguiente.
{ Al seleccionar un archivo de la lista }
procedure TForm1.FileListBox1Click(Sender: Tpbject);
begin
// lo cargamos en el TImage
Image1.Picture.LoadFromFile(FileListBox1.FileName);
end;
No es necesario hacer nada ms, puesto que los controles que muestran
las unidades, directorios y archivos se sincronizan automticamente.
Puede ejecutar el programa, que mostrar un aspecto similar al de la
figura 7.15, y recorrer su sistema visualizando el contenido de los
archivos que se listen en el control TFileUstBox, que habrn de ser
necesariamente imgenes de mapas de bits, iconos o meta-archivos.

Figura 7.15. Aspecto del visor de archivos grficos

7.17. Eventos peridicos


Hasta ahora todos los componentes que hemos conocido han sido
controles, es decir, componentes visuales con los que es posible
interactuar en ejecucin. No todos los componentes de Delphi son de
este tipo, existen tambin algunos que sin ser visibles desempean
funciones muy importantes, como tendremos ocasin de ver, por ejemplo,
en el captulo dedicado a los controles de acceso a bases de datos.
Uno de los componentes no visuales de Delphi es TTimer, un componente
cuya nica finalidad es generar un evento a intervalos regulares con
la frecuencia que nosotros mismos
establezcamos. Este componente es
el primero de la pgina System.
La frecuencia con la que el componente TTimer generar el
evento
OnTimer depender del valor que asignemos a la
propiedad Interval,
que por defecto es 1000. Esta medida est expresada en milisegundos,
lo que quiere decir que por defecto el evento se producir una vez
cada segundo.
Al igual que otros componentes, ste tambin cuenta con la propiedad
Enabled, que nos permite desactivarlo evitando as la generacin del
evento.
7.17.1. En la prctica
Qu mejor ejemplo para comprobar el funcionamiento de un componente
que se llama TTimer que un reloj digital, que cuenta con una serie de

opciones principales, que son visibles en todo momento; basndose en


ellas es posible acceder a listas de subopciones.
El men emergente, por el contrario, no est visible normalmente,
apareciendo tan slo cuando el cdigo del programa lo solicita. Delphi
es capaz de mantener una asociacin entre un men emergente y un
componente, mostrndolo en el momento en que se pulsa el botn derecho
del ratn sobre dicho componente.
7.18.1. Diseo de un men principal
Para crear un men principal deberemos insertar en el formulario un
componente TMainMenu, que encontraremos en la pgina Standard de la
Paleta de componentes. Aunque es posible insertar mltiples TMainMenu
en el formulario, tan slo el primero de ellos ser el que se muestre,
ya que una ventana tan slo puede contar con un men principal.
El siguiente paso consistir en disear el men, para lo cual
tendremos que hacer doble clic sobre el propio componente TMainMenu o
bien sobre el valor de la propiedad tems, en el Inspector de objetos.
En ambos casos aparecer el editor de mens, una ventana en la que
podremos ir introduciendo opciones y desplazndonos entre ellas
construyendo nuestro men.
Inicialmente el Editor de mens aparecer vaco, mostrando tan slo un
recuadro azul en el que podremos iniciar la introduccin del ttulo de
la opcin que deseemos definir. Observe que en el Inspector de objetos
existen una serie de propiedades que hacen referencia a la opcin que
se est definiendo.
Introduzca el ttulo de la primera opcin principal, que se llamar
por ejemplo &Archivo, y pulse la tecla <Intro>, lo que le desplazar a
la lnea siguiente, en la que podr iniciar la introduccin de las
subopciones. Vamos a aadir tres opciones, a las que vamos a llamar
&Guardar, &Recuperar y &Salir.
Insercin y borrado de opciones
En cualquier momento podemos eliminar opciones del men o bien
insertar otras nuevas entre algunas existentes. La primera operacin
la realizaremos simplemente pulsando la tecla <Supr>, mientras que la
segunda la efectuaremos con una pulsacin de la tecla <Insert>.
Sitese encima de la ltima opcin que hemos insertado,
pulse la tecla <Insert>, lo que provocar la apertura de un
blanco. Inserte en ese espacio un guin y pulse <mtro>,
automticamente en el men aparece una lnea de separacin
dos primeras opciones y la ltima.
Teclas de acceso rpido

&Salir, y
espacio en
ver como
entre las

Adems de las letras que precedemos con un signo & en los ttulos de
las opciones y que pueden ser utilizadas conjuntamente con la tecla
<Alt> para acceder de una forma ms rpida, cada opcin puede contar
adems con una tecla "caliente" o de acceso rpido.
Sitese en la opcin &Recuperar y a continuacin despliegue la lista
adjunta a la propiedad ShortCut, en el Inspector de objetos. Ver
aparecer una serie de teclas y combinaciones de tecla. Seleccione la
combinacin <Control+C>, que aparecer indicada en el men a la
derecha de la opcin. De igual forma puede asociar una tecla de acceso
rpido a las dems opciones.
Opciones con ms opciones
Ciertas opciones de un men pueden dar acceso a otras listas de
opciones, lo cual se indica mediante una flecha apuntando hacia la
derecha. El ejemplo ms cercano lo podemos encontrar en la opcin
Reopen del men File de Delphi.
Para aadir una lista de opciones a una opcin del men deberemos
pulsar la combinacin <Control+Flecha der>, o bien desplegar el men
emergente y seleccionar la opcin Crate Submenu. En cualquiera de los
dos casos se abrir una nueva lista a la derecha de la que ya
tenamos, en la que podemos introducir las opciones que deseemos.
Respuesta a la seleccin de una opcin
Al igual que un botn o una lista, un men genera un evento OnClick
cuando se selecciona una cierta opcin. Para acceder al cdigo del
mtodo asociado a una de las opciones existentes, lo nico que tenemos
que hacer es seleccionarla durante el diseo en el mismo formulario,
tras haber cerrado el Editor de mens. Tambin podemos hacer doble
clic sobre la opcin deseada en el propio Editor de mens, continuando
posteriormente con la tarea de diseo.
Observe que cada una de las opciones de
diferente, concretamente de tipo TMenultem,
propio evento, lo cual es lgico, ya que de
que buscar alguna forma de saber qu opcin es

un men es un objeto
y por tanto genera su
lo contrario tendramos
la que" se seleccion.

7.18.2. Construccin de un men emergente


El mtodo de diseo de un men emergente es muy similar al que
acabamos de ver para un men principal, aunque existen algunas
diferencias. La primera de ellas es que el componente a utilizar no es
un TMainMenu, sino un TPopupMenu. Un men emergente, a diferencia de
un men principal, no cuenta con una barra de opciones principales de
la que se despliegan listas de opciones, sino que est compuesto de
una sola lista de opciones, aunque stas pueden a su vez dar paso a
otras/creando subopciones segn lo visto en un punto anterior. En la
figura 7.17 puede ver un momento del diseo de un men emergente.

Figura 7.17. Diseo de un men emergente


Desplegar el men emergente
Como se comentaba anteriormente, un men emergente puede ser
desplegado automticamente, al pulsar el botn derecho sobre el
componente al que est asociado, o bien ser abierto mediante cdigo,
con una llamada al mtodo Popup() del propio TPopupMenu, al que
pasaremos como parmetros dos enteros indicando la posicin en la que
deseamos hacer aparecer la ventana. El mtodo ms habitual es el
primero y tambin el ms cmodo y simple.
Para conseguir que un men emergente se despliegue de forma
automtica, lo primero que tenemos que hacer es dar el valor True a la
propiedad AutoPopup, trabajo que ya tenemos hecho puesto que ese es el
valor por defecto de dicha propiedad. El segundo paso consistir en
crear un enlace entre un componente y el men, para lo cual
asignaremos a la propiedad PopupMenu del primero el nombre del
segundo.
Es posible asociar un TPopupMenu
prcticamente cualquier otro control.

al

formulario,

un

botn

7.18.3. En la prctica
El uso de los mens de opciones es muy simple, ya que prcticamente no
cuentan con ningn elemento adicional a los que ya conocemos.
Practique diseando diversos mens, tanto de tipo TMainMenu como
TPopupMenu, y escribiendo algo de cdigo asociado al evento OnClick de
cada opcin, con el fin de comprobar su funcionamiento.

8. Depuracin y excepciones

8.1. Introduccin
Mientras se desarrolla y ejecuta una aplicacin, generalmente surgen
errores que le impiden funcionar en la forma en que nosotros
esperbamos. Los errores posibles los podemos agrupar en tres bloques:
errores de compilacin, errores de ejecucin y errores lgicos.
Los errores de compilacin, como su propia denominacin indica, son
detectados por Delphi en el momento en que se compila el programa. En
estos casos no se permite la ejecucin, y en la parte inferior de la
Ventana de cdigo se abre una lista con la descripcin del error o
errores encontrados, permitindonos el desplazamiento a la lnea
apropiada. Estos errores se producen cuando se teclea mal un
identificador, una expresin no es vlida, hemos olvidado cerrar unos
parntesis, etc.
Por su parte, los errores de ejecucin no son detectables durante la
compilacin y surgen de forma espordica mientras el programa se
ejecuta. Si no est adecuadamente controlado, un error de ejecucin
puede terminar interrumpiendo la ejecucin de la aplicacin. Estos
errores se producen, por ejemplo, cuando se intenta abrir un archivo y
ste no existe, se realiza una conversin no vlida, etc. Para
controlar estos errores tendremos que conocer y controlar excepciones,
un tema que trataremos ms adelante en este captulo.
El tercer grupo de errores, a los que llamamos lgicos, no son
detectados por Delphi durante la compilacin ni tampoco por el
programa durante la ejecucin. Estos errores no hacen nada incorrecto
sintcticamente hablando pero, sin embargo, impiden que el programa
funcione de forma normal. Errores de ese tipo se producen cuando en
una expresin se ha usado la variable que no corresponda, se llama a
un procedimiento o funcin con un parmetro que no se esperaba, etc.
El nico mtodo por el cual podemos detectar y encontrar estos
errores, aparte de la propia intuicin, consiste en llevar a cabo una
sesin de depuracin.

8.2. Proceso de depuracin


En la actualidad, para depurar un programa se siguen bsicamente dos
tcnicas combinadas entre s, que consisten en ejecutar el cdigo
sentencia a sentencia e inspeccionar valores de variables, objetos,
etc. Este proceso puede ser llevado a cabo mediante una aplicacin
independiente, a la que se llama depurador, o bien desde el propio
entorno de desarrollo, segn los casos.
Delphi incorpora un depurador integrado, por lo que no es necesario
abandonar el entorno de diseo para poder depurar el cdigo de nuestro
programa. A pesar de ello, tambin tenemos la posibilidad de incluir

en el ejecutable la informacin de depurado necesaria


utilizar un depurador separado, como es Turbo Debugger.

para

poder

El depurador integrado de Delphi permite tanto la ejecucin paso a


paso, como la evaluacin de expresiones e inspeccin de objetos, lo
que facilita en gran medida el depurado de un programa.
8.2.1. Estado de ejecucin
El entorno de desarrollo de Delphi puede encontrarse en tres estados
diferentes, a los que vamos a llamar modo de diseo, de ejecucin y de
pausa. El primer estado es el inicial, en el cual podemos modificar
propiedades, escribir cdigo y realizar todas las tareas propias de
diseo.
Cuando ejecutamos un programa desde el propio entorno de Delphi, ste
pasa al estado de ejecucin. Este modo se distingue del anterior
porque en la barra de ttulo de la ventana principal de Delphi aparece
la palabra Running, y tambin por la activacin y desactivacin de
algunos de los botones de acciones rpidas. En este modo el botn de
ejecucin est desactivado, al igual que los de ejecucin paso a paso,
mientras que est activo el botn de pausa o parada.
El tercer estado posible, al que hemos llamado de pausa, se activa
cuando estando en modo de ejecucin se pulsa sobre el botn Pause o se
selecciona la opcin correspondiente del men Run. En este modo la
palabra Running en la barra de ttulo es sustituida por la palabra
Stopped. Tambin se producen cambios en losbotones de acciones
rpidas, desactivndose el de parada o pausa y activndose los de
ejecucin.
En el momento en que se inicia la ejecucin de un programa desde el
propio entorno de desarrollo de Delphi, en realidad estamos ejecutando
dos programas, el nuestro y el propio depurador integrado. En estado
de ejecucin es nuestro programa el que tiene el control, mientras que
en estado de pausa el control lo tiene el depurador. A medida que se
va ejecutando paso a paso, el control pasa alternativamente de nuestro
programa al depurador y viceversa, de tal forma que podemos ir viendo
el
resultado
generado
por
nuestro
programa
al
tiempo
que
inspeccionamos cdigo, expresiones y contenido de objetos.
8.2.2. Ejecucin paso a paso
Como se ha dicho anteriormente, una de las tcnicas ms habituales de
depuracin en la actualidad es la ejecucin paso a paso, ya que
permite ir viendo el resultado generado por la ejecucin de cada
sentencia, al tiempo que se est analizando el cdigo.
A diferencia de lo que ocurre con otras herramientas de desarrollo
visual, Delphi no cuenta con una ventana separada en la que se lleva a
cabo el proceso de depuracin. Por tanto, la ejecucin paso a paso se

efecta en la misma ventana del Editor de cdigo, resaltando en cada


momento la lnea que se va a ejecutar.
La ejecucin paso a paso habitualmente parte del modo de pausa, al que
podemos llegar de diversas formas. Una de ellas consiste en detener la
ejecucin del programa cuando nos interese, pulsando el botn Pause, y
otra en ejecutar hasta una determinada sentencia, por ejemplo
colocando un punto de parada. En cualquier caso, una vez que estemos
en el modo de pausa tendremos acceso a los comandos de depuracin que
vamos a ver a continuacin.
Ejecucin simple de una sentencia
Al encontramos en modo de pausa, en la ventana del Editor de cdigo
aparecer destacada sobre las dems la lnea que se ejecutar en el
siguiente paso. Si no ve esta lnea, utilice la opcin Show Execution
Point del men Run para hacerla aparecer.
Para ejecutar la sentencia marcada puede pulsar el botn Trace Into,
en el rea de botones de acciones rpidas, puede utilizar la opcin
del mismo nombre del men Run o bien puede simplemente pulsar la tecla
<F7>. En cualquier caso, el control se pasar de forma temporal a
nuestro programa, que ejecutar la sentencia, generando el resultado
que corresponda, y devolver de nuevo el control al depurador,
permitindonos as ver cul ser la siguiente sentencia que se
ejecutar.
En caso de que la sentencia que se va a ejecutar sea una llamada a un
mtodo, procedimiento o funcin de nuestro propio programa, al
utilizar el comando Trace Into el punto de ejecucin pasar al cuerpo
de ese bloque de cdigo, facilitndonos su depuracin sentencia a
sentencia.
Ejecucin por procedimientos
Si estamos centrados en la depuracin de un cierto bloque de cdigo,
como puede ser el cuerpo de un procedimiento, al ejecutar cada
sentencia nos puede interesar que el depurador no pase el control a
cada mtodo, procedimiento o funcin al que se
realice una llamada, ya que ello puede desviar nuestra atencin.
En este caso, en lugar
comando Step Over, que
men Run, como con un
simplemente pulsando la

de usar el comando Trace Into utilizaremos el


tenemos accesible tanto como una opcin del
botn. Tambin podemos ejecutar este comando
tecla <F8>.

Suponiendo que el punto de ejecucin se encuentre en una sentencia que


contiene una llamada a un procedimiento de nuestro programa, al
utilizar el comando Step Over automticamente se ejecutar todo el
cdigo de ese procedimiento, de tal forma que el punto de ejecucin

pasar a la
encontramos.

sentencia

siguiente

del

mismo

bloque

en

el

que

nos

Ejecucin hasta un punto


Aunque no es en s un comando de ejecucin paso a paso, una operacin
muy til durante la depuracin consiste en transferir el control a
nuestro programa, continuando con la ejecucin, hasta llegar a una
cierta sentencia. Esto nos permite, por ejemplo, saltar todos los
ciclos de un bucle, o simplemente iniciar la ejecucin del programa,
desde el estado de diseo, detenindola al llegar a esa sentencia.
Para ejecutar hasta un determinado punto del programa, lo primero que
tenemos que hacer es desplazar el cursor, en el Editor de cdigo,
hasta dicho punto. Hecho esto podemos pulsar a tecla <F4>, o bien
usar la opcin Run to Cursor del men Run.
Terminar la ejecucin
La mejor forma de finalizar la ejecucin de un programa, cuando est
en curso un proceso de depuracin, consiste en pulsar la tecla <F9>,
ejecutando el programa de forma normal, y a continuacin seleccionar
la opcin adecuada para salir de la aplicacin de forma normal.
Existe, sin embargo, otro mtodo que nos permite terminar la ejecucin
en el punto en que nos encontremos en ese momento. Para ello bastar
con pulsar la combinacin de teclas <Control+F2> o bien seleccionar la
opcin Program Reset del men Run.
8.2.3. Puntos de parada
Ya hemos visto dos modos mediante los cuales podemos pasar del estado
de ejecucin al de parada, mediante los comandos Pause Program y Run
to Cursor. Un mtodo alternativo a stos consiste en disponer en el
cdigo puntos de parada, unas marcas que indican al depurador que
cuando llegue a una determinada sentencia pare automticamente la
ejecucin del programa, permitindonos iniciar o continuar el proceso
de depuracin a partir de ese punto.
Para activar un punto de parada nos tendremos que desplazar hasta la
sentencia en que deseamos disponerlo, pulsando a continuacin la tecla
<F5>. La lnea de cdigo se destacar del resto, cambiando de color.
Tambin podemos realizar esta misma operadn mediante la opcin Debug>Toggle Breakpoint |del men emergente del Editor de cdigo.
Una vez que hemos colocado los puntos de parada en las sentencias que
nos interesen, pueden ser tantas como necesitemos, podemos iniciar la
ejecucin del programa de forma normal. En el momento en que se vaya a
ejecutar cualquiera de las lneas de cdigo marcadas, el depurador
tomar el control pasando al estado de pausa.

En el momento en que un punto de parada ya no nos sea til o no nos


interese, podremos eliminarlo exactamente de la misma forma en que lo
activamos, es decir, pulsando la tecla <F5> o con la citada opcin del
men emergente.
Puntos de parada condicionales
Los puntos de parada que se acaban de explicar son puntos de parada
incondicionales, puesto que detienen la ejecucin del programa siempre
que se llega a ellos. Aunque esto ser lo apropiado en muchos casos,
en otros, sin embargo, puede resultar en una parada continua del
programa, porque la sentencia de cdigo en que se ha dispuesto la
marca se ejecute con mucha frecuencia.
Para evitar esto podemos colocar un punto de parada condicional, que
se distingue del tipo anterior en que no pasa al estado de pausa
siempre, sino cuando una cierta condicin se cumple o bien cuando por
ese punto de parada se ha pasado un nmero determinado de veces.
Lo primero que tendremos que hacer para colocar en el cdigo un punto
de parada condicional, ser desplazar el cursor hasta la sentencia en
que se va a situar. A continuacin seleccionaremos la opcinAdd
BreakpointoSource Breakpoint del men Run, que har aparecer la
ventana que se muestra en la figura 8.1. Lo primero que vemos en esta
ventana es el nombre del mdulo y la lnea de cdigo en que se va a
colocar el punto de parada, datos que podemos modificar manualmente,
aunque no es lo habitual. A continuacin encontramos dos apartados,
llamados Condition y Pass count, en los cuales podemos introducir una
expresin condicional, que se evale a True o False, y un numero
entero, respectivamente.

Figura 8.1 Creacion de un punto de parada condicional


En la expresin condicional que se utiliza para el punto de parada no
se
pueden
realizar
llamadas
a
procedimientos
y
todos
los

identificadores que se utilicen, de variables u objetos, han de estar


accesibles desde el punto en que se ha dispuesto el punto de parada.
Al ejecutar el programa, cada vez que se pasa por el punto de parada
se evala la expresin, de tal forma que si el resultado es True se
detiene la ejecucin, y se pasa al estado de pausa.
El segundo apartado de la ventana, Pass count, lo podemos utilizar
para introducir un nmero entero que establecer el nmero de veces
que se pasar por el punto de parada antes de que ste provoque la
parada
efectiva
del
programa.
En
ejecucin
el
depurador
va
decrementando este contador que nosotros hemos dispuesto, cada vez que
se pasa por el punto de parada, de tal forma que cuando el valor llega
a ser 1 se pasa al modo de pausa.
Mediante la opcin Debug Windows->Breakpoints del men View podemos
abrir una ventana onteniendo todos los puntos de parada que hemos
dispuesto en nuestro cdigo. De esta forma es mucho ms fcil mantener
un control, ya que adems del nombre del mdulo y la lnea en que se
encuentra cada marca, tambin se muestra la expresin y el contador,
en caso de que el punto de parada sea condicional.
Esta ventana cuenta con un men emergente muy til, en el que
encontraremos opciones que nos permitirn desplazarnos directamente al
cdigo en el que se encuentra un punto de parada, aadir, eliminar,
activar y desactivar marcas.
8.2.4. Inspeccin de valores y evaluacin de expresiones
Aunque el solo hecho de poder ejecutar el cdigo paso a paso puede ser
de gran utilidad, a la hora de buscar los errores lgicos que puedan
existir en un programa, esta tarea se ve mucho ms simplificada desde
el momento en que el depurador nos permite inspeccionar el contenido
de variables y objetos, as como evaluar expresiones conociendo su
resultado. Las opciones que vamos a conocer a continuacin slo estn
disponibles en el estado de pausa, cuando se ha detenido en un punto
la ejecucin del programa que se est depurando.
Para conocer el contenido de una variable o propiedad de forma
inmediata, lo nico que hemos de hacer es situar el cursor del ratn
sobre ella. De forma automtica aparecer una pequea ventana
indicando el valor actual.
Si deseamos conocer el contenido de una variable o evaluar una
expresin no tenemos ms que pulsar la combinacin <Control+F7>, o
bien usar el comando Evaluate/Modify del men Run. Esta misma opcin
tambin est disponible en el men emergente, al que accederemos
pulsando el botn derecho del ratn estando sobre el cdigo.
La ventana de evaluacin y modificacin, cuyo aspecto puede ver en la
figura 8.3, cuenta con un primer apartado, titulado Expression, en el
que nosotros introduciremos el identificador de la variable o la

expresin cuyo contenido o resultado queremos conocer. A continuacin


tendremos que pulsar <Intro>, o el botn Evalate, lo que har
aparecer en el apartado Result el resultado de la evaluacin de la
expresin, o bien el contenido actual de la variable.

Figura 8.3. Evaluacin inmediata de una expresin


En caso de que lo que se haya evaluado sea una variable, adems de
poder ver su contenido tambin podermos modificarlo, introduciendo el
nuevo valor en el apartado New Value y pulsando el botn Modify. Esta
posibilidad nos permite realizar pruebas con diversos valores sin
necesidad de tener que modificar el cdigo.
Visualizadores
Cuando se desea conocer el resultado de una expresin o contenido de
una variable con cierta frecuencia, y no slo en un momento puntual
del proceso de depuracin, en lugar de usar el mtodo que acabamos de
ver lo que haremos ser abrir la ventana de visualizadores,
aadindole un nuevo elemento. Para ello pulsaremos la combinacin
<Control+F5> o bien seleccionaremos la opcin Add Watch del men Run.
En la Ventana que aparece, cuyo aspecto puede ver en la figura 8.4,
facilitaremos el identifcador de la variable o la expresin a
examinar, tras lo cual bastar con pulsar <Intro> o la tecla Ok.
En ese momento ver aparecer una lista con un elemento, conteniendo el
identifcador de variable o expresin y su valor actual.

Figura 8.4. Definicin de un elemento visualizador.


Mediante las opciones existentes en la parte inferior de la ventana,
podremos seleccionar el tipo para mostrar el dato, por ejemplo podemos
mostrar el contenido de una variable numrica en hexadecimal, el
nmero de dgitos con que deseamos que aparezca y un factor de
repeticin, que se utiliza principalmente al trabajar con punteros y
matrices.
La ventana que contiene los visualizadores cuenta con un men
emergente, en el que encontraremos opciones que nos permitirn
modificar las expresiones, eliminar y aadir elementos de la lista.
8.2.5. Pila de llamadas
Cuando la ejecucin del programa se encuentra detenida en un
determinado punto, hasta el que se ha llegado mediante un punto de
parada o alguno de los comandos de ejecucin paso a paso que ya
conocemos, podemos no tener claro cmo se ha llegado hasta ese punto.
Esto suele ocurrir, sobre todo, cuando depuramos un procedimiento que
es llamado desde distintos puntos de la aplicacin.
Este problema encuentra una solucin rpida y simple en la opcin
Debug Windows->Call Stack del men View, que hace visible la ventana
que contiene la pila de llamadas. Esta ventana, cuyo aspecto se
muestra en la figura 8.5, muestra en orden inverso los nombres de los
procedimientos por los que se ha pasado hasta llegar al punto actual,
lo que nos permite saber de forma inmediata cual ha sido la secuencia
que se ha seguido.

Figura 8.5. La pila de llamadas


8.3. Control de excepciones
Entre los grupos de errores que se comentaban al principio de este
captulo, haba una categora a los que denominbamos errores de
ejecucin. Estos errores no son detectados durante la compilacin y
difcilmente pueden solucionarse en una tarea de depuracin, ya que
ms que errores nuestros, de codificacin o lgica, son errores que
vienen provocados por alguna causa externa.
Tome cualquiera de los ejemplos del captulo anterior, en los quese
guarda o recupera informacin en un archivo en disco, por ejemplo el
programa de dibujo a mano alzada. A continuacin facilite un nombre de
archivo inexistente y pulse el botn Recupe rar. Ver aparecer una
ventana indicando que no se encuentra el archivo y que se produce una
excepcin. ste es un error de ejecucin.
Una de las formas ms eficientes de controlar los errores de ejecucin
consiste en interceptar las excepciones que producen, actuando en
consecuencia. El control de excepciones en Object Pascal es muy simple
gracias a la construccin Try/Except, que vamos a conocer a
continuacin.
8.3.1. La construccin Try/Except
En el cdigo de un programa, slo algunas sentencias o bloques de
sentencias son susceptibles de generar errores de ejecucin. Una
simple asignacin a una variable, por poner un ejemplo, nunca generar
una excepcin. Si est expresada correctamente se ejecutar o, en caso
contrario, producir un error de compilacin o dar pie a un error
lgico.
Lo primero que tenemos que hacer para poder controlar los errores de
ejecucin, es identificar los bloques de cdigo en que pueden tener
lugar, ya que sern esos bloques los que haya que proteger mediante la
construccin Try/Except. Son susceptibles de generar errores de
ejecucin, por ejemplo, las sentencias en que se accede a un
dispositivo extemo, como puede ser el disco, o bien cuando se realiza
una asignacin de memoria.

La sintaxis de Try/Except es la que se muestra en el fragmento


siguiente, en el que podemos distinguir unas sentencias a proteger,
que son las dispuestas detrs de la palabra Try, y unas sentencias que
se ejecutarn slo en caso de que se produzca una excepcin, que son
las escritas a continuacin de la palabra Except. La construccin se
finaliza con la palabra End, de tal forma que la ejecucin siempre
continuar con la sentencia siguiente, tanto si se ha generado la
excepcin como si no.
Try
SentenciaAProteger;
Except
SentenciaDeControl;
End;
Tanto tras la palabra Try como tras la palabra Except podemos disponer
mltiples sentencias sin necesidad de crear un bloque Begin/End, ya
que las palabras Try/Except forman un bloque y Except/End forman otro.
8.3.2. Clases de excepciones
Mediante un bloque Try/Except/End, como el mostrado en el punto
anterior, podemos controlar cualquier tipo de excepcin, sin importar
su tipo. Es posible, sin embargo, ejecutar unas sentencias u otras
segn que la excepcin haya venido provocada por una causa u otra.
Para poder llegar a diferenciar las excepciones tendremos que conocer
sus clases.
Las excepciones, al igual que otros muchos elementos de Delphi, son
objetos que tienen una cierta jerarqua, existiendo una clase de
excepcin base o genrica de la cual se van derivando clases ms
especficas. Existe, por ejemplo, una clase de excepcin llamada
EIntError de la que estn derivadas todas las clases de excepciones
relacionadas con nmeros enteros, como ERangeError o EDivByZero.
Para controlar la clase de excepcin, detrs de la palabra Except
podemos disponer una o varias lneas con la sintaxis OnClaseExcepcion
Do, donde ClaseExcepcion ser EIntError, EDivByZero o cualquier otra
clase de excepcin existente.
Detrs de la palabra Do podemos disponer una sentencia o un bloque,
que se ejecutar tan slo en caso de que la excepcin que se ha
producido sea de la clase indicada.
8.3.3. En la prctica
Para comprobar el funcionamiento de las excepciones y ver cmo podemos
controlarlas, vamos a disear un pequeo, programa que nos permita
realizar divisiones, para lo cual tendremos que facilitar el dividendo
y divisor.

Inserte en un formulario tres controles TEdit, uno debajo de otro,


precedidos de tres controles TLabel con las cadenas de texto
'Dividendo', 'Divisor' y 'Cociente'. Inserte a la derecha un control
TButton, con el ttulo 'Calcular'. D el valor True a la propiedad
ReadOnly del tercer TEdit, ya que ste ser slo para mostrar el
resultado de la operacin y no para que el usuario introduzca un
valor.
Seleccione conjuntamente los dos primeros controles TEdit, abra la
pgina de eventos en el Inspector de objetos y haga doble clic sobre
el evento OnKeyPress, en cuyo mtodo escribiremos el cdigo que se
muestra a continuacin, con el fin de controlar la entrada de
caracteres.
{ Con cada pulsacin en los controles TEdit }
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
{ Si no es un dgito numrico ni la tecla de borrado }
If Not (Key In ['0'..'9',#8]) Then
Key := #0; { ignoramos la pulsacin }
end;
Por ltimo haga doble clic sobre el TButton, para abrir el mtodo
correspondiente al evento OnClick y escriba el cdigo siguiente.
{ Al pulsar el botn Calcular }
procedure TForm1.Button1Click(Sender; TObject);
Var
Dividendo, Divisor, Cociente: Integer;
begin
Try
{ Obtenemos el dividendo y el divisor }
Dividendo := StrToInt(Edit1.Text);
Divisor := StrTolnt(Edit2.Text);
{ Realizamos la operacin }
Cociente := Dividendo Div Divisor;
{ y mostramos el resultado }
Edit3.Text := IntToStr(Cociente);
Except { Si se produce una excepcin }
{ segn la clase mostramos un mensaje u otro }
On EDivByZero Do
ShowMessage('El divisor no puede ser cero');
On EConvertError Do
ShowMessage ('El dividendo o divisor no son vlidos');
On EIntError Do
ShowMessage('Se produce un error desconocido');
End;
end;
Como puede ver, controlamos tres clases de excepciones diferentes. La
primera de ellas, EDivByZero, se producir en el momento en que

facilitemos como divisor el nmero 0, realizando una divisin por


cero. La segunda, EConvertError, tiene lugar cuando hay un fallo de
conversin, lo que puede ocurrir si introducimos como dividendo o
divisor un nmero demasiado grande. Por ltimo tenemos la clase
EIntError, que es una excepcin ms genrica que engloba cualquier
otro error con nmeros enteros.
Al
ejecutar
el
programa
podr,
bsicamente,
realizar
tres
comprobaciones: realizar una divisin sin problemas, facilitando un
dividendo y un divisor normales; provocar una divisin por cero, dando
como divisor el nmero cero, o bien provocar un error de conversin,
introduciendo en el dividendo o divisor un nmero extenso. En la
figura 8.6 puede ver el programa en funcionamiento indicando que se ha
producido un error en la introduccin de datos.

Figura 8.6. El programa indicando que se ha producido una excepcin

9. Uso de mltiples ventanas

9.1. Introduccin
Los ejemplos que se han propuesto hasta ahora, en captulos
anteriores, han sido tan simples que estaban compuestos de slo un
formulario. En la prctica, la mayora de los programas se sirven de
mltiples ventanas, lo podemos ver, por ejemplo, en Delphi. Por regla
general siempre existe una ventana principal, en la que se encuentra
el men de opciones, y una serie de ventanas accesorias que pueden
estar visibles siempre o slo cuando son necesarias. En el captulo
anterior, por ejemplo, vimos cmo podamos abrir ventanas con puntos
de parada, visualizadores, una pila de llamadas, etc., ventanas que
habitualmente no estn visibles a diferencia del formulario, el Editor
de cdigo o el Inspector de objetos.
Un programa puede utilizar mltiples ventanas simplemente para
solicitar una determinada informacin, como puede ser el nombre del
archivo que se desea recuperar o el color que se quiere utilizar, o
bien para facilitar la edicin de mltiples documentos. Las ventanas
del primer tipo se suelen construir como cuadros de dilogo, nombre
con el que se conoce a aquellas ventanas que no pueden ser
redimensionadas, no cuentan con botones de maximizar o minimizar y que
adems son modales, no permitiendo seguir trabajando con la aplicacin
hasta en tanto no son cerradas. Un cuadro de dilogo es lo que
aparece, por ejemplo, cuando seleccionamos la opcin de abrir un
proyecto existente. En caso de que el programa sea capaz de permitir
el trabajo con mltiples documentos de forma simultnea, stos puebien
en una interfaz de documento mltiple, que se conoce como MDI. Delphi
utiliza una ventana independiente para cada formulario y para el
cdigo, Microsoft Word 97, por ejemplo, usa una interfaz MDI.

9.2.Trabajo con mltiples formularios


Ya en un captulo anterior conocimos las opciones que nos permitan
crear nuevos formularios, bien partiendo de cero o desde diseos
almacenados en el Depsito de objetos. Cada vez que aadimos un nuevo
formulario al proyecto, tambin se aade un nuevo mdulo de cdigo,
conteniendo la definicin del formulario y el cdigo asociado a sus
eventos.
Cuando una aplicacin cuenta con varios formularios, es muy normal
tener la necesidad de hacer referencia a uno desde otros. De hecho,
esto es fundamental ya que de lo contrario no sera posible ir
mostrando los formularios adicionales desde la ventana principal. Para
poder hacer referencia a un formulario desde un mdulo de cdigo que
no es el suyo, deberemos aadir a la clusula Uses de dicho mdulo el
nombre del mdulo en el que est definida el formulario al que
deseamos acceder. La forma ms fcil de hacer esto es utilizar la

opcin Use Unit del men File, que nos mostrar una ventana en la que
podremos seleccionar directamente el mdulo a usar.
9.2.1. El formulario principal del programa
En un proyecto tan slo puede existir un formulario principal, que es
aquella que se muestra inicialmente cuando se ejecuta el programa. Por
defecto el formulario inicial es aquel que exista al comenzarse el
proyecto o el que se insert en primer lugar si es que el proyecto
estaba vaco.
Realmente el formulario principal no cuenta con ninguna diferencia
especial respecto a los otros formularios y cualquiera de ellos puede
actuar como formulario principal. Para establecer el formulario
principal del proyecto deberemos utilizar la opcin Options del men
Project, que dar paso a una ventana como la que se muestra en la
figura 9.1. En esta ventana existe una lista desplegable, en la parte
superior, en la que podremos indicar qu formulario actuar como
principal.

Figura 9.1. Seleccin del formulario principal del proyecto


9.2.2. Formularios creados automticamente y formularios disponibles
El resto de los formularios del proyecto, aquellos que no son el
formulario principal, pueden ser creadas automticamente, al iniciarse

el programa, o bien quedar como formularios disponibles,


nosotros responsables de su creacin y liberacin.

siendo

Un formulario autocreado se crea en el cdigo incluido por Delphi en


el archivo de proyecto, de tal forma que nosotros podemos utilizar ese
formulario en cualquier momento, sin tener que preocupamos de ningn
proceso de preparacin. Por tanto podemos mostrarla, acceder a sus
propiedades y componentes.
Los formularios disponibles son aquellos que no se crean inicialmente,
contando el programa tan slo con una plantilla o definicin de sus
caractersticas. Para poder utilizar un formulario disponible lo
primero que tendremos que hacer ser crearlo, tras esta operacin el
formulario podr ser utilizada como cualquier otro, sin diferencias
con los formularios creados automticamente. Cuando el formulario deje
de sernos til deberemos destruirlo, liberando la memoria que ocupa.
Para
indicar
a
Delphi
qu
formulario
debern
ser
creados
automticamente y cules quedarn como formularios disponibles,
utilizaremos la misma opcin que nos lleva a la venta mostrada en la
figura 9.1. En esta ventana la lista de la izquierda contiene los
formularios que se crean automticamente, mientras que la de la
derecha almacena aquellas que quedarn disponibles. Podemos utilizar
los botones centrales para desplazar formularios de una lista a otra,
tambin podemos arrastrar y soltar las formularios.
Creacin de un formulario disponible
Como se ha dicho anteriormente, un formulario disponible no puede ser
utilizado directamente puesto que lo que existe en el programa es un
tipo y no una variable, y un tipo no puede ser usado nada ms que para
declarar variables de este tipo. Por ello no puede usar el
identificador TForm2, por poner un caso, para acceder a un formulario,
de igual forma que no usa el identificador Integer para acceder a un
nmero.
La declaracin de una variable que va a contener una referencia a un
formulario se realiza segn la sintaxis que ya conocemos, no hay
ninguna novedad. La nica diferencia est en que la variable no
contiene un valor ordinario, como puede ser un nmero o una cadena,
sino una referencia a un objeto.
Al declarar la variable, por tanto, lo que estamos haciendo es
reservar espacio para almacenar esa referencia, pero no estamos
realmente creando el objeto.
La creacin de un formulario se realizar mediante un constructor, un
mtodo especial que se encarga de asignar la memoria necesaria y
llevar a cabo todo el proceso de inicializacin preciso. Este
constructor se llama Create() y necesita como nico parmetro una
referencia a un componente, que ser el dueo del formulario que se

est creando. Si deseamos que el formulario sea dueo de s mismo y,


por tanto, de su memoria y recursos, pasaremos como parmetro la
palabra Self.
Suponiendo que tenemos un proyecto con dos formularios, la declaracin
siguiente creara una variable para contener una referencia al segundo
formulario, mientras que la nica sentencia existente creara el
formulario y almacenara la referencia en la variable formulario. A
partir de ese momento podemos utilizar esta variable para acceder al
formulario.
Var
Formulario: TForm2;
Begin
Formulario := TForm2.Create(Self);
Al igual que es posible declarar mltiples variables de un mismo tipo,
tambin podemos crear varios formularios a partir de la misma
plantilla disponible. Esto nos permite, por ejemplo, construir
aplicaciones capaces de trabajar con mltiples documentos.
Destruccin de un formulario
Cuando un formulario ha sido creado automticamente por el cdigo del
propio proyecto, no tenemos por qu preocuparlos, por su destruccin,
ya que de ello se encargar autocmticamente el programa. Sin embargo,
cuando el formulario lo hemos creado nosotros mismos, segn lo visto
en el punto anterior, deberemos ser nosotros los que la destruyamos,
liberando la memoria que ocupa.
Para destruir un formulario no tenemos ms que realizar una llamada al
mtodo Release() que, tras unas comprobaciones en las que se asegurar
que no est en ejecucin ningn mtodo asociado al formulario,
liberar la memoria que se ocup durante la creacin.
Si deseamos que un formulario sea automticamente destruido cuando el
usuario la cierre, podemos utilizar el evento OnClose, asignando al
parmetro variable Action el valor caFree.
9.2.3. Visualizacin de un formulario
A1 igual que otros componentes, un formulario cuenta con un mtodo
Show() que nos permite hacerla visible, as como un mtodo Hide()
mediante
el
cual
podemos
ocultarla.
Tambin
podemos
acceder
directamente a la propiedad Visible, asignndole el valor True o False
segn deseemos mostrar u ocultar el formulario, respectivamente.
Un formulario que se muestra por los mtodos anteriores es una ventana
no modal, lo que significa que el usuario puede acceder a otras
ventanas del mismo programa sin necesidad de cerrar sta. Este es el
tipo lgico de visualizacin cuando la ventana va a servir para editar

un documento o simplemente mostrar una informacin. Sin embargo, si la


ventana que se muestra modifica en algn aspecto el entorno del
programa, abriendo un archivo, alterando opciones generales, etc., no
debera permitirse el acceso al resto de las funciones de la
aplicacin hasta en tanto el formulario no sea cerrado.
Para conseguir que un formulario tome el control absoluto de la
aplicacin mientras est visible, no permitiendo el acceso al resto de
las ventanas, lo nico que hemos de hacer es mostrarla como ventana
modal. Para ello bastar con utilizar el mtodo ShowModal(), en lugar
del mtodo Show().
9.2.4. MDI
Anteriormente comentamos brevemente lo que era MDI, una interfaz de
documento mltiple cuya finalidad es facilitar la edicin simultnea
de varios documentos, bien sean stos del mismo tipo o de tipos
diferentes. En una interfaz MDI existe una ventana principal o marco,
que es la que cuenta con el men de opciones, la barra de botones,
lnea de estado, etc., y una o ms ventanas hija.
Las ventanas hija MDI siempre se visualizan en el interior de la
ventana marco, no pudiendo extenderse ms all de ella. Si minimizamos
una ventana hija, sta se mostrar como un icono en la parte inferior
de la ventana marco. Si la maximizamos, ocupar todo el espacio
disponible en dicha ventana.
Ya sabemos cmo definir un cierto formulario como ventana marco o
ventana hija MDI, mediante la propiedad FormStyle, y tambin hemos
aprendido a crear formularios dinmicamente, mediante el constructor
Create(). Partiendo de estos conocimientos, necesitamos saber muy poco
ms para poder crear una aplicacin con interfaz MDI.
Aquellas formularios que van a actuar como ventanas hija debern ser
definidas como formularios disponibles y no autocreadas, ya que
durante la ejecucin, por regla general, ser necesario crear
mltiples ventanas hija, realizando las llamadas necesarias al
constructor Create().
La ventana principal o marco cuenta con una serie de propiedades y
mtodos que facilitan la gestin de las ventanas hija. La propiedad
MDIChildCount contiene el nmero de ventanas hija existentes, mientras
que ActiveMDIChild almacena una referencia a la ventana hija que en
ese momento tiene el foco de entrada. Mediante los mtodos Cascade() y
Tile() podemos disponer las ventanas hija existentes en ese momento
solapadas unas sobre otras o bien en forma de mosaico, mientras que el
mtodo Arrangelcons() nos permite ordenar las ventanas que en ese
momento estn minimizadas.

9.3. Cuadros de dilogo de uso comn


La mayora de las aplicaciones Windows cuentan con opciones que
permiten guardar y recuperar informacin, imprimir datos, seleccionar
tipos de letra o colores, etc. Para cada una de estas funciones sera
necesario disear un determinado tipo de formulario que, en el caso de
Delphi, podra almacenarse en el Depsito de objetos y ser usado
posteriormente en cualquier otra aplicacin.
Sin embargo, las funciones citadas son tan comunes que Windows
incorpora una serie de cuadros de dilogo que facilitan la peticin de
esos datos. Estos cuadros de dilogo estn representados en Delphi
mediante una serie de componentes que vamos a ver a continuacin, por
lo que lo nico que tendremos que hacer ser insertarlos en el
formulario y usarlos.
Los componentes que permiten el acceso a los cuadros de dilogo de uso
comn de Windows estn en la pgina Dialogs de la Paleta de
componentes.
9.3.1. Abrir y guardar archivos
Seguramente las dos funciones ms habituales en una aplicacin,
indistintamente de su tipo, son las de guardar y recuperar
informacin. Para ello lo normal es solicitar al usuario un nombre de
archivo,
permitiendo
adicionalmente
especificar
una
unidad
y
directorio de destino. Toda esta informacin, que en programas
anteriores hemos solicitado directamente en un control TEdit, puede
ser gestionada de una forma mucho ms atractiva, visualmente hablando,
mediante los componentes TOpenDialog y TSaveDialog.
Estos dos componentes cuentan con muchos elementos en comn, siendo
prcticamente iguales en su funcionamiento.
Las propiedades de que disponen tienen por finalidad configurar el
aspecto y comportamiento de la ventana en la que se solicitar el
nombre del archivo, ventana que se har visible en el momento en que
realicemos una llamada al mtodo Execute(). Este mtodo devolver un
valor de tipo Boolean, que ser True en caso de que el usuario haya
seleccionado un archivo o False en caso contrario.
La ventana mostrada por estos dos componentes tendr un ttulo, cuyo
texto podemos facilitar en la propiedad Title.
Mediante la propiedad InitialDir tenemos la posibilidad de fijar
un directorio inicial, mientras que FileName nos servir para asignar
un nombre de archivo por defecto. A la salida, cuando el usuario haya
cerrado la ventana, utilizaremos esta misma propiedad para obtener el
nombre del archivo seleccionado.

Por defecto, en la lista que ocupa la parte central del cuadro de


dilogo se mostrarn los nombres de todos los archivos existentes en
el directorio actual. Si lo deseamos podemos limitar el nmero de
archivos visibles, facilitando unas referencias de seleccin, que
asignaremos a la propiedad Filter. En modo de diseo nos resultar muy
fdl trabajar con esta propiedad, ya que cuenta con un editor
especfico qu nos permite introducir el ttulo de cada filtro y la
referencia a utilizar. Estos datos son convertidos posteriormente en
una cadena, que es el valor que se asigna a la propiedad Filter. En
caso de que facilitemos varios filtros, de tal forma que en ejecucin
el usuario pueda seleccionar el que ms le interese, podemos indicar
cual ser el filtro usado por defecto mediante la propiedad
FilterIndex.
Cuando en un cuadro de dilogo de este tipo se introduce el nombre de
un archivo teclendolo directamente, en lugar de seleccionndolo de
una lista, es habitual omitir la extensin, que se da por asumida. En
Delphi, por ejemplo, no es necesario indicar que los mdulos tienen
extensin PAS y los proyectos extensin DPR. Si queremos facilitar una
extensin por defecto, que ser la que se use siempre que el usuario
no indique otra diferente, no tenemos mas que asignarla a la propiedad
DefaultExt, omitiendo el punto inicial.
Ciertos aspectos del funcionamiento de los cuadros de dilogo
TOpenDialog y TSaveDialog vendrn determinados por los valores que
contenga la propiedad Options. Esta propiedad es un conjunto que puede
estar formado por los valores que se enumeran en la tabla 9.1. Algunas
de las opciones slo son aplicables a uno de los dos componentes y, de
hecho, no aparecern en el Inspector de objetos si no son aplicables.
La opcin ofOverwritePrompt, por ejemplo, slo tiene sentido al
guardar un archivo y no al recuperarlo.
Constante

Significado

ofAllowMultiSelect

Permitir la seleccin de mltiples archivos.


Si se intenta abrir un archivo que no existe
pregunta si se desea crear.
El archivo seleccionado debe existir.
Ocultar la opcin de abrir como slo lectura.
Restablecer el directorio original.
No comprobar la validez del nombre introducido.
Si al guardar se selecciona un archivo existente,
preguntar si se desea sobreescribir.
Marca la opcin de abrir como slo lectura.
El camino seleccionado debe existir.
Mostrar un botn de ayuda.

ofCreatePrompt
ofFileMustExist
ofHideReadOnly
ofNoChangeDir
ofNoValidate
ofOverWritePrompt
ofReadOnly
ofPathMustExis
ofShowHelp

Tabla 9.1 Opciones para TopenDialog y TsaveDialog

Con el fin de realizar una prueba muy simple, inserte en un formulario


un componente TOpenDialog o TSaveDialog y un componente TButton. A
continuacin establezca el ttulo para la ventana, introducindolo en
la propiedad Title, y facilite tambin un filtro, por ejemplo
asignando a la propiedad Filter el valor 'Archivos de texto | *.txt'.
A continuacin haga doble clic sobre el TButton, con el fin de abrir
el mtodo asociado al evento OnClick, y escriba el cdigo siguiente.
procedure TForm1.Button1Click(Sender: TObject);
begin
If OpenDialog1.Execute Then
ShowMessage('Se ha seleccionado un archivo')
Else
ShowMessage('Se ha salido sin elegir un archivo');
end;
Al ejecutar el programa tan slo podr pulsar el botn, ya que ste
ser el nico control del formulario. Al hacerlo aparecer el cuadro
de dilogo comn que se muestra en la figura 9.2, pudiendo seleccionar
un archivo cualquiera. Al salir aparecer un mensaje indicndonos si
hemos elegido o no un archivo.

Figura 9.2. Aspecto del cuadro de dilogo TOpenDialog


9.3.2. Tipos y atributos de letra
Cuando necesitemos solicitar al usuario de nuestro programa la
seleccin de un tipo, tamao y atributos para el texto, el mtodo ms
fcil consiste en usar el componente TFontDialog.
Este componente muestra un cuadro de dilogo en el que es posible
seleccionar uno de los tipos de letra disponibles en el sistema,
elegir un tamao, indicar atributos y color.

La propiedad ms interesante de este componente es Font, ya que


mediante ella podemos indicar cules sern las opciones seleccionadas,
antes de mostrar el cuadro de dilogo, y posteriormente recoger las
opciones elegidas por el usuario, una vez que la ventana ha sido
cerrada.
Antes de mostrar el cuadro de dilogo podemos tambin limitar el
tamao de letra seleccionable, indicando un mnimo y un mximo en las
propiedadesMinFontSize y MaxFontSize. Por ltimo, podemos limitar o
modificar las opciones disponibles mediante la propiedad Options, que
puede contener los elementos que se enumeran en la tabla 9.2.
Constante
fdAnsiOnly
fdEffects
fdFixedPitchO
nly
fdForceFontEx
ist
fdLimitSize
fdNoFaceSel
fdNoOEMFonts
fdScalableOnl
y
fdNoSimulatio
ns
fdNoSizeSel
fdNoStyleSel
fdNoVectorFon
ts
fdShowHelp
fdTrueTypeOnl
y

Significado
Mostrar slo tipos de letras con conjunto de
caracteres Windows.
Mostrar las opciones de tachada, subrayada y
color del texto.
Mostrar slo tipos de letras de espaciado fijo.
Avisar al usuario en caso de que seleccione un
tipo de letra no disponible.
Limitar el tamao de la letra al rango facilitado
en MinFontSize y MaxFontSize.
No seleccionar un tipo de letra inicial.
Mostrar slo tipos de letra no vectoriales.
Mostrar slo tipos de letra escalables.
No mostrar tipos de letras que sean simulaciones.
No seleccionar un tamao de letra inicial.
No seleccionar un estilo inicial.
Igual a fdNoOEMFonts.
Mostrar un botn de ayuda.
Mostrar slo tipos de letra TrueType.

Mostrar slo tipos de letra disponibles


pantalla e impresora.
Tabla 9.2. Opciones del componente TFontDialog

fdWysiwyg

en

Hagamos una simple comprobacin del funcionamiento de este componente,


incluyendo en el formulario un TFontDialog y un TButton. Haga doble
clic sobre el botn y escriba el cdigo siguiente.
procedure TForm1.Button1Click(Sender: TObject);
begin
FontDialog1.Font := Button1.Font;
If FontDialog1.Execute Then Button1.Font := FontDialog1.Font;

end;
Como puede ver, seleccionamos inicialmente en el cuadro de dilogo el
tipo, tamao y estilo de letra del propio botn, mostrando a
continuacin la ventana que puede ver en la figura 9.3. En caso de que
se pulse el botn Aceptar, se asigna al botn la propiedad Font del
cuadro de dilogo, aplicando as la seleccin que hayamos efectuado.

Figura 9.3. Aspecto del cuadro de dilogo TFontDialog


9.3.3. Seleccin de colores
El funcionamiento del cuadro de dilogo TColorDialog, cuya finalidad
es permitir la seleccin de un color, es parecido al que hemos visto
en el apartado anterior, en el sentido de que dispone de una
propiedad, llamada Color, que nos servir tanto para especificar el
color seleccionado inicialmente al mostrar el formulario como para
recuperar el color que se eligi, una vez que la ventana ha sido
cerrada.
Adems de la propiedad Color, el componente TcolorDialog tan slo
cuenta con otra propiedad relevante, llamada Options, mediante la cual
podemos alterar el comportamiento del cuadro de dilogo. Esta
propiedad puede tomar los elementos que se indican en la tabla 9.3.

Constante

Significado

cdShowHelp

Mostrar un botn de ayuda.


Abrir inicialmente la paleta
de color.
Impedir la apertura de la
paleta de color.

cdFullOpen
cdPreventFullO
pen

Tabla 9.3. Opciones para el componente TColorDialog


El cuadro de dilogo de seleccin de color tiene dos partes. En la
primera, que siempre se muestra abierta y ocupa la parte izquierda de
la ventana, existe una matriz d rectngulos con una serie de colores,
de los cuales podemos elegir directamente cualquiera de ellos. La
segunda parte de la ventana, que puede estar o no abierta, es la
paleta de color, y en ella se muestran todos los colores posibles.
Vamos a sustituir en el formulario de la prueba
TFontDialog por un TColorDialog y a modificar
evento OnClick del botn, para que quede
continuacin. En la figura 9.4 puede ver el
seleccin de color, que nos permitir modificar
formulario, gracias al cdigo que hemos escrito.

anterior el componente
el cdigo asociado al
como se muestra a
cuadro de dilogo de
el color del fondo del

procedure TForm1.Button1Click(Sender: TObject);


begin
ColorDialog1.Color := Color;
If ColorDialog1.Execute Then
Color := ColorDialog1.Color;
end;
9.3.4. Opciones de impresin y configuracin de impresora
Existen dos cuadros de dilogo relacionados con la impresin. Uno de
ellos nos servir para solicitar opciones de impresin tales como el
rango de pginas a imprimir o el nmro de copias. El segundo
permitir al usuario realizar tareas de configuracin, tales como la
seleccin del tamao del papel, su orientacin, el cargador que desea
utilizar, etc.
Mediante el componente TPrintDialog accederemos al cuadro de dilogo
de opciones de impresin. Como es habitual, antes de mostrar esta
ventana podemos configurar algunos aspectos de su funcionamiento. La
mayora de las propiedades que vamos a ver nos sirven tanto para
seleccionar un valor por defecto, antes de mostrar el cuadro de
dilogo, como para obtener, posteriormente, la seleccin que ha
efectuado el usuario.

Figura 9.4. Aspecto del cuadro de dilogo TColorDialog


A la hora de imprimir un documento, el usuario puede tener la
posibilidad de indicar qu parte es la que desea imprimir. Podemos
conocer la seleccin del usuario gracias a la propiedad PrintRange,
que contendr uno de los valores mostrados en la tabla 9.4. En caso de
que esta propiedad tenga el valor prPageNums, el rango de pginas a
imprimir vendr determinado por las propiedades FromPage y ToPage.
Podemos limitar el nmero de pginas que el usuario puede seleccionar
dando un valor mnimo a la propiedad MinPage y un valor mximo a la
propiedad MaxPage.
Constante
prAllPages
prSelection
prPageNums

Se imprimir
Todo el documento.
La parte del documento que est seleccionada.
Un rango de pginas.

Tabla 9.4. Valores posibles para la propiedad PrintRange


En la ventana de opciones de impresin tambin es posible facilitar un
nmero de copias, que recuperaremos mediante la propiedad Copies, y
una indicacin de si stas han de imprimirse en secuencia, todas las
copias de una misma pgina, o bien ordenadas, todas las pginas de una
copia.
Al igual que en los
anteriores, en ste
contener una serie de
desactivar algunas de

componentes que ya hemos visto en los puntos


tambin existe una propiedad Options capaz de
elementos, mediante los cuales podemos activar o
las opciones del cudro de dilogo de impresin.

En la tabla 9.5 se enumeran estas opciones, indicndose la finalidad


de cada una de ellas.
Constante

Significado

poHelp

Mostrar un botn de ayuda.


Permitir la seleccin de un rango de
pginas.
Permitir
la
impresin
del
texto
seleccionado.
Mostrar una opcin de impresin a archivo.
Mostrar un mensaje de aviso si no hay
impresora instalada.

poPageNums
poSelection
poPrintToFile
poWarning

Tabla 9.5 Opciones para el componente TPrintDialog


Tenga en cuenta que el cuadro de dilogo de opciones de impresin tan
slo sirve para solicitar unos datos, pero no lleva a cabo ningn
proceso de impresin, de igual forma que el cuadro de dilogo de
apertura de un archivo tan slo es til para obtener un nombre de
archivo, pero no para realizar la apertura en s. En la figura 9.5
puede ver el aspecto de este cuadro de dilogo.

Figura 9.5. Aspecto del cuadro de dilogo TPrintDialog


El componente TPrinterSetupDialog, por su parte, nos permite mostrar
un cuadro de dilogo de configuracin de impresora. Este es el
componente ms simple de los existentes en la paleta Dialogs, ya que
tan slo disponemos del mtodo Execute() para hacer aparecer la

ventana, sin contar con opciones ni propiedades adicionales. En la


figura 9.6 puede ver el aspecto de este cuadro de dilogo.

Figura 9.6. Aspecto del cuadro de dilogo TPrinterSetupDialog


9.3.5. Bsquedas y sustituciones
Las aplicaciones en las que se trabaja con documentos de texto suelen
fadlitaroperaciones de bsqueda y bsqueda y sustitucin. Para iniciar
una operacin de este tipo, el usuario
tiene que introducir
inicialmente alguna informacin, como la cadena a buscar, la cadena
que se desea poner en su lugar y otras opciones adicionales.
Mediante los componentes TFindDialog y TreplaceDialog podremos
solicitar al usuario los datos necesarios para realizar una bsqueda o
una bsqueda y sustitucin. Estos dos cuadros de dilogo son muy
similares, como vamos a ver a continuacin.
Antes de mostrar el cuadro de dilogo podemos configurar su
funcionamiento, para lo cual daremos los valores adecuados a la
propiedad Options. En la tabla 9.6 se enumeran las opciones
disponibles, indicndose la finalidad de cada una de ellas. Como podr
observar, algunasde las opdones tan slo son aplicables a la operacin
de bsqueda y sustitucin. La propiedad Options tambin puede ser
utilizada, una vez que el usuario cierra la ventana, para comprobar la
activacin de algunas opciones.
Constante

Significado

frDown
frFindNext

Realizar la bsqueda hacia abajo.


Se ha pulsado el botn de Buscar siguiente.

frHideMatchCase
frDisableMatchCase
frHideWholeWord
frDisableWholeWord
frHideUpDown
frMatchCase
frWholeWord
frReplace
frReplaceAll
frShowHelp

Ocultar la opcin de coincidencia entre


maysculas y minsculas
Desactivar la opcin de coincidencia entre
maysculas y minsculas.
Ocultar
la
opcin
de
buscar
palabras
completas.
Desactivar la misma opcin anterior.
Ocultar
los
botones
de
seleccin
de
direccin.
La opcin de coincidencia entre maysculas y
minsculas est activada.
La
opcin
de
palabras
completas
est
activada.
Indica que se ha pulsado el botn Sustituir.
Indica que se ha pulsado el botn Sustituir
todo.
Mostrar un botn de ayuda.

Tabla 9.6. Opciones para TFindDialog y TReplaceDialog


El texto a buscar ser facilitado en la propiedad FindText, mientras
que el texto a colocar en su lugar, en el caso del componente
TReplaceDialog, lo encontraremos en la propiedad ReplaceText.
A diferencia de otros cuadros de dilogo, estos dos no son cerrados
automticamente cuando el usuario ha introducido la informacin
solicitada, sino que permanecen abiertos mientras est en curso la
operacin de bsqueda o bsqueda y sustitucin. Cada vez que se pulsa
el botn Buscar siguiente el componente genera un evento OnFind, que
nosotros deberemos aprovechar para leer el contenido de la propiedad
FindText y realizar la bsqueda en el texto.
De forma anloga, cuando se pulsa el botn Reemplazar se genera un
evento OnReplace, momento en el cual tomaremos el contenido de la
propiedad ReplaceText y lo dispondremos en el texto en lugar de la
cadena buscada. La ventana ser cerrada cuando se pulse el botn
Cerrar o Cancelar. En la figura 9.7 puede ver el aspecto del cuadro de
dilogo de bsqueda y sustitucin.

Figura 9.7. Aspecto del cuadro de dilogo TReplaceDialog


9.4. En la prctica
Con el fin de ver en la prctica cmo podemos utilizar mltiples
formularios en un proyecto, as como algunos de los cuadros de dilogo
de uso comn que hemos conocido, vamos a disear un programa que nos
permita editar archivos de texto, con la posibilidad de tener abiertos
varios archivos de forma simultnea en un entorno MDI.
El texto de cada ventana estar contenido en un control TMemo, por lo
que no es posible el uso de atributos en el texto. Sin embargo, cada
ventana puede tener un tipo de letra y color diferentes al resto.
9.4.1. Diseo del formulario principal
Comenzaremos diseando lo que ser el formulario principal del
proyecto, que actuar como ventana marco de la interfaz MDI. Este
formulario ser el que existe inicialmente en el proyecto, al que
vamos a asignar el ttulo 'Multi Editor'. Deber dar el valor
fsMDIForm a la propiedad FormStyle, a fin de que el formulario acte
como ventana padre de las dems.
El siguiente paso consistir en el diseo de un men de opciones,
desde el cual ser posible recuperar un archive, guardarlo, crear
nuevos archivos, modificar el tipo de letra y el color de fondo de la
ventana y gestionar las mltiples ventanas hija que puedan existir.
Inserte en el formulario un componente TMainMenu, haga"doble clic
sobre l y disee el men que se muestra en la figura 9.8. Observe que
a las opciones del men Archivo, que sern las que se utilicen con una
mayor frecuencia, se les ha asignado una tecla de acceso rpido.

Figura 9.8. Opciones del men principal del programa

Para permitir las diversas operaciones que se deducen de las opciones


del men, tendremos que insertar en el formulario un componente
TSaveDialog, un TOpenDialog, un TfontDialog y un TColorDialog. El
formulario quedar finalmente, en la fase de diseo, tal y como se
muestra en la figura 9.9. A diferencia de otros ejemplos anteriores,
en ste la ventana s que podr ser redimensionada y contar con los
botones de maximizar y minimizar.

Figura 9.9. Aspecto del formulario principal en la fase de diseo


Asigne a la propiedad Title del componente TSaveDialog la cadena
'Guardar archivo de texto', y a la misma propiedad del componente
TOpenDialog la cadena 'Recuperar archivo de texto'.
Asigne a la propiedad Fllter de ambos componentes la cadena 'Archivos
de texto | *.txt'. Active en el componente TSaveDialog las opciones
ofOverwritePrompt
y
ofPathMustExist.
Active
en
el
componente
TopenDialog la opcin ofFileMustExist.
9.4.2. Diseo del formulario hijo
El siguiente paso que daremos ser aadir al proyecto un nuevo
formulario, para lo cual podemos pulsar el botn New Form que hay en
el rea de acciones rpidas. Tambin podemos seleccionar esta opcin
del men File. Este formulario ser el que acte como hijo y, en
ejecucin, podrn existir mltiples copias de el abiertas. Por ello
esta ventana no deber ser creada automticamente, al iniciarse el
programa. Acceda a la ventana de opciones de proyecto y desplace el
segundo formulario de la lista de ventanas autocreadas a la lista de
ventanas disponibles.

Puesto que este formulario va a ser una ventana hija MDI, deberemos
dar el valor fsMDIChild a la propiedad FormStyle, Por lo dems, no
tendremos que alterar ninguna propiedad ms del formulario.
Para visualizar y permitir la edicin del texto insertaremos en el
formulario un control TMemo, que ocupar todo el espacio disponible en
la ventana, por lo que daremos el valor alClient a la propiedad Align.
Este control contar con una barra de desplazamiento vertical, siendo
preciso, por tanto, modificar la propiedad ScrollBars seleccionando el
valor ssVertical. Tambin modificaremos la propiedad WantTabs,
asignndole el valor True.
9.4.3. El cdigo del formulario principal
Procedamos ahora con la escritura del cdigo necesario para hacer que
nuestro programa funcione segn el diseo que estamos esbozando. Lo
primero que tendremos que hacer es utilizar la opcin Use Unit del
men File, para aadir al mdulo de cdigo del primer formulario una
referencia a la segunda, lo que nos permitir acceder a la definicin
de TForm2.
El ttulo de cada una de las ventanas hija ser algo que
estableceremos durante la ejecucin. En caso de que la ventana se cree
abrindose un archivo existente, el ttulo ser el nombre del archivo.
Si, por el contrario, la ventana se ha creado vaca, asignaremos como
ttulo la palabra Nuevo, seguida de un nmero que se ir incrementando
secuencialmente. Este contador lo declararemos al nivel de mdulo,
delante de cualquier mtodo.
Var
Contador: Integer;
Creacin de un nuevo archivo
La primera opcin que encontramos en el men Archivo es la opcin
Nuevo, cuya finalidad es crear una ventana hija vaca, permitindonos
as la creacin de un nuevo archivo de texto. Seleccione esta opcin
en el formulario, durante el diseo, para abrir el Editor de cdigo
por el mtodo correspondiente, en el que escribiremos el cdigo que se
muestra a continuacin.
{ Al pulsar la opcin Muevo }
procedure TForm1.Nuevo1Click(Sender: TObject);
begin
{ creamos un nuevo formulario bijo }
With TForm2.Create(Self) Do
Begin
{ Incrementamos el contador }
Inc(Contador);
{ Establecemos el titulo }
Caption := 'Nuevo ' + IntToStr(Contador);

Show; { y la mostramos }
End;
End;
Bsicamente creamos el formulario, con una llamada al consructor
Create(), asignndole a continuacin un ttulo y mostrndolo, con una
llamada al mtodo Show(). Observe que los formularios hijos MDI se
visualizan como ventanas no modales, ya que de lo contrario no sera
posible cambiar de un documento a otro en ejecucin.
Guardar un archivo
La opcin Guardar del men Archivo no debe estar accesible en caso de
que no exista actualmente una ventana hija abierta, ya que de lo
contrario se podra llamar al mtodo correspondiente cuando en
realidad la operacin no puede llevarse a cabo. Con el fin de que esta
opcin aparezca activada o desactivada segn proceda/ vamos a hacer
doble clic en el men Archivo, desde el Editor de mens, para abrir el
mtodo correspondiente al evento OnClick de este men, que se produce
cuando accedemos a l para desplegarlo. En este mtodo insertaremos
una sentencia, como puede ver a continuacin, en la que asignaremos a
la propiedad Enabled de la opcin el valor True o False, dependiendo
de que exista o no un formulario hijo activo en ese momento.
{ Al desplegar el men Archivo }
procedure TForm1.Archivo1Click(Sender: TObject);
begin
{ Desactivamos la opcin Guardar en caso de que no existe una
ventana hija activa }
Guardar1.Enabled := ActiveMDIChild <> Nil;
end;
Si la opdn Guardar est activa y la seleccionamos, lo primero que
tendremos que hacer ser solicitar un nombre de archivo, para lo cual
utilizaremos el componente TSaveDialog. A continuacin obtendremos una
referencia a la ventana hija que est activa en ese momento, mediante
la propiedad ActiveMDIChild, realizando la necesaria conversin al
tipo TForm2. Esto nos permitir acceder al control TMemo que contiene
el texto y realizar una llamada al mtodoSaveToFile().
A continuacin asignaremos a la propiedad Caption del formulario el
nombre del archivo seleccionado y, por ltimo, daremos el valor False
a la propiedad Modified del control TMemo, para indicar que no se ha
modificado desde la ltima grabacin. El mtodo completo es el que se
muestra a continuacin.
{ Al pulsar la opcin Guardar }
procedure TForm1.Guardar1Click(Sender: TObject);
begin
{ Si se selecciona un nombre de archivo }
If SaveDialog1.Execute Then

{ Accedemos al formulario hijo activo }


Try With (ActiveMDIChild As TForm2) Do
Begin
{e intentamos guardar su contenido }
Memo1.Lines.SaveToFile(SaveDialog1.FileName);
{ Ponemos como ttulo el nombre de archivo }
Caption := SaveDialog1.FileName;
{ Desactivamos el indicador de modificado }
Memo1.Modified := False;
End;
Except { Si se produce un fallo lo indicamos }
ShowMessage('Se produce un error al guardar');
End;
end;
Observe que el bloque en el que se intenta guardar el archivo ha sido
protegido adecuadamente a fin de evitar que un fallo, como puede ser
que el disco est lleno, provoque un mal funcionamiento del programa.
Recuperar un archivo
La opcin Recuperar del men Archivo es la complementaria a la
anterior. Con ella podremos abrir una ventana con el contenido de un
archivo que nosotros indiquemos. Abra el mtodo correspondiente al
evento OnClick de esta opcin y teclee el cdigo siguiente.
{ Al pulsar la opcin Recuperar }
procedure TForm1.Recuperar1Click(Sender: TObject);
begin
{ Si se selecciona un archivo }
If OpenDialog1.Execute Then
{ Creamos una nuevo formulario hijo }
Try with TForm2.Create(Self) Do
Begin
{ y cargamos en ella el archivo indicado }
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
{ Ponemos como ttulo el nombre del archivo }
Caption := OpenDialog1.FileName;
{ Desactivamos el indicador de modificado }
Memo1.Modified := False;
{ y mostramos el formulario }
Show;
End;
Except { Si se produce un error lo indicamos }
ShowMessage('Se produce un error al cargar');
End;
end;
Tras solicitar un nombre de archivo a abrir, creamos una nueva ventana
hija y accedemos al contro TMemo para poder recuperar el contenido de
ese archivo. A continuacin asignamos el ttulo de la ventana, damos

el valor False a la propiedad Modified del control TMemo y mostramos


la nueva ventana hija. Como en el caso anterior, el proceso de
recuperacin del archivo ha sido protegido ante una posible excepcin.
Salida del programa
Hasta ahora nunca habamos dispuesto en un programa una opcin o botn
que nos permitiese salir, ya que para ello es posible pulsar el botn
que automticamente muestra el formulario en el extremo superior
derecho. En este caso, sin embargo, hemos incluido una opcin Salir en
el men Archivo, cuya finalidad ser cerrar el formulario principal y
con el todos los formularios hijos. Para ello bastar con realizar una
simple llamada al mtodo Close() del formulario, tal y como puede ver
en el mtodo siguiente.
{ Al pulsar la opcin Salir }
procedure TForm1.Salir1Click(Sender: TObject);
begin
Close; { cerramos la ventana }
end;
Cambio del tipo de letra
La primera opcin del men Estilo es Letra, una opcin que nos
permitir seleccionar cualquier tipo, tamao y estilo de letra para
mostrar el texto de la ventana que en ese momento tengamos activa.
Para ello lo primero que haremos ser obtener los valores actuales de
la propiedad Font del control TMemo, asignndolos a la propiedad Font
del componente TFontDialog. Seguidamente mostraremos el cuadro de
dilogo y, en caso de que se pulse el botn Aceptar, realizaremos la
asignacin contraria, tal y como puede ver seguidamente.
{ Al pulsar la opcin Letra }
procedure TForm1.Letra1Click(Sender: TObject);
begin
{Hacemos referencia al formulario hijo activo }
With ActiveMDIChild As TForm2 Do
Begin
{tomando el tipo de letra actual}
FontDialog1.Font := Memo1.Font;
{ y permitiendo modificarlo }
If FontDialog1.Execute Then
Memo1.Font := FontDialog1.Font;
End;
end;
Cambio del color de fondo
Para permitir cambiar el color de fondo de la ventana hija que
tengamos activa, utilizaremos un mtodo muy similar al anterior, si
exceptuamos que en este caso usaremos un componente TColorDialog y que

el valor lo obtendremos de la propiedad Color y no de la propiedad


Font. El cdigo de este mtodo sera el que se muestra a continuacin.
{ Al pulsar la opcin Color }
procedure TForm1.Color1ClicktSender: TObject);
begin
{ Accedemos al formulario hijo activo }
With ActiveMDIChild As TForm2 Do
Begin
{ tomando el color de fondo }
ColorDialog1.Color := Memo1.Color;
{ y permitiendo seleccionar otro }
If ColorDialog1.Execute Then
Memo1.Color := ColorDialog1.Color;
End;
end;
Gestin de las ventanas hija
Por ltimo encontramos en el men una opcin Ventana, conteniendo tres
opciones que nos permiten disponer las ventanas hija en forma de
cascada, en forma de mosaico o bien organizar los iconos de aquellas
ventanas
que
estn
minimizadas.
El
cdigo
de
los
mtodos
correspondientes a los eventos OnClick de estas tres opciones es tan
simple
como
una
llamada
a
los
mtodos
Cascade(),
Tile()
y
Arrangelcons(), como puede ver.
{ Al pulsar la opcin Cascada }
procedure TForm1.Cascada1Click(Sender: TObject);
begin
Cascade; { Llamamos al mtodo Cascade }
end;
{ Al pulsar la opcin Mosaico }
procedure Tform1.Mosaico1Click(Sender: TObject);
begin
Tile; { Llamamos al mtodo Tile }
end;
{ Al pulsar la opcin Organizar iconos }
procedure TForm1.OrganizarIconos1Click(Sender: TObject);
begin
Arrangelcons; { Llamamos al mtodo ArrangeZcons }
end;
9.4.4. El cdigo del formulario hijo
Tambin desde el mdulo de cdigo del formulario hija necesitaremos
acceder al formulario principal, por lo que el primer paso que
daremos, una vez que hayamos abierto en el Editor de cdigo la pgina

apropiada, ser seleccionar la opcin Use Unit


seleccionando el nico mdulo existente en la lista.

del

men

File,

Como hemos podido ver en el punto anterior, los mtodos que se


encargan de guardar y recuperar el texto de una ventana utilizan la
propiedad Modified del control TMemo, asignndole el valor False con
el fin de indicar que no se han realizado modificaciones tras haber
realizado la recuperacin o salvaguarda. Esta propiedad tomar
automticamente el valor True en el momento en que el usuario del
programa modifique el texto.
Por tanto, en el momento en que se desee cerrar una ventana hija el
texto puede estar modificado, lo que podemos comprobar fcilmente con
la propiedad comentada. En caso de que esto sea as deberamos
permitir al usuario guardar el texto, salir sin guardar o bien
cancelar la operacin de cierre de la ventana. El mejor punto para
poder hacer esto es el mtodo correspondiente al evento OnloseQuery,
cuyo cdigo se muestra seguidamente.
{ Antes de proceder con el cierre del formulario }
procedure TForm2.FormCloseQuery(Sender: TObject; var
CanClose: Boolean);
begin
{ Comprobamos si el texto se ha modifcado }
If Memo1.Modified Then
{ en caso afirmativo preguntamos si se desea guardar }
Case Application.MessageBox('Desea guardar el texto
modificado?',Pchar('Cerrar ' + Caption),
MB_YESNOCANCEL) Of
{ en caso afirmativo }
ID_YES: Form1.Guardar1Click(Self); { Guardar el texto }
{ Si se pulsa cancelar }
ID_CANCEL: CanClose := False; { no cerramos la ventana }
End;
end;
Como puede ver, en caso de que el texto se haya modificado usamos el
mtodo MessageBox() para preguntar al usuario si desea guardarlo o no,
permitindole tambin cancelar. Si la respuesta del usuario es
afirmativa realizamos una llamada al mtodo GuardarlClick(), que se
encargar de guardar el texto. Si se ha pulsado el botn de
cancelacin, asignamos el valor False a la propiedad CanClose,
indicando as que no se debe continuar con el proceso de cierre. La
ltima respuesta posible es que no se quiera guardar el texto, caso
ste en el que no hacemos nada, por lo que el formulario se cierra y
el texto se pierde.
Cuando se pulsa el botn de cierre de una ventana hija MDI lo
ocurre es que sta se minimiza, pero no se destruye. Si deseamos
al pulsar dicho botn la ventana se cierre y se libere la memoria
sta ocupa, tendremos que utilizar el evento OnClose, asignando

que
que
que
al

parmetro Action el valor caFree, indicando que deseamos liberar el


formulario.
{ Al cerrar el formulario }
procedure TForm2.Form1Close(Sender: TObject; var Action:
TCloseAction);
begin
Action := caFree; { liberar la memoria asignada }
end;
9.4.5. Probando el programa
Ya tenemos finalizado nuestro programa editor, tan slo hemos de
pulsar la tecla <F9> para ejecutarlo y verlo en funcionamiento.
Inicialmente la ventana marco aparecer vaca. Si pulsamos <Control+N>
se crear una ventana vaca, en la que podremos introducir el texto
que deseemos. Pulsando <Control+R> se abrir un cuadro de dilogo en
el que podremos seleccionar un archivo cualquiera, recuperando el
texto que ste contiene. Pruebe el resto de las opciones, guardando un
texto que haya escrito partiendo de cero, modificando el tipo de
letra, el color de fondo y jugando con las ventanas, disponindolas en
cascada, mosaico, minimizndolas, etc.

Figura 9.10. Aspecto del programa en funcionamiento

10. Trabajo con base de datos


10.1. Introduccin
Uno de los aspectos ms interesantes de Delphi es su facilidad para
tratar bases de datos en diversos formatos, sin necesidad de gue el
programador tenga conocimiento alguno sobre la estructura de cada
tipo. Para trabajar con una base de datos bsicamente tendremos que

completar dos procesos: la creacin de la base de datos, apartado en


el cual se definen sus campos, tipos, ndices, etc., y su posterior
uso en nuestra aplicacin.
Para crear o definir bases de datos podemos usar el Database Desktop,
una herramienta que acompaa a Delphi y a la que podemos acceder desde
el men Tools, bien una herramienta especfica para el tipo de base
de datos a crear.
A lo largo de este captulo conoceremos los fundamentos del Database
Desktop y crearemos una base de datos de ejemplo. Disponiendo ya de
una base de datos, podemos acceder a ella desde nuestras aplicaciones
mediante los componentes de bases de datos. Estos componentes, que
conoceremos en el captulo siguiente, nos permitirn especificar los
datos a los que deseamos acceder, editarlos, etc.
Comencemos a trabajar con el Database Desktop en los puntos
siguientes, ejecutndolo desde el propio entorno de Delphi. Tras
un momento, en el que se mostrar una ventana con datos acerca del
programa, nos encontraremos con el entorno de trabajo de esta
herramienta, cuyo aspecto se muestra en la figura 10.1.
10.2. Gestin de alias
Las bases de datos son archivos, o grupos de archivos, que pueden
estar localizados en un directorio de nuestro disco, sin son bases de
datos locales, o en un servidor, en caso de que estemos trabajando en
un entorno cliente/servidor. Con el fin de no tener que recordar el
camino y nombre de los archivos en que se encuentra una determinada
base de datos cada vez que es necesario usarla, lo habitual es definir
un alias.
Un alias o mote es un identificador asociado a una base de datos, de
tal forma que cada vez que se quiere acceder a ella, en lugar del
camino en el que se encuentra y el nombre de archivo, usamos dicho
alias. Mediante la opcin Alias Managerdel men Tools accederemos a la
ventana de gestin de alias. En la figura 10.2 puede ver los distintos
apartados de esta ventana.

Figura 10.1. Aspecto del entorno del Database Desktop

Fig 10.2 Ventana de gestion de alias del Database Desktop

10.2.1. Creacin de un nuevo alias


El primer paso que daremos para crear un nuevo alias ser pulsar el
botn New, lo que har que la mayora de los apartados del formulario
queden en blanco. A continuacin facilitaremos un identificador para
el alias, es decir, el nombre con el que vamos a conocer a la base de
datos. Seguidamente seleccionaremos el tipo de controlador, en el
apartado Driver type, que puede ser cualquiera de los controladores
que tengamos instalado en nuestro sistema.
Delphi tiene un motor de bases de datos capaz de trabajar con
controladores de diferentes tipos. Al motor de bases de datos de
Delphi se le conoce habitualmente como BDE(Borland Database Engine) y
los controladores propios son los llamados estndar o controladores
IDAPI. Estos son los controladores ms eficientes, ya que estn
optimizados para trabajar con Delphi. Mediante ellos podremos trabajar
con bases de datos de dBase, Paradox, Access y texto.
Los formatos de bases de datos, sin embargo, no estn limitados a los
mencionados, ya que el BDE est preparado para trabajar con otros
controladores diferentes. Mediante los controladores ODBC, por
ejemplo, podemos acceder a bases de datos locales en otros formatos,
mientras que con los controladores incluidos en el paquete SQL Links
es posible acceder a bases de datos remotas. Tambin es posible
prescindir del BDE, utilizando los componentes de acceso directo a
InterBase o incluso los ADO (Active Data Objects), aunque son dos
opciones que no veremos en esta gua.
Dependiendo del controlador que hayamos seleccionado, en la ventana de
la figura 10.2 se solicitarn unos datos u otros. Elija de la lista
desplegable el tipo STANDARD, con el fin de crear un alias para una
base de datos con tablas Paradox. Al seleccionar este controlador tan
slo ser necesario facilitar un dato ms, el camino o directorio en
el que estn almacenadas o se almacenarn las tablas de esta base de
datos.
Dados los pasos anteriores ya puede pulsar el botn OK, momento en el
que se le preguntar si desea guardar los nuevos alias en el archivo
de configuracin del BDE, a lo que responderemos afirmativamente.
10.2.2 Modificacin y eliminacin de alias
Desde la ventana de gestin de alias tambin podemos modificar un
alias existente, as como eliminar alias que ya no nos interesen. En
cualquiera de los dos casos, lo primero que tendremos que hacer ser
seleccionar el alias a modificar o borrar, para lo cual desplegaremos
la lista adjunta al apartado Database Alias, eligiendo el alias
deseado.

Si lo que queremos es eliminar el alias cuya informacin se est


mostrando en la ventana, bastar con pulsar el botn Remove. El alias
y todos sus datos desaparecern del registro del BDE. En caso de que
lo que necesitemos sea realizar alguna modificacin, tan slo tenemos
que desplazarnos hasta el apartado correspondiente, introducir el
nuevo valor y terminar pulsando OK, a fn de que los cambios se
guarden en el citado archivo de configuracin.
10.3. Creacin de una tabla
Como se comentaba al principio, una de las finalidades principales
para las cuales utilizaremos el Database Desktop, aunque como veremos
despus hay ms posibilidades, ser para crear las tablas de las bases
de datos necesarias para nuestros programas. Para ello tendremos que
abrir el men File y seleccionar la opcin New, que nos dar paso a
tres nuevas opciones de las cuales seleccionaremos Table.
Lo primero que tendremos que hacer, al inidar la creacin de una nueva
tabla, ser indicar su tipo. Para ello el Database Desktop
visualizar una ventana como la de la figura 10.3, con una lista en la
que podremos seleccionar cualquiera de los tipos disponibles. En
nuestro caso vamos a elegir el formato de Paradox 7.

Figura 10.3. Seleccin del tipo de tabla a crear


Dependiendo del tipo de la tabla que creemos, sta soportar unos
tipos de campos u otros, la existencia de chequeos de validacin,
ndices de unos tipos u otros, etc.

10.3.1. Definicin de los campos de la tabla


Una vez que hemos indicado el tipo de tabla a crear, el Database
Desktop mostrar una ventana en la que podremos ir especificando los
distintos campos o columnas que forman cada registro de la tabla. Por
regla general deberemos indicar para cada campo un nombre, tipo y
longitud, pudiendo adicionalmente especificar si formar o no parte de
un ndice, si es un campo requerido, etc. En la figura 10.4 puede ver

el aspecto de la ventana mostrada al crear una nueva tabla de tipo


Paradox 7.

Figura 10.4. Definicin de los campos de una tabla


Tras introducir el nombre de un campo, que en este caso podr contar
con un mximo de veinticinco caracteres, pulsaremos la tecla <Intro> o
la teda <Tab> para acceder a la columna Type. En esta columna lo ms
cmodo es pulsar la barra espaciadora o el botn derecho del ratn,
desplegando as una lista con todos los tipos posibles. Como podr
ver, podemos definir campos para contener cadenas de caracteres,
nmeros de diferentes precisiones, fechas, objetos OLE e incluso
grficos.
En caso de que el tipo de campo lo requiera, deberemos facilitar una
longitud mxima. Si seleccionamos, por ejemplo, el tipo Alpha en una
tabla Paradox, que nos permite introducir cadenas de caracteres,
tendremos que indicar cuntos caracteres como mximo ser posible
almacenar en el campo.
10.3.2. Propiedades de la tabla
La zona derecha de la ventana de definicin de tabla, ilustrada en la
figura 10.4, contiene las propiedades de la tabla.

Existen varios campos de propiedades, como son los chequeos de


validacin
de
campos,
los
ndices
secundarios,
etc.
Podemos
seleccionar el grupo de propiedades que deseamos ver desplegando la
lista que hay en la parte superior, eligiendo cualquiera de los
elementos existentes. Inicialmente el grupo mostrado es el de chequeos
de validacin, propiedades que se aplican a cada campo individual de
la tabla.
Los chequeos de validacin nos permiten, como su propio nombre indica,
validar la entrada de datos en los campos. Para ello disponemos de
cinco propiedades diferentes, mediante las cuales podemos indicar si
se ha de introducir necesariamente un valor en el campo, cul ser el
valor mnimo y el valor mximo permitido, qu valor se tomar por
defecto si el usuario no introduce uno nuevo, y cul ser la plantilla
de entrada de datos.
El apartado Picture, en el que podemos introducir una plantilla o
mscara de entrada de los datos en el campo que tenemos seleccionado
en ese momento, tiene justo debajo un botn mediante el cual podemos
acceder a la ventana mostrada en la figura 10.5. En esta ventana se
facilita la construccin de mscaras de entrada de datos y su
comprobacin de validez y funcionamiento. En la figura 10.5 puede ver
cmo se ha introducido una plantilla que facilite la introduccin de
un nmero de telfono, comprobando su funcionamiento en el apartado
Sample Value. Al pulsar el botn OK la cadena se pasa automticamente
a la propiedad Picture.

Fig 10.5 Definicin de una mscara de entrada para un campo

Tenga en cuenta que la mayora de las propiedades comentadas son


aplicables slo a tablas de tipo Paradox. Una tabla de dBase, por
ejemplo, no cuenta con chequeos de validacin.
10.3.3. ndices
En una tabla de tipo Paradox pueden existir dos tipos de ndices: el
ndice principal o clave y uno o ms ndices secundarios. El ndice
principal est siempre formado por el primer o los primeros campos de
la tabla. Podemos indicar qu campos formarn parte de este ndice
pulsando cualquier carcter en la columna Key, lo que har aparecer un
asterisco indicativo de que ese campo forma parte del ndice.
El ndice principal establece el orden inicial en el que estarn
registros de la tabla, ya que ser el ndice que se utilice
defecto. Los valores que forman parte de un ndice principal deben
nicos, una repeticin de un valor clave causara una violacin de
clave, en este caso una duplicacin.

los
por
ser
esa

Tambin podemos contar en una tabla de este tipo con ndices


secundarios, que pueden ser activados en el momento en que a nosotros
nos interese. Para definir un ndice secundario lo primero que
tendremos que hacer ser seleccionar de la lista de propiedades el
elemento Secondary Indexes, que mostrar una lista en la parte derecha
de la ventana con los nombres de los ndices secundarios existentes en
ese momento. Inicialmente esta lista estar dada, como es lgico, ya
que la tabla es nueva.
La definicin de un nuevo ndice secundario la iniciaremos pulsando el
botn Define, que se encuentra justo debajo de la lista desplegable de
propiedades. Al hacerlo aparecer una ventana como la que puede ver en
la figura 10.6. En la lista de la izquierda estn los campos
disponibles en la tabla, mientras que en la de la derecha se enumeran
los que forman parte del ndice que deseamos definir. Tendremos, por
lo tanto, que mover de una lista a otra el campo o campos que formarn
el ndice secundario. Por ltimo pulsaremos el botn OK, lo que har
aparecer una ventana en la que tendremos que facilitar el nombre que
deseamos asignar al ndice. Este nombre se mostrar en la lista de
ndices secundarios de la tabla.

Figura 10.6. Definicin de un ndice secundario


10.3.4. Guardar la tabla
Cuando hayamos terminado de definir todos los campos y propiedades de
la tabla, tendremos que pulsar el botn Save As para guardarla en
disco, dejndola as disponible para cualquier uso posterior. Al
pulsar dicho botn aparecer la ventana que se muestra en la figura
10.7.

Figura 10.7 Guardando la nueva tabla

En ella lo primero que haremos ser desplegar la lista que hay en la


parte inferior derecha, seleccionando el alias correspondiente a la
base de datos en la que deseamos almacenar la tabla. Este alias
determinar el disco y directorio en el que ser efectivamente grabada
la informacin. Hecho esto tan slo debemos facilitar el nombre de la
tabla, que en este caso ser el nombre de un archivo con extensin DB,
pulsando finalmente el botn OK.
10.4. Modificar la estructura de una tabla
Desde el Database Desktop no slo podemos crear nuevas tablas, tambin
podemos modificar la estructura de tablas ya existentes, adems de
editar su contenido como veremos en el prximo punto.
La modificacin de una tabla que ya existe, y que
contiene datos, es siempre un tema delicado. En caso de
de aadir nuevos campos no surge ningn problema. Si lo
hacer es modificar el tipo de un campo, en caso de que el
y el nuevo no sean compatibles no ser posible realizar
conversin.

posiblemente
que se trate
que deseamos
tipo antiguo
la necesaria

La eliminacin de un campo siempre resultar en una prdida de datos,


como es lgico. En casos como ste el Database Desktop nos avisar
antes de realizar la operacin, tal y como puede ver en la figura
10.8.

Figura 10.8. Aviso de prdida de datos durante una reestructuracin


Para modificar la estructura de una tabla utilizaremos la opcin
Restructure del submen Utilities, que se encuentra en el men Tools.

Tras seleccionar la tabla que se desea reestructurar nos encontraremos


en la misma ventana que se utilizaba para la creacin, pudiendo aadir
nuevos campos, modificar o eliminar los existentes.
10.5. Editar el contenido de una tabla
Aunque, por regla general, sta ser una tarea a realizar desde la
aplicacin que nosotros desarrollemos, el Database Desktop tambin nos
permite editar el contenido de una tabla, como si de un pequeo gestor
de bases de datos se tratara. Esta opcin es muy til, ya que nos
permite, por ejemplo, comprobar si nuestro programa introduce los
datos adecuadamente en la base de datos.
Con el fin de abrir una tabla puede pulsar el primer botn que aparece
en la barra que hay debajo del men, o bien utilizar la opcin Open
del men File, eligiendo la opcin Table. En cualquiera de los dos
casos se abrir la ventana de apertura de tabla, en la que podremos
seleccionar un alias, facilitando as el camino en el que se almacena
la base de datos, y posteriormente elegir una de las tablas.
Dado el paso anterior veremos aparecer en pantalla una ventana en
forma de tabla, conteniendo tantas columnas como campos existan y
tantas filas como registros contenga la tabla. En esta ventana
podremos aadir datos a la tabla, as como modificar los ya
existentes. En la figura 10.9 puede ver el aspecto de la ventana de
edicin.

Figura 10.9. Ventana de edicin de una tabla

La modificacin del contenido de una tabla es una tarea muy simple con
el Database Desktop. Inicialmente nos encontramos en el modo de
visualizacin, por lo que podemos movemos por la tabla pero no
realizar tareas de edicin, tales como modificar un dato, aadir un
nuevo registro o borrar un registro existente. Para pasar al modo de
edicin bastar con pulsar la tecla <F9> o el botn que est en el
extremo derecho de la parte superior de la ventana.
10.5.1. Edicin de datos
Encontrndonos en el modo de edicin, lo cual est indicado por el
botn citado anteriormente y un pequeo letrero en la barra de estado,
en la parte inferior de la ventana, podemos realizar diversas tareas
de edicin con la tabla que tenemos abierta.
Para aadir un nuevo registro deberemos desplazamos hasta el final de
la tabla, pulsando la <Flecha abajo> cuando nos encontremos en el
ltimo registro. Esto provocar que se aada un registro en blanco, en
el que podremos introducir los valores que deseemos de forma
inmediata.
Si deseamos insertar un registro en una posicin determida, en lugar
de hacerlo al final de la tabla, deberemos situarnos en el punto que
nos interese, pulsando a continuacin la tecla <Insert>, que abrir un
espacio vaco desplazando todos los registros inferiores. Hecha esta
operacin, podemos introducir los valores para el registro de igual
forma que hacamos en el caso anterior. Tenga en cuenta que si la
tabla tiene un ndice activo, el orden de los registros vendr
determinado por el valor de los campos que forman parte de ese ndice,
por lo que dar igual el punto en donde lo insertemos o aadamos.
Tambin podemos, encontrndonos en el modo de edicin eliminar
registros de la tabla. Para ello lo primero que deberemos hacer es
situamos sobre el registro a borrar, pulsando a continuacin la
combinacin de teclas <Ctrol+Supr>. A diferencia de otras operaciones,
como la modificacin de un campo, el borrado de un registro no puede
deshacerse posteriormente con el comando Undo del men Edit.
A la hora de modificar un campo de un registro ya existente, podemos
optar por introducir un nuevo valor, eliminando el anterior, o bien
por modificar el dato que se muestra. Por defecto la ventana de
edicin se encuentra en un modo que permite que las teclas de cursor
sean usadas para desplazarse al campo anterior o siguiente. En este
modo, la introduccin de un valor en un campo elimina el contenido
anterior. Podemos pasar al modo de edicin de campo pulsando la tecla
<F2>, o el penltimo botn de la barra, de tal forma que las teclas de
cursor permitan el desplazamiento por los caracteres del campo,
facilitando as la modificacin de un valor.

10.5.2. Columnas no accesibles


Ciertos tipos de campo no pueden ser editados desde el Database
Desktop y tan slo podremos introducir y modificar sus valores desde
un gestor de bases de datos, como puede ser Paradox, o bien desde una
aplicacin que nosotros hayamos desarrollado a tal efecto.
Los campos de tipo MEMO, que almacenan textos extensos; de tipo OLE,
que almacenan objetos, o de tipo GRAPHIC, que contienen grficos, son
algunos de los que no podemos editar en el Database Desktop. En las
posiciones de estos campos simplemente se mostrar una cadena
indicando el tipo al que pertenecen.

10.6. Consultas
La seleccin de una tabla con la nica finalidad de ver su contenido
tiene como consecuencia la visualizacin de todos sus campos y todos
sus registros, es decir, se muestra toda la informacin que contiene
la tabla. A veces, sin embargo, podemos necesitar recuperar slo
algunos de los datos con el fin, por ejemplo, de generar un cierto
listado o informe. En estos casos lo que se hace es disear y ejecutar
una consulta.
Database Desktop soporta dos tipos de consultas diferentes, a las que
se denomina QBE (Query By Example) y SQL (Structured Query Language).
La primera de ellas, ms simple e intuitiva, se basa en la composicin
de la consulta a partir de unos datos facilitados como ejemplo. La
segunda, mucho ms conocida, se basa en el uso del lenguaje de
consulta de bases de datos SQL, un estndar prcticamente general.
10.6.1. Construccin de una consulta QBE
Para crear una consulta QBE tendremos que seleccionar la opcin New
del men File, eligiendo la opcin QBE Query del submen adjunto. Esto
nos llevar a una ventana en la que tendremos que seleccionar la tabla
sobre la que se va a realizar la consulta, para lo cual podemos partir
por especificar el alias, pulsando seguidamente sobre la tabla
deseada. Hecho esto aparecer una ventana, como la mostrada en la
figura 10.10, en la cual podremos componer la consulta.

Figura 10.10. Creacin de una consulta QBE


Como podr ver, a la izquierda de cada uno de los campos existe una
casilla, similar a un control TCheckBox, que nos servir para indicar
si deseamos que el campo adjunto aparezca o no en la tabla resultante
de la consulta. En caso de que deseemos marcar todos los campos, lo
podemos hacer de forma inmediata pulsando en la casilla que hay en la
izquierda de la ventana, justo debajo del nombre de la tabla.
A continuacin tendremos que facilitar unos datos de ejemplo,
que
pueden ir acompaados de operadores relacionales, mediante los cuales
seleccionaremos los registros a obtener. En la figura 10.10 se buscan
todos aquellos alumnos que pertenezcan a la Provincia Ciudad de la
Habana que tengan menos de 21 aos de edad.
Una vez que tenemos compuesta la consulta, bastar con pulsar la tecla
<F8> para obtener la tabla resultante, que estar compuesta de los
registros que cumplan las condiciones que hemos impuesto, cada uno de
los cuales, contar a su vez slo con los campos que hayamos marcado.
Esta tabla resultado es una tabla temporal, que se almacena en un
directorio privado, pero que podemos guardar en caso de que nos
interese conservarla.
Las consultas QBE pueden ser almacenadas en disco, de tal forma que
posteriormente estn disponibles para volver a ejecutarse en cualquier
momento.
10.6.2. Construccin de una consulta SQL
El proceso de creacin de una consulta utilizando el lenguaje SQL se
inicia de forma similar a una consulta QBE, seleccionando la opcin
New del men File, y eligiendo en este caso la opcin SQL File. La

ejecucin de esta opcin abrir una ventana de texto, en la que


podremos introducir el comando SQL para realizar la consulta. En la
figura 10.11 puede ver la ventana y una sentencia SQL de ejemplo, en
la que se seleccionan de la tabla de alumnos los mismos registros
obtenidos con la consulta QBE del punto anterior.

Figura 10.11. Creacin de una consulta SQL


Para obtener la tabla resultante de la consulta SQL, actuaremos de
igual forma que se ha descrito en el punto anterior, es decir, bastar
con pulsar la tecla <F8>. Las consultas SQL que son archivos de texto,
tambin pueden ser guardadas en disco para su posterior uso.

11. Componentes enlazados a datos

11.1. Introduccin
Habiendo diseado la estructura de la base de datos que necesitamos
para nuestra aplicacin y definido las tablas que la vayan a
conformar, usando el Database Desktop, estaremos ya preparados para
usar dichas tablas en nuestros programas, para lo cual necesitaremos
conocer los componentes enlazados a datos de Delphi.
En la Paleta de componentes de Delphi existe una pgina, llamada Data
Access, que contiene componentes no visuales de acceso a bases de
datos. Estos componentes nos servirn, por ejemplo, para crear un
enlace entre una tabla de la base de datos y nuestro programa, o para
crear y ejecutar una consulta. A la derecha de esa pgina existe otra,
llamada Data Controls, en la que encontraremos los controles enlazados
a datos, una serie de componentes visuales cuya finalidad es mostrar y
permitir la modificacin de los datos que se almacenan en cada campo.

11.2. Edicin de una tabla


Vamos a partir viendo con qu facilidad podemos crear un formulario
para editar el contenido de una tabla, pasando en puntos posteriores a
estudiar con ms detenimiento el funcionamiento de los componentes de
bases de datos ms habituales.
Suponga que desea construir un formulario en el que sea posible
visualizar y editar el contenido de la tabla de libros que se dise
como ejemplo en el captulo anterior, incorporando funciones que le
permitan desplazarse de un registro a otro, modificar, borrar y
aadir.
11.2.1. Establecer un enlace con la tabla
El primer paso que daremos para poder acceder a los datos de una tabla
ser crear un enlace entre ella y nuestro programa, para lo cual
usaremos el componente TTable. Este es un componente no visual que
dispone de la funcionalidad suficiente como para abrir una tabla y
gestionar su contenido. Para ello deberemos facilitarle el nombre de
la base de datos y, obviamente, el nombre de la tabla.
Inserte un componente de este tipo en el formulario, editando a
continuacin las propiedades DatabaseName y TableName. La primera de
ellas contendr el nombre de la base de datos, que puede ser tanto un
alias que hayamos creado para la base como el camino del directorio en
el que se encuentran las tablas de sta. Puesto que en el captulo
anterior se defini un alias para la base en la que se encuentra la
tabla de libros, bastar con asignar a esta propiedad el identificador
de ese alias.

Tambin puede desplegarla lista adjunta a la propiedad Database Name,


que contiene todos los alias definidos en el sistema.
Como puede suponer, la propiedad TableName almacena el nombre de la
tabla a la que se desea acceder. Este dato no tenemos por qu
teclearlo directamente, ya que al haber facilitado al componente
TTable el nombre de la base de datos podremos desplegar la lista
adjunta a la propiedad TableName para poder ver todas las tablas
existentes, seleccionando directamente la que deseemos.
Una vez haya asignado los valores adecuados a las dos propiedades
anteriores, d el valor True a la propiedad Active. Si todo es
correcto no pasar nada, pero el control TTable habr accedido a la
tabla, abrindola y recuperando datos acerca de ella.
11.2.2. El editor de campos de TTable
Una tabla est compuesta de una serie de campos, y mediante el
componente TTable nosotros podemos seleccionar qu campos son los que
deseamos manipular desde nuestro programa. Para ello utilizaremos el
Editor de campos, una ventana a la que podemos acceder haciendo doble
clic sobre el componente.
Inicialmente esta ventana estar vaca, indicando que no ha
seleccionado campo alguno. En este estado la lista de campos a la que
es posible acceder desde nuestro programa se crea dinmicamente, es
decir, durante la ejecucin. En la mayora de los casos, sin embargo,
es ms til y rpido definir en la fase de diseo qu campos son los
que necesitamos, crendolos estticamente.
Pulse la combinacin <Control+A> en el Editor de campos, o bien pulse
el botn derecho del ratn, para hacer aparecer el men emergente, y
seleccione la opcin Add fields. Esto har aparecer otra ventana con
una lista de los campos existentes en la tabla, estando todos ellos
seleccionados en principio. Bastar con que pulsemos el botn OK para
aadir campos al Editor de campos, que mostrar el aspecto que puede
ver en la figura 11.1. Los botones existentes en la parte superior nos
permitirn el desplazamiento entre los registros que haya en la tabla,
como podremos ver en un momento.

Figura 11.1. El Editor de campos con la tabla de alumnos


11.2.3. Insercin de los controles de edicin
El siguiente paso que daremos ser insertar en el formulario los
controles que permitan, en ejecucin, ver y editar el contenido cada
registro de la tabla. Estos controles, cuyo funcionamiento conoceremos
dentro de un momento, sern realmente insertados automticamente por
el propio Delphi.
Teniendo abierta la ventana de la figura 11.1, seleccione los
elementos de la lista, los cuatro campos, marcndolos con el puntero
del ratn mientras mantiene pulsada la tecla <Mays>, como hara en
cualquier otra lista. A continuacin pulse el botn izquierdo del
ratn estando sobre los campos marcados y, sin soltarlo, arrstrelos
hasta situarse en la parte superior izquierda del formulario, momento
en el cual soltar el botn del ratn. Podr ver cmo automticamente
se insertan en el formulario una serie de controles TLabel, TDBEdit y
un componente TDataSource.
Aunque an estamos en fase de diseo, podr comprobar que ya est
viendo datos reales de la tabla. Ahora puede utilizar los botones que
hay en la parte superior del Editor de campos con el fin de
desplazarse de un registro a otro, comprobando en modo de diseo los
datos existentes en la tabla.
11.2.4. Navegacin por los datos
Durante la ejecucin, la ventana del Editor de campos no estar
disponible, por lo cual no ser posible utilizar sus botones para
navegar por los datos de la tabla. Este es un elemento que est
construido para su uso slo en la fase de diseo, para permitir una
funcionalidad similar durante la ejecucin necesitaremos utilizar un
control adicional.

En la pgina Data Controls existe un componente, llamado TDBNavigator,


que cuenta con una serie de botones que facilitan las operaciones de
desplazamiento por los registros de la tabla, adems de contar con
otros adicionales para permitir el borrado o insercin de datos.
Inserte en el formulario un control TDBNavigator dando el valor
alBottom a la propiedad Align, con el fn de mantenerlo alineado en la
parte inferior del formulario. A continuacin edite la propiedad
DataSource, seleccionando de la lista adjunta el nico elemento
disponible. Con esto estamos enlazando el control TDBNavigator con los
datos sobre los que va a trabajar.
El aspecto definitivo del formulario es el que se muestra en la figura
11.2,
con
los
componentes
TTable
y
TDataSource,
el
control
TDBNavigator y los controles TLabel y TDBEdit. No necesita hacer nada
ms, ni siquiera escribir una lnea de cdigo, para poder ejecutar el
programa y trabajar sobre la tabla de alumnos.

Figura 11.2. Formulario para editar la tabla de alumnos

11.3.Tablas y consultas
Acabamos de ver lo fcil que resulta crear en Delphi un programa para
manipular los datos de una tabla, sin necesidad de escribir nada de
cdigo y tan slo con unas pocas operaciones de ratn, ya que
prcticamente tampoco hemos tenido que edificar propiedades. Esta
simplicidad, sin embargo, no est reida con la flexibilidad y la
potencia, y los componentes de bases de datos de Delphi cuentan con
ambas caractersticas.
11.3.1. El componente TTabIe
Desde un programa Delphi podemos acceder a los datos de una sla
tabla, a todos sus datos, o bien a datos parciales de una o ms

tablas. En el primer caso el componente apropiado es TTable, mientras


que en el segundo deberemos usar un componente TQuery.
El componente TTable, al igual que TQuery, es un puente entre los
datos fsicos, que se encuentran en la base de datos, y nuestro
programa. Son estos componentes los que realizan todas las llamadas
necesarias al BDE, recuperando y actualizando informacin.
Los controles enlazados a datos, que trataremos en un punto posterior,
son componentes visuales que cuentan con los elementos necesarios para
poder recuperar la informacin de un campo y actualizarlo. Estos
controles no pueden ser enlazados directamente con un componente
TTable o TQuery, siendo necesario usar
un intermediario que es el
componente TDataSource.
11.3.2. El componente TQuery
Suponga que desea seleccionar slo algunos campos o registros de la
tabla de alumnos o bien que quiere recuperar datos de dos tablas,
estableciendo la relacin necesaria entre ellas. En casos, como stos,
el componente apropiado para acceder a la base de datos no es TTable
sino TQuery.
El funcionamiento de TQuery es muy similar al descrito anteriormente
para TTable. Contamos con una propiedad, DatabaseName, en la que
facilitaremos el alias o camino en el que se encuentra la base de
datos, y con una propiedad. Active, a la que daremos el valor True
para activar el acceso a los datos.
TQuery no dispone de una propiedad TableName y, en su lugar,
encontramos otra llamada SQL. Esta propiedad, que es una lista de
cadenas de texto, nos servir para facilitar la
sentencia SQL de
seleccin de los datos que se desean obtener. Bastar con que haga
doble clic sobre esta propiedad, en el Inspector de objetos, para
abrir la ventana de edicin. Tambin puede facilitar la sentencia SQL
en ejecucin, permitiendo incluso que sea el usuario del programa el
que determine los datos que desea obtener.
Para realizar una prueba inserte un componente TQuery en el formulario
e introduzca la sentencia SQL que se muestra en la figura 11.3. A
continuacin d el valor True a la propiedad Active y asocie el
componente TDataSource que ya hay en el formulario con el TQuery,
modificando el valor de la propiedad DataSet. De forma inmediata podr
ver en el formulario los datos seleccionados y utilizando los botones
del Editor de campos, que podr abrir haciendo doble dic sobre el
componente TQuery, comprobar si se han seleccionado los registros
deseados.

Figura 11.3. Sentencia SQL de seleccin de datos en el TQuery


11.3.3. El componente TDataSource
Entre los componentes que utilizan las funciones del IDAPI para
acceder al BDE y manipular los datos, que son los dos anteriores, y
los controles de bases de datos que nos permiten mostrar y editar esa
informacin, que veremos en el apartado siguiente, existe un
intrprete
intermedio
que
es
el
componente
TDataSource.
Este
componente es una interfaz comn para los controles de bases de datos,
de tal forma que stos pueden acceder a los datos independientemente
de que se hayan recuperado mediante un TTable o un TQuery.
La propiedad DataSet del componente TDataSource har referencia al
componente TTable o TQuery con el que se va a asociar, mientras que la
propiedad DataSource de cada uno de los controles de bases de datos
contendrn el nombre del componente TDataSource, creando as la cadena
necesaria.

11.4. Controles enlazados a datos


Todos los controles de bases de datos cuentan con una propiedad
llamada DataSource que nos servir, como acaba de explicarse, para
asociarlos con el componente TDataSource que nos permitir obtener los
datos. Adems, la mayora de ellos tambin cuentan con una propiedad
DataField, en la cual indicaremos qu campo de la tabla o consulta es
el que se mostrar o editar en el control.
Prcticamente existen tantos controles de bases de datos como
controles estndar y la nica diferencia entre unos y otros es gue los
de bases de datos recuperan y almacenan la informacin en las tablas
correspondientes. Tambin hay controles de bases de datos que no

tienen
correspondencia
con
TDBNavigator o TDBControlGrid.

ningn

control

normal,

como

es

11.4.1.Mostrar y editar datos


Si queremos usar un control de base de datos tan slo para mostrar el
contenido de un Campo, sin facilitar ninguna operacin de edicin,
podemos usar el control TDBText. Este control, que en apariencia es
idntico a un TLabel, cuenta con las citadas propiedades DataSource y
DataField, de tal forma que es posible asociarlo con el campo cuyo
contenido queremos mostrar.
El control de base de datos ms usado es TDBEdit, un derivado de TEdit
que permite la visualizacin y edicin del contenido de un campo. La
asociacin entre el campo y el control se establece mediante las
propiedades DataSource y DataField, como en el caso anterior. Por lo
dems, este control es prcticamente idntico a TEdit, contando con
las mismas propiedades.
11.4.2. Datos lgicos y botones de radio
En una base de datos pueden existir campos de tipo lgico o boolean,
as como campos que pueden tomar slo una serie de valores
predeterminados. A nuestra tabla de libros, por ejemplo, podramos
aadir un campo de tipo lgico que nos permitiese indicar si el libro
viene acompaado de software.
Tambin sera posible aadir un campo que nos permitiese clasificar el
inters de los libros, con valores como interesante, bueno, normal o
pobre, por poner un ejemplo.
Los campos de tipo lgico pueden ser gestionados en un formulario
mediante el control TDBCheckBox, que es a todos los efectos un control
TCheckBox que toma su valor de la base de datos a la cual est
enlazado por las propiedades DataSource y DataField.
En caso de que tengamos un campo que slo puede contener una serie de
valores limitado, podemos mostrarlo en el formulario como un conjunto
de botones de radio, mediante el control TDBRadioGroup.
Este control es prcticamente igual a TRadioGroup y cuenta con una
propiedad, Items, que nos servir para facilitar el ttulo de cada uno
de los valores posibles. Adems de las propiedades DataSource y
DataField, este control cuenta tambin con una propiedad llamada
Values, que nos servir para indicar los valores que puede tomar el
campo facilitndolos en el mismo orden en que se han facilitado los
ttulos en la propiedad Items. De esta forma, en nuestra tabla de
libros el inters podra ser un campo de un carcter, con los valores
I, B, N o P, que seran los que asignaramos a la propiedad Values,
mientras en el formulario estos valores apareceran como Interesantes,
Bueno, Normal o Pobre, que seran las cadenas a asignar a la propiedad

Items. En ejecucin podemos saber en cualquier momento qu valor es el


que se est representando en el control, gracias a que ste dispone de
una propiedad Value que lo contiene.
11.4.3. Textos extensos e imgenes
En el captulo anterior, al tratar el Database Desktop vimos que ste
no permita la visualizacin ni edicin detos tipos de campo, como
eran los campos MEMO y los que contenan grficos. Por tanto, para
poder ver y editar el contenido de estos campos tendremos que disear
un formulario en el que insertaremos los controles TDBMemo y TDBImage.
El control TDBMemo es como un TMemo que cuenta con las propiedades
DataSource y DataField que le permiten obtener y asignar su contenido
a un campo de la tabla que indiquemos. De igual forma, el control
TDBImage es a todos los efectos un TImage que cuenta tambin con las
propiedades mencionadas, lo que permite establecer un enlace entre l
y un campo de la base de datos.
Durante la ejecucin el contenido de un TDBMemo puede editarse
directamente, como si fuese un TMemo. El contenido del TDBImage
tambin puede ser modificado con simples operaciones de copiar y
pegar. Esto nos permite obtener las imagenes de cualquier programa,
sin importar el formato en que se encuentren, e insertarlas en nuestra
base de datos.
11.4.4. Listas y listas combinadas
De forma similar a como podemos utilizar un control DBRadioGroup, para
dar a elegir o mostrar un nmero de valores predeterminado y muy
limitado, tambin podemos usar con este fin los controles TDBListBox y
TDBComboBox. Estos dos controles permiten, sin embargo, que el nmero
de posibles valores sea ms amplio, al facilitar una visualizacin
parcial
mediante
una
lista
desplegable
o
unas
barras
de
desplazamiento.
El funcionamiento de TDBListBox y TDBComboBox es prcticamente igual,
si exceptuamos las diferencias visuales existentes entre ambos
controles. Una vez que hayamos asociado el control con un campo de la
base de datos, para lo cual nos serviremos de las propiedades
DataSource y DataField, asignaremos los valores posibles a la
propiedad Items. De esta forma, durante la ejecucin el usuario puede
seleccionar el contenido de ese campo entre los valores mostrados en
la lista, en lugar de tener que introducirlo manualmente.
Podramos usar un control TDBListBox para, por ejemplo, crear una
lista de editoriales posibles, de tal forma que el usuario del
programa no tiene por qu teclear su nombre, sino que lo seleccionar
directamente de la lista, evitando adems que unas veces se introduzca
el nombre de una forma y otras veces de otra diferente.

11.4.5. Rejillas de datos


Hasta ahora hemos conocido controles que nos permiten la visualizacin
y edicin de un solo campo de un nico registro de la tabla, siendo
necesaria la inclusin en el formulario de un control TDBNavigator
para permitir que el usuario pueda moverse por los datos. Existen, sin
embargo, otros controles que nos permiten gestionar de forma
simultnea mltiples campos de todos los registros seleccionados,
mostrando los datos en forma de tabla.
El control TDBGrid es uno de los controles ms completos y complejos
de Delphi, aunque su uso es bastante simple. Tan slo cuenta con la
propiedad DataSource y no con DataField, ya que este control no se
asocia con un campo de la base de datos.
Al insertar este control en el formulario y asociarlo al control
TDataSource, que a su vez estar asociado con un TTable TQuery,
podr ver que de forma inmediata se muestran todos los campos y todos
los registros disponibles. Incluso en modo de diseo puede actuar
sobre la tabla, desplazndola segn le interese, horizontal o
verticalmente, y modificando el ancho de las columnas y filas.
Como podr ver, inicialmente el ttulo de las columnas en el control
TDBGrid es el propio nombre de los campos. ste y otros aspectos del
funcionamiento de este control son configurables y la mejor forma de
hacerlo es usar la ventana del Editor de columnas, a la que
accederemos haciendo doble clic sobre el control o bien abriendo el
men emergente y seleccionando la opcin Columns Editor.
El Editor de columnas
En la figura 11.4 puede ver el aspecto del Editor de columnas del
control TDBGrid, en este caso con una lista que contiene los cuatro
campos de la tabla de alumnos que estamos utilizando como ejemplo,
inicialmente esta lista estar vaca, pero bastar con que pulse el
botn Add All Fields, tercero contando de izquierda a derecha, para
aadir todos los campos de la tabla o consulta. Previamente deber
haber asignado a la propiedad DataSource el valor adecuado, ya que de
lo contrario el control TDBGrid no podr acceder a los datos.
Si no deseamos que en el controlTDBGrid aparezcan todos los campos,
sino slo algunos que a nosotros nos interesen, podemos a continuacin
seleccionar en la lista los campos a eliminar, pulsando a continuacin
el botn Delete o la tecla <Supr>. Tambin podemos aadir columnas
individuales a la tabla, usando para ello el botn New o la tecla
<Insert>.

Figura 11.4. El Editor de columnas del control TDBGrid

Al seleccionar cualquiera de las columnas en el Inspector de Objetos,


que en la figura 11.4 se muestra a la derecha, se encuentran las
propiedades que afectan a los datos que se visualizarn y los ttulos
de cada una de esas columnas. Con ellas podemos, por ejemplo,
establecer el ttulo que nos interese, fijar la alineacin de los
datos de cada columna, as como el ancho de sta. Tambin podemos
seleccionar el color de fondo y tipo de letra, que puede ser diferente
para cada una de las columnas, y tambin para los ttulos de columna.
Si queremos que una cierta columna sea usada slo para mostrar una
informacin, evitando la edicin de su contenido, no tenemos ms que
dar el valor True a la propiedad ReadOnly de esa columna.
11.4.6. Rejillas de controles
El control TDBGrid es una de las alternativas que tenemos al uso del
control TDBNavigator, con el fin de permitir que el usuario pueda
acceder a los mltiples registros de datos, viendo de forma simultnea
varios de estos registros. Sin embargo, este control presenta los
datos de una forma, como si fuese una tabla, que en ocasiones puede no
interesamos. En este caso seguramente nos ser til el control
TDBCtrlGrid, que encontraremos ms a la derecha en la pgina Data
Controls de la Paleta de componentes.
Al insertar un control TDBCtrIGrid en el formulario podr apreciar que
cuenta con tres paneles, uno debajo de otro, dos de los cuales
aparecen con una trama de lneas inclinadas. El nmero de paneles y

sus dimensiones podemos configurarlos a nuestro gusto. Mediante la


propiedad ColCount indicaremos el nmero de columnas o paneles en
sentido horizontal, que inicialmente es uno. De forma anloga, la
propiedad RowCount nos permite especificar el nmero de filas, o
paneles en sentido vertical, que por defecto es tres. Mediante las
propiedades PanelHeight y PanelWidth fijaremos el alto y ancho,
respectivamente,
de
los
paneles,
que
tendrn
todos
idnticas
dimensiones. La propiedad PanelBorder, por ltimo, nos permite activar
o desactivar un borde entre los paneles, que por defecto est
activado.
Como podr observar, este control tan slo cuenta con la propiedad
DataSource, al igual queTDBGrid, ya que mediante l podremos mostrar
mltiples campos y mltiples registros.
Una vez que haya insertado en el formulario un control TDBCtrIGrid, y
asignado apropiadamente su propiedad DataSource, inserte en el panel
superior, el que no est lleno de lneas inclinadas, controles de
datos como los que hemos conocido hasta ahora. Puede insertar, por
ejemplo, un control TLabel y un control TDBEdit para cada uno de los
campos de la tabla de alumnos, disponindolos como se observa en la
figura 11.5. Tambin puede usar otros controles, como TDBCheckBox o
TDBComboBox.

Figura 11.5. Aspecto del formulario con el control TDBCtrlGrid


El aspecto ms interesante de este control no lo percibiremos hasta
que no ejecutemos el programa, en ese momento podemos ver que los

controles que nosotros hemos insertado en el primer panel son


repetidos en todos los dems paneles existentes en el TDBCtrlGrid,
permitiendo as la visualizacin y edicin de mltiples registros,
pero de una forma ms personalizada que la vista anteriormente
mediante el control TDBGrid. En la figura 11.6 puede ver el resultado
obtenido tenido en ejecucin del diseo anterior.

Figura 11.6. Edicin de mltiples registros con TDBCtrlGrid

11.5. Acceso programtico a los datos


Hasta ahora nos hemos centrado en el trabajo visual, el conocimiento
de una serie de controles y componentes que, sin escribir una sola
lnea de cdigo, facilitan la creacin de complejas plantillas de
entradas de datos. Sin embargo, en ocasiones desearemos acceder a los
datos de las tablas desde el cdigo de nuestro programa, con el fin de
realizar cualquier tipo de clculo, generar una lista, etc.
El componente TTable que hemos tratado ya anteriormente cuenta con una
serie de mtodos que nos permiten el desplazamiento por los registros,
la bsqueda, modificacin de datos, etc. Adems de este componente,
tambin necesitaremos conocer las propiedades y funcionamiento del
objeto TField, con el que se representa a cada uno de los campos de la
base de datos.

11.5.1. El objeto TField


Aunque en realidad cada uno de los campos de una tabla puede ser de
diferente tipo, Delphi necesita contar con una interfaz comn que le
permita gestionar todos los campos de una forma genrica, y esa
interfaz es la que establece el tipo TField. Realmente este tipo sirve
como base para otros, que sern los que realmente se utilicen,
actuando como una plantilla para todos los tipos derivados. En la
tabla 11.1 se enumeran los diferentes tipos derivados de TField,
indicndose el tipo de dato que almacena cada uno de ellos.
Tipo

Dato que almacena

TIntegerField
TSmallIntField
TWordField
TStringField
TFloatField
TBCDField
TBooleanField
TDateTimeField
TDateField
TTimeField

Nmeros enteros en el rango de Integer.


Nmeros enteros en el rango de SmallInt.
Nmeros enteros en el rango de Word.
Cadenas de hasta 255 caracteres.
Nmeros reales.
Nmeros decimales en punto fijo.
Valores de tipo Boolean.
Valores de tipo TdateTime (fechas y horas).
Fechas.
Horas.
Datos
arbitrarios
sin
un
tamao
predeterminado.
Datos arbitrarios con un mximo de 64 Kbytes.
Texto de longitud indeterminada.
Grfico de longitud indeterminada.

TBlobField y TBytesField
TVarBytesField
TMemoField
TGraphicField

Tabla 11.1. Tipos derivados de TField


En la prctica nosotros nunca crearemos un objeto TField, ni de
ninguno de sus tipos derivados/ya que estos objetos se crean
dinmicamente, durante la ejecucin, o bien estticamente, en la fase
de diseo, en caso de que mediante el Editor de campos del componente
TTable oTQuery se hayan indicado los campos que se desean manipular.
Acceso a un TField
Desde el cdigo de nuestro programa, en ejecucin, podemos acceder a
cada uno de los objetos TField bsicamente de dos formas, dependiendo
de que stos se hayan creado de forma dinmica o esttica.
Tanto el componente TTable como TQuery cuentan con una propiedad
llamada Fields, que es una matriz de objetos TField. Cada uno de los
elementos de esta matriz contiene una referencia a un objeto derivado
de TField, representando a cada uno de los campos de la tabla o de la

consulta. Aunque es posible acceder a un campo mediante su ndice en


esta matriz, en caso de que lo conozcamos, es mucho ms seguro
utilizar el mtodo FieldByName(), al que pasando como parmetro el
nombre del campo,nos devolver una referenda al objeto TField
correspondiente. Usando este mtodo evitaremos que nuestro cdigo
tenga problemas cuando, por ejemplo, el orden de los campos en la
tabla sea alterado. En el siguiente fragmento de cgido, en el que se
asume la existencia de un componente TTable llamado Table1, puede ver
cmo se asigna un valor al campo ttulo del registro actual de la
tabla.
Table1.FieldByName('Titulo').AsString := 'programacin con Java';
Esta forma de acceder a los campos de una tabla es cmoda, pero
tambin lenta e insegura, ya que el programa puede encontrarse en
ejecucin con que no encuentra un determinado campo. La alternativa a
este mtodo consiste en definir, durante el diseo, los campos que
estarn disponibles durante la ejecucin simplemente abriendo el
Editor de campos del TTable o TQuery y aadiendo los campos que
necesitemos. Esto conllevar la creacin esttica de los objetos
TField que correspondan, a los que podremos acceder directamente desde
el cdigo de nuestro
programa concatenando el nombre del componente
Ttable o TQuery con el nombre del campo. Esta referencia directa, sin
necesidad de realizar bsquedas en una matriz ni nada parecido, es
mucho ms rpida, adems de ser ms segura, ya que durante la
compilacin se comprueba si el objeto Tfield al que deseamos acceder
existe o no. En la sentencia siguiente puede ver cmo se realiza la
misma asignacin del ejemplo anterior, pero en este caso accediendo
directamente al campo.
Table1Titulo.Value := 'Programacin con Java';
Acceso al valor de un campo
En las dos sentencias que se han puesto como ejemplo en el punto
anterior, se usan dos propiedades diferentes para acceder al mismo
valor. La propiedad AsString, propia de TField y heredada por los
tipos derivados de la tabla 11.1, realiza una conversin del valor a
cadena. Esto es necesario porque el mtodo FieldByName() devuelve una
referencia a un TField y este tipo de campo no sabe si el valor es un
nmero, una cadena o una imagen. Por ello es necesario realizar una
conversin previa a la asignacin.
La segunda asignacin, en la que accedemos directamente al campo que
se ha creado estticamente, utiliza la propiedad Value para manipular
el valor del campo, sin necesidad de indicar que se trata de una
cadena. Esto es as porque el objeto Table1Titulo no es de tipo
TField, sino de tipo TStringField.
Por regla general, cuando deseemos acceder al valor de un campo
utilizando un objeto TField deberemos llevar a cabo la conversin que

corresponda, utilizando para ello


Asinteger, AsFloat o AsDateTime.

los

mtodos

AsString,

AsBoolean,

Sin embargo, cuando para acceder al valor de un campo estemos


utilizando uno de los tipos derivados de Tfield, cualquiera de los que
se enumeraron en la tabla 11.1, podremos usar la propiedad Value sin
ningn problema, ya que sta ser del tipo apropiado.
Ciertos tipos de campo, como TMemoField o TgraphicField, representan
valores que no pueden ser fcilmente manipulados mediante cdigo, como
son grficos o textos de longitud indeterminada. Estos tipos de objeto
cuentan con mtodos adicionales, como LoadPromFile() y SaveToFile(),
que facilitan la asignacin y obtencin del valor que almacenan.
Todos los tipos de campo, tanto TField como sus derivados, cuentan
tambin con los mtodos SetData() y GetData().
Mediante estos mtodos es posible la asignacin y obtencin del
contenido de cualquier campo, para lo cual deberemos facilitar la
direccin de un bloque de memoria en el que se almacenar la
informacin.
11.5.2. Mtodos de TTable
Sin bien ya sabemos cmo acceder a los datos de cada campo, segn los
pasos dados en el punto anterior, para poder manipular los datos de
una tabla o consulta necesitaremos adems desplazamos entre los
registros existentes. Para ello usaremos una serie de mtodos del
componente TTable que vamos a conocer seguidamente.
Antes de poder realizar cualquier operacin con los datos de una tabla
o consulta, sta deber estar abierta. Si hemos dado el valor True a
la propiedad Active durante el diseo no tendremos por qu
preocupamos, pero en caso contrario deberemos realizar una llamada al
mtodo Open() o bien dirrectamente asignar el valor True a la citada
propiedad.
Desplazamiento por los registros
Cuando se abre una tabla o consulta, el registro actual es siempre el
primero. Por tanto, cualquier acceso a los objetos TField estar
accediendo a los datos de ese primer registro.
Podemos situamos en el primer registro, en caso de que se hayan
realizado otras operaciones previas, con una simple llamada al mtodo
First(). De igual forma, podemos situamos en el ltimo registro
existente realizando una llamada al mtodo Last().
Para realizar un recorrido secuencial de los registros contenidos en
la tabla o consulta, usaremos los mtodos Next() y Prior(), que nos
llevarn al registro siguiente y anterior, respectivamente, siempre

que no estemos ya en el primer o ltimo registro. Podemos saber si


estamos ya en el primero de los registros comprobando el valor de la
propiedad BOF, en caso de ser True ello indicar que no hay registros
anteriores al actual. De igual forma, podemos saber si estamos ya en
el ltimo registro mediante la propiedad EOF.
Tambin podemos avanzar o retroceder un determinado nmero de
posiciones a partir del registro actual utilizando el mtodo MoveBy().
Este mtodo toma como parmetro un nmero entero, positivo o negativo,
indicando
el
nmero
de
registros
a
avanzar
o
retroceder,
respectivamente.
Tareas de edicin
Una vez que nos hemos situado en el registro apropiado podemos
facilitar la edicin de su contenido, a partir de los controles de
bases de datos que ya conocemos, con una simple llamada al mtodo
Edit(). Previamente debemos comprobar si el registro puede ser
modificado o no, consultando el valor de la propiedad CanModify. Si
esta propiedad contiene el valor False, indicando que el registro no
puede ser modificado, no debemos realizar una llamada a Edit(), ya que
ello causara una excepcin.
Las modificaciones que se efecten en un determinado registro no sern
escritas en la tabla o tablas correspondientes hasta en tanto no se
realice una llamada al mtodo Post(), ya sea directa o indirectamente.
Cuando tras haber realizado una modificacin se hace una llamada a
ciertos mtodos, como los que hemos visto antes para desplazamos por
los registros, automticamente se realiza una llamada al mtodo
Post(), de tal forma que los datos son guardados antes de cambiar de
registro.
Si no deseamos que los cambios efectuados a un registro sean
guardados, en lugar de utilizar el mtodo Post() haremos una llamada
al mtodo Cancel(), lo que devolver los valores originales a los
campos y cancelar el modo de edicin. Tenga en cuenta que si no desea
guardar unos cambios de edicin, no le basta con abandonar el registro
desplazndose a otro, ya que esa operacin implica una llamada
indirecta a Post(). Por tanto, siempre que desee cancelar una
operacin de edicin deber hacerlo de forma explcita, llamando a
Cancel().
Adems de modificar un registro que ya existe, tambin podemos aadir
o insertar nuevos registros mediante los mtodos Append() e Insert().
En el primer caso el registro se aade al final de la tabla, mientras
que en el segundo el registro se inserta en la posicin actual,
desplazando a los registros posteriores. En ambos casos se pasa
automticamente al modo de edicin, permitiendo as la entrada de
nuevos, valores, que sern escritos una vez que se realice la llamada
al mtodo Post(). La operacin de aadir o insertar un nuevo registro

tambin puede
anteriormente.

ser

cancelada

mediante

el

mtodo

Cancel()

visto

Tambin es posible, lgicamente, eliminar informacin de una base de


datos, borrando los registros que nos interese. Para ello, y una vez
que nos hayamos posicionado en el registro a borrar, bastar con
realizar una llamada al mtodo Delete().
Trabajo con ndices
Asociados a una tabla pueden existir uno o ms ndices, cuya finalidad
principal es establecer el orden de los registro y agilizar los
procesos de bsqueda. El nombre del ndice activo est contenido en la
propiedad IndexName del componente TTable, propiedad cuyo valor
podemos alterar durante la ejecucin para activar el ndice que nos
interese.
El orden de los registros de una tabla est determinado por los
valores de los campos que actan como ndice principal o primario. En
el mismo momento en que se cambia de ndice, asignando el valor
apropiado a la propiedad IndexName, el orden de los registros se
recalcula, de acorde con los valores de los campos que correspondan.
Como se ha dicho antes, un ndice tambin es til a la hora de buscar
registros, principalmente agilizando este proceso que, de otra manera,
habra que realizarlo leyendo todos los datos de la tabla. Para buscar
el primer registro que contiene en el campo o campos clave un
determinado valor, no tenemos ms que realizar una llamada al mtodo
FindKey(), pasando como parmetro un conjunto con los valores
buscados. Este mtodo devolver True en caso de que se encuentre la
clave dada, posicionndose adems en ese registro.
Un ejemplo
Veamos en la prctica cmo podemos utilizar alguno de los mtodos que
hemos visto, por ejemplo para disear un programa que nos permita
listar todos los alumnos correspondientes a una cierta provincia. En
este programa el usuario introducir el nombre de la provincia, en un
control TEdit, y el cdigo que nosotros vamos a escribir buscar todos
los alumnos existentes, mostrndolos en un TListBox.
Comience por abrir la tabla en el Database Desktop y aadir un ndice
secundario, que estar basado exclusivamente en el campo Editorial.
Una vez dado este paso, tendremos que disear el formulario que puede
ver en la figura 11.7, en la que hemos insertado un TEdit y TListBox,
ambos encabezados con un TLabel, un TButton y un componente TTable,
que es el nico componente de base de datos.

Figura 11.7. Aspecto del formulario a disear


Seguidamente deberemos establecer las propiedades oportunas para poder
acceder mediante el componente TTable a la tabla de alumnos que
estamos utilizando en los ejemplos. Debe asignar, por tanto, el valor
adecuado a las propiedades DatabaseName y TableName. Despliegue la
lista adjunta a la propiedad IndexName seleccionando el ndice por
provincia que hemos definido. Por ltimo asigne el valor True a la
propiedad Active, con el fin de que la tabla est ya abierta al
ejecutar el programa.
A continuacin haga doble clic sobre el TButton, con el fin de abrir
el Editor de cdigo creando el mtodo asociado al evento OnClick de
este control, e introduzca el cdigo siguiente.
procedure TForm1.Button1Click(Sender: TObject);
begin
With Table1 Do
Begin
{ Eliminamos ttulos de bsquedas anteriores }
ListBox1.Items.Clear;
First; // Nos ponemos al principio de la tabla
{ Si encontramos la provincia buscada }
If FindKey([Edit1.Text]) Then
Repeat
{ Aadimos el alumno a la lista }
ListBox1.Items.Add(FieldByName('Nombre').AsString);
Next; //y pasamos al registro siguiente
{ repitiendo mientras la provincia coincida
y no lleguemos al final de la tabla }
Until (FieldByName('Provincia').AsString <> Edit1.Text)
Or EOF;
End;

end;
Lo primero que hacemos es eliminar cualquier contenido de la lista,
realizando una llamada al mtodo Clear() de la propiedad Items. Esto
evitar que en la lista se acumulen resultados de varias bsquedas. A
continuacin nos desplazamos hasta el primer registro de la tabla y
usamos el mtodo FindKey() para buscar la provincia introducida en el
TEdit. En caso de que se encuentre una coincidencia, aadimos el
nombre del registro encontrado a la lista, avanzando al registro
siguiente con una simple llamada al mtodo Next(). Estas dos ltimas
sentencias se repetirn continuamente, hasta en tanto no se encuentre
una editorial diferente o se llegue al ltimo registro de la tabla.
12. Creacin de Informes

12.1. Introduccin
En Delphi 5 el diseo de informes se basa en el uso de los componentes
QuickReport, que encontraremos en la pgina QReport de la Paleta de
componentes. Mediante estos componentes es posible disear un informe
fcilmente, utilizando un formulario para la composicin visual. La
ventaja de QuickReport frente a otras herramientas de diseo de
informes se trata de un conjunto de componentes VCL y, como tal su
cdigo pasa a formar parte de nuestro propio programa sin necesidad
as de tener que distribuir aplicaciones separadas. Adems, la
generacin de un informe con QuickReport es ms rpida, ya que no es
necesaria la ejecucin de un programa independiente.
lo largo de este captulo vamos a aprender a usar los componentes
QuickReport para generar informes simples. Los datos que utilizaremos
sern los de la tabla de libros que se cre
como ejemplo en el
captulo 9 y se ha usado en diversos ejemplos del 10.

12.2. Funcionamiento general de QuickReport


Antes de entrar en los detalles propios de cada componente, vamos a
adquirir una idea general sobre su funcionamiento,lo que nos ser til
para tener una visin global y conocer ya de antemano los pasos
fundamentales que habremos de dar al disear un informe.
El formato de un informe QuickReport se disea en un formulario, lo
que hace innecesario el uso de una ventana separada con este fin.
Dicho
formulario
se
transforma
automticamente
en
un
informe
QuickReport en el momento en que insertamos en ella un componente
TQuickReport. Este componente nos servir para relacionar el informe
con los datos a utilizar en el mismo, adems de para establecer
algunos aspectos generales.
Por regla general, todo informe se divide en mltiples secciones, como
pueden ser la cabecera, cuerpo, pie, divisiones de grupo, etc. Cada
una de estas secciones est representada mediante un componente

TQRBand. Este componente aparece visualmente, al insertarlo en el


formulario, como una franja de izquierda a derecha y acta como un
contenedor, de tal forma que es posible insertar en l los componentes
necesarios para mostrar la informacin adecuada en cada seccin.
Entre estos componentes encontramos TQRDBText, TQRMemo y TQRLabel, que
facilitan la impresin de un texto, un campo MEMO o un ttulo,
respectivamente.
Mediante el componente TQRGroup es posible agrupar los datos de un
informe basndose en uno o ms campos, esta agrupacin puede
producirse simplemente a partir del orden de los registros o bien para
generar un informe maestro/detalle, para lo cual deberemos usar adems
el componente TQRSubDetail.
El aspecto del informe puede ser realzado incluyendo en l diversos
elementos grficos, usando el componente TQRShape. Este componente, al
igual que otros, habr d incluirse en el TQRBand correspondiente a la
Seccin en la que Se desea hacer aparecer el elemento grfico.
Adems de los elementos de realce, los ttulos y los propios datos, en
un informe tambin pueden aparecer otras informaciones, como campos
calculados e informacin de sistema. En el primer caso usaremos el
componente TQRExpr, facilitando el clculo a realizar, mientras que en
el segundo usaremos un TQRSysData, mediante el cual podremos obtener
la fecha actual, el nmero de pgina y datos similares.
Una vez que el informe est diseado, en ejecucin ste puede ser
visualizado en pantalla, haciendo una visualizacin previa, o bien
directamente impreso. Tambin es posible exportarlo a un archivo en
diversos formatos. .Para ello el componente TQuickReport dispone de
los mtodos adecuados.

12.3. El componente TQuickReport


Este es el componente central de todo informe QuickReport. Su
insercin en el formulario provoca que sta se comporte como una
ventana de diseo de informe y no como un formulario normal. El primer
cambio que podremos apreciar, en el mismo momento en que insertemos el
TQuickReport, es que en el formulario aparece una barra de
desplazamiento horizontal y otra vertical, cuya finalidad es facilitar
el desplazamiento por las secciones del informe, que pueden ocupar
bastante ms espacio del disponible fsicamente en el formulario.
Utilizando las opciones Zoom in y Zoom out del men emergente,
podremos ver Todd el informe e ir ampliando la seccin que nos
interese.
Para iniciar el diseo de un informe usted puede partir de cero, con
un formulario vaco, o bien de un informe predefinido. En el Depsito
de objetos existen varios modelos de informe prediseados que podemos
aadir a nuestro proyecto segn nos interese.

12.3.1. Seleccin de los datos a imprimir


Los datos a imprimir en el informe vendrn, en la mayora de los
casos, del contenido de una base de datos, aunque tambin es posible
facilitar los datos a imprimir desde otras fuentes gracias a la
existencia de un evento, OnNeedData, que se produce cada vez que se
necesita un registro de datos a imprimir.
Al igual que el componente TDataSource, un TquickReport cuenta con una
propiedad DataSet mediante la cual relacionamos el informe con un
TTable o TQuery. En cualquier caso, el componente TQuickReport se
encargar de ir avanzando de un registro a otro, recuperando los datos
para el informe.
12.3.2. Formato del informe
Mediante el componente TQuickReport podemos prefijar el tamao de
papel, los mrgenes, el nmero de columnas o el espaciado entre stas.
Todos estos elementos forman parte de la propiedad Page, un objeto
TQRPage que cuenta, entre otras, con las propiedades PaperSize,
LeftMargin, RightMargin, Orientation y Columns. Los valores de muchas
de estas propiedades vienen expresados por defecto en milmetros,
unidad de medida que podemos cambiar alterando la propiedad Units.
Adems de los ttulos que podamos disponer en las diferentes secciones
del informe, y que nos pueden servir para encabezar diversos
apartados, columnas, etc., en el informe existe un ttulo general que
es el que se almacena en la propiedad ReportTitle del componente
TQuickReport.
Muchos de los parmetros de impresin, como el nmero de copias, la
bandeja de papel a utilizar o el rango de pginas a imprimir, los
estableceremos con la propiedad PrinterSettings, que al igual que Page
contiene una serie de propiedades como FirstPage, LastPage, Copies u
OutputBin.
Con el fin de facilitar la alineacin de los componentes de datos, en
el interior del TQuickReport existen una serie de lneas de divisin,
una cuadrcula, numerada en la unidad de medida que hayamos
seleccionado. La propiedad Page dispone de una propiedad, llamada
Ruler, mediante la cual podremos mostrar u ocultar esa cuadrcula.
12.3.3. Informacin durante la ejecucin
Una vez que el informe ha sido preparado, durante la ejecucin podemos
obtener alguna informacin acerca de l partiendo de ciertas
propiedades. La preparacin del informe se realiza automticamente,
antes de mostrarlo en pantalla o imprimirlo, aunque tambin es posible

realizar la preparacin, sin ms, con una simple llamada al mtodo


Prepare().
Mediante la propiedad RecordCount podemos saber el nmero de registros
que van a formar parte del informe, mientras que la propiedad
RecorNumber nos facilita el nmero de registro que se est procesando
actualmente. Podemos tambin conocer el nmero pgina actual con la
propiedad PageNumber.
12.3.4. Visualizacin e impresin del informe
Estando el informe ya diseado, podemos optar por visualizarlo o bien
imprimirlo directamente. Para ello disponemos de los mtodos Preview()
y Print(). Lo primero que ocurre cuando se llama a cualquiera de estos
mtodos, es que se prepara el informe, proceso en el cual se puede
invertir ms o menos tiempo dependiendo de la cantidad de datos a
manipular y la relacin que pueda existir entre ellos. Mientras dura
este proceso, opcionalmente se puede mostrar una ventana en cual se
indica el tanto por ciento que se lleva realizado.
Si deseamos que esta ventana aparezca no tenemos que hacer nada, ya
que por defecto la propiedad ShowProgress tiene el valor True,
indicando as que s debe mostrarse dicha ventana.
Tambin durante el diseo es posible realizar una visualizacin previa
del informe, lo que nos permite ir viendo si ste queda tal y como
nosotros deseamos. Puede insertar un control TQuickReport en un
formulario y, a continuacin, hacer doble clic sobre l para hacer
aparecer la ventana de parmetros generales del informe que se muestra
en la figura 12.1.

Figura 12.1. Parmetros generales del informe

Pulsando el botn Preview se har una vista previa del informe, como
se observa en la figura 12.2, vaca puesto que an no se han insertado
datos en el informe, aunque ya contamos con una serie de botones que
nos permiten ajustar la visualizacin e imprimir el informe.

Figura 12.2.

Ventana de visualizacin previa en tiempo de diseo

12.4. El componente TQRBand


Cada pgina del informe debe tener, al menos, una seccin en la que se
imprimen datos, ya que de lo contrario el informe aparecer vaco.
Esta seccin estar representada por un componente TQRBand. En la
prctica, existirn varios componentes de este tipo en el formulario
en la que se disea el informe, con el fin de definir una cabecera, un
cuerpo de datos, un pie, etc.
Mediante el mismo tipo de componente, TQRBand, podemos definir, por
tanto, secciones que actan de forma diferente. Una cabecera de
pgina, por ejemplo, se imprimir slo una vez y al principio de cada
pgina, mientras que la seccin que compone el cuerpo se repite
mltiples veces en cada pgina. Este funcionamiento del componente
TQRBand viene determinado, en parte, por el valor que asignemos a la

propiedad BandType, que ser uno de los que se enumera en la tabla


12.1.
Constante

Tipo de seccin

rbTitle
rbPageHeader
rbDetail
rbChild
rbPageFooter
rbSummary
rbGroupHeader
rbGroupFooter
rbColumnHeader
rbOverlay

Ttulo del informe.


Cabecera de pgina.
Cuerpo del informe.
Detalle de un registro maestro.
Pie de pgina.
Pie de informe.
Cabecera de grupo.
Pie de grupo.
Cabecera de columna.
Seccin superpuesta.

Tabla 12.1. Valores posibles para la propiedad BandType


Por regla general, en un informe contaremos al menos con una seccin
rbDetail, que usaremos para imprimir los datos del informe. Tambin es
habitual usar una seccin rbTitle, para imprimir el ttulo del
informe, una seccin rbPageHeader y otra rbPageFooter, para disponer
elementos
que
aparecern
como
cabecera
y
pie
de
pgina,
respectivamente. La seccin de tipo rbSummary es til, por ejemplo,
para imprimir unos totales finales que resuman el informe. Mediante el
tipo rbOveriay podemos insertar en el informe una seccin que actuar
como fondo, sobre la cual se imprimirn las dems. Esto nos permite,
por ejemplo, la insercin en el informe de una imagen o dibujo de
fondo.
En lugar de insertar componentes TQRBand seleccionndolos de la Paleta
de componentes y colocndolos en el informe, podemos abrir la ventana
de parmetros generales del informe, mostrada en la figura 12.1, y
seleccionar en la parte inferior las secciones que deseamos que
existan en el informe. De esta forma los componentes sern insertados
automticamente.
12.4.1. Aspecto de la seccin en el informe
Los datos que se incluyan en la seccin que representa el componente
TQRBand tomarn por defecto el tipo de letra que nosotros hayamos
fijado en la propiedad Font. Si deseamos que la apariencia del informe
sea similar en pantalla y en el papel, el tipo de letra deber ser del
tipo wysiwyg, por ejemplo un tipo TrueType.
El color de fondo de la seccin tambin es confgurable, disponiendo
para ello el componente TQRBand de una propiedad Color. Esta

propiedad, al igual que todas las


constante, representando a un color.

de

su

tipo,

puede

tomar

una

12.4.2. El componente TQRExpr


En un informe, adems de ttulos y datos almacenados en la base de
datos, tambin es posible incluir datos que se calculan en ejecucin.
Estos datos se representarn mediante componentes TQRExpr, en cuya
propiedad Expression se facilitar la expresin a evaluar. En ella
podremos componer la expresin a partir de una lista de funciones,
operadores y campos de las tablas segn nos interese.
Habitualmente este componente se utiliza para imprimir resmenes al
final del informe, en los pies de grupo o pies de pgina.
12.4.3. El componente TQRSysData
Mediante este componente podemos aadir otros datos al informe, como
puede ser la fecha de impresin, el nmero de pgina o el nmero de
registros. El funcionamiento de este componente es similar a TQRLabel
si exceptuamos la existencia de la propiedad Data, mediante la cual
podemos elegir la informacin a imprimir. Esta propiedad tomar uno de
los valores que se muestran en la tabla 12.2. Como es lgico, este
componente no cuenta con la propiedad Caption, que se ve sustituida en
cierta forma por la propiedad Data.
Constante
qrsTime
qrsDate
qrsDateTime
qrsPageNumber
qrsReportTitle
qrsDetailCount
qrsDetailNo

Informacin a mostrar
Hora de impresin del informe.
Fecha de impresin del informe.
Fecha y hora de impresin del informe.
Nmero de pgina actual.
Ttulo del informe.
Nmero total de registros en el informe.
Nmero de registro actual.

Tabla 12.2. Valores posibles para la propiedad Data


El ttulo del informe, que representa el valor qrsReportTitle, es el
que
previamente
nosotros
habremos
facilitado
en
la
propiedad
ReportTitle del componente TQuickReport, que por defecto se imprime en
una seccin con el tipo rbTitle.
12.4.4. El componente TQRShape
Adems del borde alrededor de cada seccin, cuya existencia y
apariencia
podemos
controlar
mediante
la
propiedad
Frame
del
componente TQRBand, en el informe podemos incluir otros elementos de
realce. Para ello usaremos el componente TQRShape que, en cierta

forma, es el equivalente
captulo anterior.

al

control

TShape

que

conocimos

en

un

Segn el valor que asignemos a la propiedad Shape, que ser uno de los
que se enumeran en la tabla 12.3, aparecer en el informe una figura u
otra. El borde e interior de la figura puede tener un color u otro y
un tipo de relleno u otro, dependiendo de las propiedades Brush y Pen,
cuyo funcionamiento tambin conocemos.
Constante

Figura a dibujar

qrsRectangle
qrsCircle
qrsVertLine
qrsHorLine
qrsTopAndBottom
qrsRightAndLeft

Rectngulo
Crculo.
Una lnea vertical.
Una lnea horizontal.
Lneas horizontales arriba y abajo.
Lneas verticales a la izquierda y derecha.

Tabla 12.3. Valores posibles para la propiedad Shape


12.4.5. Imgenes en el informe
Como podr comprobar, en la pgina QReport de la Paleta de componentes
existen dos componentes muy similares cuya finalidad es la insercin
de una imagen en el informe. El componente TQRImage nos ser til para
insertar cualquier imagen, mientras que TQRDBImage ser el adecuado en
caso de que las imgenes se encuentren almacenadas en tablas de una
base de datos.
Podemos incluir una imagen en una seccin de cabecera, por ejemplo
para insertar un logotipo. Tambin ser til en el caso de que cada
registro de la base de datos contenga alguna imagen, como podra ser,
por ejemplo, la portada de cada libro.
Otro uso habitual de las imgenes en un informe, en combinacin con
una seccin de tipo rbOverlay, es dibujar un fondo en el papel, sobre
el que se mostrarn los datos propiamente dichos. Este fondo suele ser
claro y no demasiado complejo, con el fin de no impedir la correcta
visin de los datos, que es lo que realmente importa del informe.
12.4.6. Un ejemplo
Para ver en la prctica cmo podemos utilizar los diversos componentes
que hemos conocido hasta ahora, vamos a disear un informe que nos
permita obtener una lista de los libros que tenemos almacenados en
nuestra base de datos.
Partiremos insertando en el formulario un componente TTable, asignando
a las propiedades DatabaseName y TableName los valores adecuados para

acceder a la tabla de libros. No olvide dar el valor True a la


propiedad Active del TTable, ya que ello le permitir trabajar con
datos reales mientras disea el informe, facilitndole as la
colocacin y ajuste de los controles.
Inserte ahora un componente TQuickReport, asignando a su propiedad
DataSet el nombre del TTable que hemos insertado antes. Asigne a la
propiedad ReportTitle el valor 'Lista de libros'. A continuacin
inserte en el formulario cinco componentes TQRBand, uno debajo de
otro, y asigne a la propiedad BandType de cada uno los valores
rbTitle,
rbPageHeader,
rbDetail,
rbPageFooter
y
rbSummary,
respectivamente. De esta forma contamos con una seccin para mostrar
un ttulo, otra que acta como encabezado de pgina, una tercera que
es en la que se mostrarn los datos, una cuarta que ser el pie de
pgina y por ltimo un resumen de informe. Veamos ahora qu controles
insertaremos en cada una de estas secciones.
La seccin de ttulo del informe
En la primera seccin del informe tan slo vamos a insertar un
componente TQRSysData, que nos servir para mostrar el ttulo que
previamente hemos asignado a la propiedad ReportTitle. Seleccione de
la lista adjunta a la propiedad Data el valor qrsReportTitle.
Al ser el ttulo del informe, ste deber aparecer en un tipo de letra
algo mayor que el resto. Haga doble clic sobre la propiedad Font y
fije el tamao y estilo de letra para el ttulo.
Por ltimo, asigne el valor taCentera la propiedad Alignment, con el
fin de que el ttulo aparezca centrado horizontalmente en la pgina.
Esta alineacin se producir en el momento en que se prepare el
informe, tomando el ttulo que se haya asignado.
La cabecera de pgina
El siguiente apartado que tenemos es la cabecera de pgina, una
seccin que se repetir mltiples veces, una por cada pgina con que
cuente el informe.
En esta seccin deber insertar tres controles TQRLabel, con los
ttulos Ttulo', 'Autor' y 'Editorial'. Colquelos uno a la derecha de
otro, con la separacin suficiente como para poder mostrar estos datos
de la tabla. Inserte debajo un componente TQRShape en forma de lnea
horizontal, que le servir como separacin visual entre la cabecera y
el cuerpo del informe.
El cuerpo
La tercera seccin del informe es la que va a contener los datos
propiamente dichos, componiendo el cuerpo del informe. En esta seccin
insertaremos tres componentes TQRDBText, relacionando cada uno de

ellos con las columnas apropiadas de la tabla de libros. Coloque cada


componente alineado debajo del ttulo que ha insertado anteriormente
en la cabecera de pgina.
Con el fin de evitar un espacio demasiado amplio en el informe, que
llevara a que ste contase con ms pginas de las necesarias, ajuste
la altura de la seccin para que sea la justa que ocupa el texto de un
campo.
El pie de pgina
La seccin siguiente, al igual que la cabecera de pgina, se repetir
una vez por cada pgina, imprimindose en la parte inferior de sta.
Vamos a utilizar esta seccin para mostrar la fecha de impresin y el
nmero de pgina, por lo que tendremos que incluir dos componentes
TQRSysData, uno a la izquierda y otro a la derecha, asignando a la
propiedad Data los valores qrsDate y qrsPageNumber, respectivamente.
Puede preceder el nmero de pgina con un ttulo, insertando a su
izquierda con un componente TQRLabel y asignando a la propiedad
Caption la cadena 'Pgina'.
La seccin de resumen
Por ltimo nos encontramos con la secdn de resumen del informe, en la
que simplemente vamos a indicar el nmero de ttulos que se han
incluido en ste. Para ello insertaremos un componente QRLabel, con la
cadena 'Nmero de ttulos' y un componente QRExpr, cuya expresin a
evaluar ser simplemente COUNT.
Puede separar este resumen del cuerpo del informe mediante una lnea
horizontal, insertando un componente QRShape al igual que hicimos
anteriormente en la cabecera de pgina. Con todo, el aspecto del
informe en modo de diseo es el que se muestra en la figura 12.4.

Figura 12.4. Aspecto del informe en tiempo de diseo


Ejecucin del informe
El formulario en el que hemos diseado el informe, que al ser el nico
del proyecto es el principal, no cuenta con ningn elemento visual con
el que el usuario pueda interactuar. En la prctica este formulario
nunca debera aparecer en pantalla, ya que su finalidad es contener
todos los componentes del informe.
Para poder ver el resultado del informe, por tanto, deber aadir otro
formulario al proyecto, seleccionndolo adems como formulario
principal. A continuacin utilice la opcin Use Unit del men File
para hacer referencia al primer mdulo desde el segundo. Inserte en el
nuevo formulario un botn, y escriba la siguiente lnea de cdigo en
el mtodo correspondiente al evento OnClick.
Form1.QuickReport1.Preview;
Ya
puede
ejecutar
el
programa,
que
inicialmente
no
tendr
funcionalidad alguna ms que la de poder pulsar ese botn, mostrndose
el informe que puede ver parcialmente en la figura 12.5. Tambin puede
llegar a este mismo punto simplemente seleccionando la opcin Preview
del men emergente del TQuickReport durante el diseo.

Fig 12.5. Resultado obtenido del informe

13. Componentes avanzados

13.1. Introduccin
Una de las caractersticas de Delphi 5 es su total soporte para los
controles avanzados de Windows 95/98 y NT, que bsicamente realzan la
interfaz y facilitan su uso. Estos componentes los encontramos en la
pgina Win32 de la Paleta de componentes y vamos a conocer los ms
importantes a lo largo de este captulo.
y Adems de en Windows 95/98, muchos de estos componentes tambin
podrn utilizarse en Windows NT 3.51 si tiene instalada la nueva
interfaz, as como en la versin 4.0, que utiliza ya el nuevo aspecto
creado por Microsoft en Windows 95.

13.2. Valores discretos y rangos


En el captulo 6 de esta gua, dedicado a los componentes ms
habituales de Delphi, conocimos algunos controles que nos permitan
solicitar datos al usuario de diferentes formas. El control TTrackBar
representa una manera alternativa de solicitar un dato, en este caso
numrico, que se encuentre entre unos ciertos lmites. En cierta forma

el funcionamiento de este componente es similar a TScrollBar, pero no


tiene por qu ir necesariamente asociado al desplazamiento de algn
elemento.
El rango de valores entre los cuales es posible moverse vendr
determinado por las propiedades Min y Max, mientras que la posicin
actual, indicada por un puntero, depender del valor que contenga en
cada momento la propiedad Position.
Al igual que ocurre con un control TScrollBar, el control TTrackBar
puede ser manipulado por el usuario, en ejecucin, tanto con el ratn
como con el teclado, causando cambios en la posicin actual. Mediante
las propiedades LineSize y PageSize podremos fijar el factor, de
incremento o decremento, que se utilizar segn se desee desplazar una
lnea o una pgina, respectivamente.
Podemos utilizar un control TTrackBar disponindolo en la ventana en
sentido horizontal o vertical, segn nos interese, simplemente dando
el valor apropiado a la propiedad Orientation, que ser trHorizontal o
trVertical, respectivamente.
13.2.1. Marcas de posicin
A diferencia de una barra de desplazamiento normal, el control
TTrackBar puede mostrar en su interior unas marcas mediante las cuales
se puede indicar la posicin de cada punto. La existencia o no de
estas marcas, as como su disposicin, depender del valor que se
asigne a la propiedad TickStyle, que ser uno de los que se muestra en
la tabla 13.1, siendo el valor tsAuto el que se toma por defecto.
Si elegimos el estilo tsAuto, las marcas se dispondrn automticamente
a lo largo o ancho del control con la frecuencia que nosotros mismos
indiquemos en la propiedad Frequency. En caso de que optemos por el
estilo tsManual inicialmente tan slo existirn dos marcas, una al
inicio y otra al final, pudiendo nosotros disponer cualquier otra
mediante el mtodo SetTck(), al que pasaremos como parmetro un
entero indicando la posicin en la que se ha de situar la marca.
Constante
tsNone
tsAuto
tsManual

Tipo de marca
Ninguna.
Automtica.
Manual.

Tabla 13.1. Valores posibles para la propiedad TickStyle


La posicin en la que se dispondrn las marcas en el control depender
del valor que contenga la propiedad TickMarks, que habr de ser
necesariamente uno de los enumerados en la tabla 13.2. El valor tomado

por defecto es tmBottomRight, por lo que inicialmente


aparecen en la parte inferior o derecha del control.
Constante
tmBottomRight
tmTopLeft
tmBoth

las

marcas

Disposicin de las marcas


Abajo o a la derecha, segn la orientacin.
Arriba o a la izquierda, segn la orientacin.
A ambos lados del control.

Tabla 13.2. Valores posibles para la propiedad TickMarks


13.2.2. Seleccin de rangos
Adems de reflejar una posicin, el control TtrackBar tambin puede
mostrar la seleccin de un rango o franja de los valores que
representa. Para ello tendremos que usar las propiedades SelStart y
SelEnd,
a
las
que
asignaremos
el
valor
de
inicio
y
fin,
respectivamente, de la franja a mostrar como seleccionada.
A diferencia de la posicin, que es un factor modificable durante la
ejecucin por la actuacin directa del usuario, la seleccin de un
rango en un control TTrackBar tan slo es programable mediante cdigo,
utilizando las dos propiedades citadas.
13.2.3. En la prctica
Veamos en la prctica cmo podemos usar el control TTrackBar, en este
ejemplo para seleccionar los componentes de rojo, verde y azul de un
color. Este programa nos puede servir para conocer la magnitud de cada
componente, que podemos usar posteriormente en nuestros programas
mediante la funcin RGB(), para obtener el color deseado.
Comenzaremos, como es habitual, insertando en el formulario los
componentes precisos para crear la interfaz del programa, que ser
similar a la que se muestra en la figura 13.1. Como puede ver se han
insertado tres controles TTrackBar, encabezados por tres controles
TLabel que sirven como ttulos y otros tres controles TLabel que nos
servirn para mostrar el valor de cada componente del color. La parte
derecha del formulario est ocupada por un control TPanel, cuyo fondo
nos servir para mostrar el color seleccionado en cada momento.

Figura 13.1. Aspecto del formulario con los controles TTrackBar

Seleccione los tres controles TTrackBar con el fin de facilitar la


modificacin conjunta de sus propiedades. Asigne a la propiedad Max el
valor 255, ya que cada uno de los componentes de un color puede estar
comprendido entre cero, que es el valor mnimo por defecto, y 255.
Al realizar la modificacin anterior podr apreciar que las marcas,
que estn en la parte inferior del control, tienen tanta densidad que
forman una lnea continua. Esto se debe a que por defecto la
frecuencia de las marcas es 1, valor que nosotros vamos a modificar
utilizando en su lugar el 16.
Vamos ahora con las propiedades del control TPanel, cuyo color de
fondo inicialmente ser el negro. Por tanto, tendremos que modificar
la propiedad Color, seleccionando el color clBIack.
Por ltimo modificaremos las propiedades de los tres controles TLabel
en los cuales vamos a mostrar los componentes de rojo, verde y azul.
D el valor False a la propiedad AutoSize de estas propiedades, asigne
el valor taRightJustify a la propiedad Alignment y establezca como
valor inicial de la propiedad Caption la cadena "0".
El ltimo paso que habremos de dar ser escribir el cdigo necesario
para que cuando se modifique la posicin en uno de los controles
TTrackBar, momento en el que ste generar un evento OnChange, se
actualice apropiadamente el color del TPanel, as como los valores
mostrados en los tres TLabel. Puesto que esta actuacin ser la misma
indistintamente de que se modifique la posicin de un componente u
otro, escribiremos un solo mtodo que asedaremos al evento OnChange de
los tres controles. El cdigo necesario es el que se muestra
seguidamente.
{ Al modificar la posicin de cualquiera de los controles
TtrackBar }

Procedure TForm1.TrackBar2Change(Sender: Tobject);


begin
// Establecemos el nuevo color del TPanel
Panel1.Color := RGB(TrackBar1.Position, TrackBar2.Position,
TrackBar3.Position);
//y mostramos los componentes del color
Label4.Caption:= IntToStr(TrackBar1.Position);
Label5.Caption:= IntToStr(TrackBar2.Position);
Label6.Caption:= IntToStr(TrackBar3.Position);
end;
Ahora ya puede ejecutar el programa, seleccionando el factor de rojo,
verde y azul para ir viendo los colores hasta encontrar el que le
interese, momento en el que podr anotar la magnitud de cada
componente. El aspecto del programa, en ejecucin, ser similar al
mostrado en la figura 13.2.

Figura 13.2. Aspecto del programa en ejecucin

13.3. Curso de un proceso


El componente TProgressBar se utiliza, principalmente, para indicar el
punto en el que se encuentra un proceso en curso. En el captulo
anterior vimos cmo, por ejemplo, el componente TQuickReport utilizaba
una barra de progreso para indicar que estaba en marcha el proceso de
preparacin del informe.
La forma de utilizar este control es bastante simple, ya que su
funcionamiento se basa prcticamente en tres propiedades que ya
conocemos, como son Min, Max y Position. Mediante las dos primeras
indicaremos los valores de inicio y fin del proceso, mientras que la
ltima determinar la posicin actual de ese proceso. Por defecto el
rango de valores est comprendido entre cero y cien, ya que por regla
general el estado de un proceso en curso se mide en tanto por ciento.

En lugar de asignar un valor directamente a la propiedad Position, con


el fin de incrementar la indicacin de estado del proceso, podemos
asignar inicialmente un valor de incremento a la propiedad Step, de
tal forma que una simple llamada al mtodo StepItQ realizar el
incremento de forma automtica.
13.3.1. En la prctica
Un simple ejemplo nos servir para conocer mejor el funcionamiento de
este
nuevo
control.
La
finalidad
de
este
programa
ser
ir
incrementando un estado de proceso que durar un determinado nmero de
segundos, que nosotros mismos determinaremos de antemano.
El formulario del programa es el que se muestra en la figura 13.3. En
ella hemos insertado un control TLabel con un TEdit, para solicitar el
nmero de segundos que ha de durar el proceso; un control TButton, que
ser el que pondr en marcha el proceso; un TProgressBar, como es
lgico, ya que es ste el control que deseamos probar, y un componente
TTimer, que nos servir para controlar el tiempo.

Figura 13.3. Aspecto del formulario con el control TProgressBar


Asigne el valor True a la propiedad Default del TButton, de tal forma
que baste con pulsar la tecla <Intro> para activarlo, sin necesidad de
abandonar el control TEdit, que ser el que tome el foco de entrada
inicialmente. D el valor False a la propiedad Enabled del componente
TTimer, ya que inicialmente el proceso no estar en marcha. Por ltimo
asigne el valor 1 a la propiedad Step del TProgressBar, indicando que
el incremento que se realizar al llamar a Steplt() ser de una
unidad.
Al pulsar el botn tendremos que asignar a la propiedad Max del
TProgressBar el valor que se haya introducido en el TEdit, fijando as
el valor mximo del proceso, que se iniciar en el momento en que
demos el valor True a la propiedad Enabled del TTimer. Tambin
desactivaremos el botn, con el fin de que no sea posible pulsarlo
hasta en tanto el proceso no haya finalizado. El cdigo del mtodo
asociado al evento OnClick del botn ser el siguiente.

{ Al pulsar el TButton }
procedure TForm1.Button1Click(Sender: TObject);
begin
// Fijamos el valor mximo
ProgressBar1.Max := StrToInt(Edit1.Text);
// Activamos el TTimer y desactivamos el TButton
Timer1.Enabled := True;
Button1.Enabled := False;
end;
Para evitar que se puedan introducir valores no numricos, lo cual
causara un error de conversin al utilizar la funcin StrTolnt(),
controlaremos cada pulsacin de tecla que se produzca en el TEdit,
aprovechando para ello el evento OnKeyPress. En el mtodo asociado a
este evento comprobaremos si el carcter pulsado es un dgito
numrico, ignorndolo en caso contrario.
{ Con cada pulsacin en el TEdit }
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
// Ignorar cualquier pulsacin que no sea un dgito numrico o
// la tecla de borrado
If Not (Key In ['0'..'9', #8]) Then
Key := #0;
end;
Una vez que el proceso est puesto en marcha, cada vez
que el TTimer genere un evento deberemos incrementar el indicador de
estado del proceso, para lo cual bastar una llamada al mtodo
StepIt(). A continuacin comprobaremos si hemos llegado al final del
proceso, caso ste en el que desactivaremos el TTimer, activaremos de
nuevo el TButton y daremos el valor cero a la propiedad Position del
TProgressBar, como puede ver en el cdigo siguiente.
{ Con cada evento del TTimer }
procedure Tform1.Timer1Timer(Sender: TObject);
begin
With ProgressBar1 Do
Begin
StepIt; // Incrementamos el proceso
If Position = Max Then // Si ya se ha completado
Begin
Position := 0; // Ponemos a cero la posicin
// Desactivamos el TTimer y reactivamos el TButton
Timer1.Enabled := False;
Button1.Enabled := True;
End;
End;
end;

Al ejecutar el programa deber introducir un valor indicando el nmero


de segundos de duracin del proceso y pulsar el botn para ponerlo en
marcha. Inicialmente pruebe con un valor pequeo y observe cmo a
medida que van pasando los segundos se va completando la franja de
color del TProgressBar, tal y como puede ver en la figura 13.4.

Figura 13.4. Aspecto del programa en funcionamiento

13.4. Incrementar y decrementar valores


Seguramente habr visto en algn programa Windows controles TEdit con
unas flechas adjuntas, que permiten incrementar o decrementar el valor
que contiene dicho control. En realidad estas flechas, accesibles
mediante el control TUpDown, pueden asociarse tambin a otros
controles y no slo a un TEdit.
Un control TUpDown es como una pareja de dos Tbutton que directamente
incrementan o decrementan un valor, que puede representarse en un
control adjunto. El citado valor se encontrar en un determinado
margen que definiremos mediante las propiedades Min y Max, como en
otros casos que acabamos de ver. La posicin actual se almacenar en
la propiedad Position del propio control TUpDown, aunque tambin puede
quedar reflejada en el control adjunto, cuyo nombre habremos de
asignar a la propiedad Associate.
13.4.1. Otras propiedades de TUpDown
El control TUpDown puede colocarse a la izquierda o derecha del
control asociado, segn el valor que asignemos a la propiedad
AlignButton, que ser udLeft o udRight. Si lo deseamos, el control
TUpDown puede interceptar las pulsaciones de tecla recibidas por el
control adjunto, de tal forma que al usarse las teclas del cursor se
incremente o decremente adecuadamente el valor.
Aunque la orientacin ms habitual y tomada por defecto de este
control es vertical, de tal forma que una flecha aparece hacia arriba
y otra hacia abajo, podemos tambin modificar este aspecto mediante la

propiedad Orientation. El valor por defecto es udVertical, existiendo


tambin la posibilidad de orientar el control horizontalmente,
asignando a esa propiedad el valor udHorizontal.
Cuando al incrementar o decrementar el valor que representa el control
TUpDown se llega a uno de los lmites, el inferior o el superior, no
es posible seguir avanzando a no ser que demos el valor True a la
propiedad Wrap. En este caso, al llegar a un lmite se saltar
automticamente al opuesto, es decir, si estamos en el valor mnimo y
pulsamos el botn de decrementar, el valor que se tomar ser el
mximo.
13.4.2. En la prctica
El funcionamiento del control TUpDown es extremadamente simple y tan
slo ha de insertarlo en el formulario y asociarlo con algn otro
control, como puede ser un TEdit o un TButton, para poder comprobar su
funcionamiento en la prctica.

13.5. Cabeceras redimensionables


Algunas aplicaciones visualizan listas de datos con unas cabeceras que
permiten que el usuario establezca el ancho de cada columna,
adaptndolo a sus preferencias o necesidades. La cabecera propiamente
dicha, que contiene los ttulos y los lmites de cada columna, es en
realidad un control, que en Delphi recibe el nombre de THeaderControl.
Un control THeaderControl es una coleccin de objetos THeaderSection,
cada uno de los cuales mantiene la informacin de una seccin de la
cabecera, como puede ser el ttulo o el ancho actual. Podemos acceder
a esta matriz de objetos a travs de la propiedad Sections del
THeaderControl. Aparte de esta propiedad, prcticamente no existe
ninguna otra que no conozcamos, pudiendo configurarse el color, la
alineacin, etctera.
13.5.1. Propiedades de un objeto THeaderSection
Como se acaba de decir, cada una de las secciones existentes en un
THeaderControl es un objeto THeaderSection, que puede ser definido
tanto en fase de diseo como durante la ejecucin. Al igual que otros
objetos, ste dispone de sus propiedades y mtodos que nos servirn,
por ejemplo, para establecer el ttulo de la seccin, su ancho,
alineacin, etc.
El ttulo que se muestra en una seccin de la cabecera se almacena en
la propiedad Text del objeto TheaderSection correspondiente. De igual
forma, la alineacin de dicho ttulo se define mediante la propiedad
Alignment, el ancho de la seccin con la propiedad Width y su anchura
mnima con la propiedad MinWidth. Esta ltima propiedad tiene por
defecto el valor cero, lo que significa que en ejecucin el usuario
puede reducir la seccin hasta hacerla desaparecer.

Desde el cdigo de nuestro programa tan slo podemos hacer referencia


a los objetos THeaderSection existentes a travs de la propiedad
Sections. Podemos aadir nuevas secciones mediante el mtodo Add(), de
igual forma que utilizamos ese mismo mtodo para aadir lneas a la
propiedad Lines de un control TMemo, por ejemplo.
13.5.2. Edicin de la propiedad Sections
Durante el diseo, para modificar el valor de la propiedad Sections
tendremos que utilizar una ventana especfica, que haremos aparecer
haciendo doble clic sobre dicha propiedad en el Inspector de objetos.
En esta ventana, cuyo aspecto puede ver en la figura 13.5, disponemos
de dos botones que nos permiten aadir y eliminar secciones. A su
derecha otros dos botones permiten cambiar la posicin de la seccin
elegida. Por cada una de las secciones existentes, cuyos ttulos se
muestran en una lista, podemos definir el propio ttulo, el ancho
actual, mnimo y mximo y la alineacin.

Figura 13.5. El editor especfico para la propiedad Sections


Durante la ejecucin del programa, desde el cdigo escrito por
nosotros, podemos tanto acceder a las secciones existentes como crear
otras nuevas. En el fragmento siguiente puede ver cmo se aade una
nueva seccin y se fija su ttulo.
With HeaderControl1.Sections.Add Do
Text := 'Nueva seccin';
13.5.3. Eventos de THeaderControl
Las secciones de una cabecera pueden ser redimensionadas, adems de
pulsadas como si de botones se tratase. Cada vez que se modifica el
tamao de una seccin se genera un evento OnSectionResize, que
nosotros podemos aprovechar para adecuar la informacin que se est
mostrando, ajustndola segn el nuevo ancho de la columna.
En caso de que la propiedad AllowClick del objeto THeaderSection
correspondiente a una seccin tenga el valor True, indicando que la
seccin puede ser pulsada como si fuese un botn, al producirse dicha
pulsacin el control genera un evento OnSectionClick.

13.5.4. En la prctica
Con el fin de ver en la prctica cmo podemos usar un control
THeaderControl en nuestros programas, vamos a desarrollar un ejemplo
en el cual usaremos la superficie del formulario como rea de trabajo,
listando en ella el contenido de la tabla de alumnos que utilizbamos
en los ejemplos de los dos captulos anteriores.
Definiremos una cabecera con tres secciones, en las cuales mostraremos
el Nombre, sexo y provincia de cada alumno. Estas tres secciones se
podrn redimensionar durante la ejecucin, permitiendo que el usuario
adecu su anchura segn desee.
Puesto que vamos a usar el formulario como si de un papel se tratase,
imprimiendo datos en su superficie, vamos a cambiar el color de fondo
haciendo que ste sea blanco. Por tanto, deber asignar el valor
clWhite a la propiedad Color.
Inserte en el formulario un componente TTable, asignando los valores
adecuados a las propiedades DatabaseName y TableName para poder
acceder a la tabla de alumnos. D tambin el valor True a la propiedad
Active. Puesto que no vamos a usar ningn control de base de datos, no
necesitaremos insertar un componente TDataSource. Con el fin de poder
acceder directamente a los objetos TField que representan a cada
campo, haga doble clic sobre el TTable, para abrir el Editor de
campos, pulse la combinacin <Control+A> y aada todos los campos a la
lista.
Tan slo existir un componente ms en el formulario, un control
THeaderControl. Edite la propiedad Sections definiendo las tres
secciones citadas antes, de tal forma que el formulario quede
aproximadamente como se muestra en la figura 13.6.

Figura 13.6. Aspecto del formulario con el THeaderControl

Para mostrar los datos en el formulario no vamos a usar control


alguno, sino que los dibujaremos directamente en la superficie, a la
cual accederemos mediante la propiedad Canvas. El proceso de dibujo,
por tanto, deber llevarse a cabo en el mtodo correspondiente al
evento OnPaint, que es generado por el formulario cada vez que es
necesario dibujar su contenido. Por consiguiente, ser en ese mtodo
en el que recorramos el contenido de la tabla de alumnos, leyendo
todos sus registros y mostrando el nombre, sexo y provincia
almacenados en cada uno de ellos. La longitud de cada uno de estos
datos deber adecuarse al ancho de la seccin correspondiente, por lo
cual antes de imprimir la cadena, mediante el mtodo TextOut(), ser
necesario comprobar si sta excede del ancho de la seccin. Para
realizar esta comprobacin nos serviremos del mtodo TextWidth(), que
nos devuelve el ancho en puntos de la cadena que pasemos como
parmetro. En caso de que ese ancho sea superior al ancho de la
seccin, reduciremos la longitud de la cadena en un caracter,
utilizando para ello el procedimiento SetLength(). Este proceso se
repetir hasta que la cadena sea lo suficientemente corta, momento en
el cual se imprimir. El cdigo completo de este mtodo es el que se
muestra seguidamente.
{ Cada vez que sea necesario dibujar el contenido del formulario }
procedure TForm1.FormPaint(Sender: TObject);
Var
X, Y: Integer;
Cadena: String;
begin
// Tomamos la coordenada Y inicial
Y := HeaderControl1.Height;
{ Asumimos la referencia al componente TTable }
With Table1 Do
Begin
First; // Nos movemos hasta el primer registro
Repeat // Inicio del bucle
X:=0; // Cada registro comienza en la coordenada X cero
// Tomamos el nombre del alumno
Cadena := Table1Nombre.Value;
{ Y ajustamos su longitus hasta que no exceda del ancho
de la seccin }
While Canvas.TextWidth(Cadena) >
HeaderControl1.Sections[0].Width Do
SetLength(Cadena, Length(Cadena)-1);
// Imprimindolo a continuacin
Canvas.TextOut(X, Y, Cadena);
// Incrementamos la coordenada X
Inc(X, HeaderControl1.Sections[0].Width);
{ Repetimos el mismo proceso, pero en este caso con el
sexo del alumno }
Cadena := Table1Sexo.value;
While Canvas.TextWidth(Cadena) >
HeaderControl1.Sections[1].Width Do

SetLength(Cadena, Length(Cadena)-1);
Canvas.TextOut(X, Y, Cadena);
Inc(X, HeaderControl1.Sections[1].Width);
{ volvemos a repetir, en este caso con la provincia }
Cadena := Table1Provincia.Value;
While Canvas.TextWidth(Cadena) >
HeaderControl1.Sections[2].Width Do
SetLength(Cadena, Length(Cadena)-1);
Canvas.TextOut(X, Y, Cadena);
Next; // Pasamos al registro siguiente
// e incrementamos la coordenada vertical
Inc(Y, Canvas.TextHeight(Cadena));
Until EOF; // Repetir hasta mostrar todos los registros
End;
end;
Cada vez que modifiquemos durante la ejecucin el ancho de una de las
secciones o bien las dimensiones del formulario, el contenido de sta
deber ser dibujado de nuevo. Para forzar esta accin realizaremos una
llamada al mtodo Invalidate() del formulario siempre que se produzcan
los evento OnResize y OnSectionResize, como puede ver a continuacin.
{ Al modificar el ancho de una seccin )
procedure TForm1.HeaderControl1SectionResize (HeaderControl:
THeaderControl;Section: THeaderSection);
begin
Invalidate; // Invalidamos el contenido del formulario
end;
{ Al modificar l tamao del formulario }
procedure Tform1.Form1Resize(Sender: TObject);
begin
Invalidate; // Tambin invalidamos su contenido
end;
Al ejecutar el programa los datos se mostrarn con el ancho prefijado
en la fase de diseo, pero bastar con que tome uno de los extremos de
cada seccin para poder ampliarla o reducirla. En la figura 13.7 puede
ver el aspecto que muestra el programa tras algunos ajustes durante la
ejecucin.

Figura 13.7. El programa en ejecucin

13.6. Barras de estado


Uno de los componentes ms habituales en los programas Windows es la
lnea de estado, un rea en la parte inferior de la ventana principal,
normalmente diferenciada con otro color, en la que se muestran
mensajes indicativos, estados diversos e informaciones como la hora.
Nosotros tambin podemos aadir a nuestro programa lneas de estado
con este estilo, gracias al control TStatusBar.
Este control es similar al que hemos conocido en el punto anterior, en
el sentido de que tambin cuenta con una coleccin de objetos, en este
caso de tipo TStatusPanel, cada uno de los
cuales representa una
seccin o panel de la lnea de estado.
Podemos acceder a esta matriz mediante la propiedad Panels, una
propiedad que cuenta con un mtodo Add() que facilita la creacin de
paneles durante la ejecucin del programa.
13.6.1. El objeto TStatusPanel
Cada uno de los paneles de una lnea de estado se corresponde con un
objeto TStatusPanel que cuenta con las propiedades necesarias para
poder establecer el estilo del panel, sus elementos de realce, el
texto que se muestra, etc.
El estilo de un panel queda determinado por el valor de la propiedad
Style del objeto TStatusPanel correspondiente, que puede contener el
valor psText, en cuyo caso el panel contiene un texto, o bien el valor
psOwnerDraw, caso ste en que el panel genera un evento cuando es

necesario dibujar su contenido, debiendo nosotros escribir el cdigo


preciso para hacerlo.
En caso de que el panel vaya a contener un texto, ste se asignar a
la propiedad Text y se alinear segn el valor asignado a la propiedad
Alignment.
Mediante la propiedad Bevel del
aadir un elemento de realce al
resaltado o hundido en la lnea de
cualquiera de los valores mostrados
Constante
pbNone
pbLowered
pbRaised

tipo TStatusPanel podemos tambin


panel, haciendo que ste aparezca
estado. Esta propiedad podr tomar
en la tabla 13.3.

Aspecto del panel en la lnea de estado


Normal.
Hundido.
Resaltado.

Tabla 13.3. Valores posibles para la propiedad Bevel


13.6.2. Otras propiedades de TStatusBar
En caso de que deseemos utilizar la lnea de estado como una simple
lnea para mostrar una cadena de texto, sin tener que preocupamos de
paneles, su definicin y posterior gestin, no tenemos ms que dar el
valor True a la propiedad SimplePanel, que por defecto es False. De
esta forma en la lnea de estado no existirn paneles, y tan slo se
mostrar el texto que asignemos a la propiedad SimpleText.
Si la lnea de estado se inserta en la parte inferior de una ventana
que puede ser redimensionada, podemos hacer que la esquina inferior
derecha del TStatusBar muestre un control indicativo de que es posible
modificar el tamao de la ventana. Para ello habremos de dar el valor
True a la propiedad SizeGrip.
13.6.3. Eventos de TStatusBar
Adems de los acostumbrados eventos de ratn, arrastrar y soltar y
pulsacin, este control cuenta con dos eventos adicionales. El evento
OnResize se produce cada vez que el tamao de la lnea de estado
cambia, lo que ocurre cuando se modifican las dimensiones de la
ventana, ya que la lnea de estado suele ajustarse siempre a la parte
inferior.
El segundo evento existente es OnDrawPanel, que se produce cuando en
necesario dibujar el contenido de un panel de la lnea de estado. Este
evento tan slo nos ser til si adems de un texto deseamos incluir
en un panel algn elemento ms, como puede ser un icono indicativo.

13.6.4. Edicin de la propiedad Panels


Al igual que ocurra con el control THeaderControl, la propiedad
Paneis del control TStatusBar cuenta con un editor especfico,
mediante el cual es posible definir los diferentes paneles de la lnea
de estado, a los cuales podemos acceder posteriormente, durante la
ejecucin, con el fin de asignar el texto a mostrar en cada momento.
Pulsando sobre la propiedad Panels accederemos a una ventana, como la
que se muestra en la figura 13.8, que cuenta con dos botones, que nos
permiten definir nuevos paneles y eliminar alguno de los existentes.
En la lista se muestra el texto de cada panel, mientras que en el
Inspector de objetos es posible establecer su estilo, anchura, texto y
alineacin.

Figura 13.8. El editor especfico para la propiedad Panels


Durante la ejecucin accederemos a la propiedad Panel como si de una
matriz se tratase, haciendo referencia a un objeto TStatusPanel
individual con el fin de modificar alguna de sus propiedades. En la
sentencia siguiente puede ver cmo se cambia el texto mostrado en el
primer panel de la lnea de estado.
StatusBar1.Panels[0].Text := 'SOB';
13.6.5. En la prctica
Realmente el trabajo con este control se lleva a cabo, casi en su
totalidad, en la fase de diseo, definiendo los paneles y fijando las
propiedades de cada uno de ellos. Durante la ejecucin bsicamente nos
limitaremos a alterar el contenido de la propiedad Text de cada panel,
reflejando el estado actual de la aplicacin.

13.7. Ventanas multipgina


Otro de los elementos que desde la aparicin de Windows 95 se utiliza
con ms frecuencia, ofrece la posibilidad de disponer de varias
pginas en una misma ventana, cambiando de una a otra mediante unos
marcadores o pestaas, que tienen un ttulo indicativo del contenido
de cada pgina. Cada una de las pginas no tiene por qu ser igual a

las otras, es decir, los controles existentes en ellas pueden ser


diferentes.
Para poder construir ventanas con mltiples pginas tendremos que usar
el control TPageControl. Este control es en realidad un contenedor en
el que podemos incluir uno o ms objetos TTabSheet, cada uno de los
cuales representa una pgina. Al insertar en el formulario un
TPageControl ste est vaco, no tiene pgina alguna.
Al igual que ocurre con los controles THeaderControl y TStatusBar, los
objetos que representan a cada seccin, panel o pgina en este caso,
estn accesibles mediante una matriz a la que tenemos acceso a travs
de la propiedad Pages. Sin embargo, y a diferencia de los dos
controles anteriores, esta propiedad tan slo est disponible en
ejecucin.
13.7.1. Gestin de las pginas en la etapa de diseo
Como se acaba de decir, al insertar en el formulario un TPageControl
ste no tienen ninguna pgina definida y, adems, no tenemos acceso
directo a la propiedad Pages, por lo que no existe ningn editor
especfico que nos asista en la tarea de definicin de las pginas.
Existen, sin embargo, unas opciones en el men emergente del control
TpageControl cuya finalidad es permitimos aadir nuevas pginas, as
como desplazamos por las ya existentes.
Si inserta en el formulario un TPageControl y a continuacin pulsa el
botn derecho del ratn sobre l, ver que la primera opcin del men
emergente es New Page. Si la selecciona, se aadir al control una
pgina, un objeto TTabSheet, proceso que puede repetir tantas veces
como pginas desee insertar.
Para hacer activa una u otra, bastar con pulsar sobre la pestaa
adecuada, aunque tambin podemos utilizar las opciones Next Page y
Previous Page del men emergente. La propiedad ActivePage del
TPageControl almacena el nombre de la pgina activa, modificando el
valor de esta propiedad tambin podremos cambiar dicha pgina activa.
13.7.2. Propiedades de TPageControl
El control TPageControl cuenta con una serie de propiedades generales
que afectan a todas las pginas que haya definidas en cada momento. Ya
se ha mencionado la propiedad ActivePage, que almacena el nombre de la
pgina que est activa en cada momento y que podemos modificar tanto
en la fase de diseo como durante la ejecucin.
Por defecto, todas las pestaas correspondientes a las pginas que
haya definidas se muestran en una sola lnea, por lo que el ancho de
cada pestaa se ir adecuando al espacio disponible, segn la anchura
del propio TPageControl y el nmero de pestaas existentes. En caso de
que el espacio no sea suficiente para poder visualizar todas las

pestaas, en el extremo derecho aparecer una pequea barra


desplazamiento, que nos permitir ir movindonos de unas a otras.

de

Podemos, sin embargo, indicar al control que distribuya las pestaas


en varias lneas, simplemente dando el valor True a la propiedad
MultiLine. De esta forma todas las pestaas se mostrarn de forma
simultnea.
Las dimensiones de cada una de las pestaas por defecto se ajustan al
alto del tipo de letra y el ancho del ttulo, pero son dos factores
que tambin podemos modificar, aunque de forma conjunta, para todas
las pestaas de forma simultnea. El control TPageControl dispone de
dos propiedades, llamadas TabHeight y TabWidth, mediante las cuales es
posible establecer el alto y ancho, respectivamente, de todas las
pestaas.
13.7.3. Propiedades de TTabSheet
Aunque algunas caractersticas de las pginas, como son las
dimensiones de sus pestaas, se establecen de forma general mediante
propiedades del control TPageControl.
Otros aspectos, como el ttulo o el tipo de letra del texto en la
pestaa, son configurables mediante las propiedades de cada pgina
individual, representada por un objeto TTabSheet.
Adems de las propiedades Caption, Font, Color y otras que ya
conocemos, un objeto TTabSheet cuenta con una propiedad llamada
Pageindex, mediante la cual podemos saber el ndice de la pgina en la
matriz a la que hace referencia la propiedad Pages del TPageControl.
Podemos mostrar u ocultar pginas individuales gracias a la propiedad
TabVisible, que es como la propiedad Visible de cualquier control pero
aplicada al objeto TTabSheet. Por tanto, dando el valor False a esta
propiedad conseguiremos ocultar la pgina y dndole el valor True la
haremos visible.
13.7.4. Gestin de las pginas durante la ejecucin
Durante la ejecucin podemos saber cuntas pginas existen en el
TPageControl consultando el valor de la propiedad PageCount, dato que
nos servir para poder acceder a la matriz referenciada por la
propiedad Pages.
Contando con el ndice de una cierta pgina, podemos alterar su ttulo
modificando el contenido de la propiedad Caption, as como hacerla
visible o no mediante la propiedad TabVisible. En caso de que una
cierta pgina no est visible, el contenido de la propiedad Tabindex
ser -1, mientras que en otro caso contendr el ndice de la pgina en
el TPageControl.

Podemos avanzar a la siguiente pgina, o retroceder a la anterior, con


una simple llamada al mtodo SelectNextPage(), sin tener que
preocupamos de ndices ni nada parecido. Este mtodo toma un slo
parmetro, indicando si se desea avanzar, True, o retroceder, False.
13.7.5. En la prctica.
De forma similar a lo que ocurre con un control TStatusPanel, el
trabajo con este nuevo control se centra prcticamente en el diseo,
ya que una vez que han sido definidas las pginas e insertado en ellas
los componentes que correspondan, en ejecucin el usuario podr
cambiar de una pgina a otra sin que prcticamente nuestro programa
tenga que hacer nada adicional.

13.8. Almacenes de imgenes


TImageList es el nico componente no visual que existe en la pgina
Win32. Su finalidad es facilitar el almacenamiento de imgenes, como
pueden ser iconos, que posteriormente pueden utilizarse desde el
programa sin necesidad de tener que acceder a archivo alguno. El
verdadero uso de este componente, su aplicacin ms til, la
conoceremos en los puntos siguientes, cuando tratemos controles como
TTreeView y TListView.
Las imgenes que se van a almacenar en un TImageList han de tener
todas el mismo tamao, siendo las dimensiones por defecto de 16 por 16
puntos. En caso de que necesitemos disponer de imgenes en diferentes
tamaos, tendremos que usar varios controles TImageList.
13.8.1. Asignacin de imgenes durante el diseo
Al igual que otros componentes de los que hemos visto a lo largo de
este captulo, ste tambin cuenta con un editor especfico, que en
este caso haremos aparecer haciendo doble clic sobre el componente o
bien seleccionando la opcin ImageList Editor del men emergente.
La ventana de este editor especfico, cuyo aspecto puede observar en
la figura 13.9, cuenta con un botn Add, mediante el cual podemos
recuperar una imagen de un archivo en disco, almacenndola en el
TImageList. Esta imagen, que puede en realidad tener cualquier tamao,
puede ser cortada a las dimensiones fijadas por el componente, 16 por
16 como se dijo antes, puede ser redimensionada, reducindose o
amplindose, o bien puede aparecer centrada.
Mediante el botn Delete podemos eliminar la imagen que se encuentra
seleccionada en ese momento, que se muestra en la parte superior,
mientras que una pulsacin del botn Clear causar que el TImageList
quede vaco, eliminando todo su contenido.

13.8.2. Asignacin de imgenes mediante cdigo


Independientemente de que el componente TImageList se haya preparado
previamente con imgenes, durante el diseo, desde el cdigo de
nuestro programa podemos aadir en cualquier momento nuevas imgenes,
disponiendo para ello de una serie de mtodos.

Figura 13.9. El editor de imgenes del componente TImageList


Bsicamente podemos aadir dos tipos diferentes de imgenes al
componente: iconos y mapas de bits. Los primeros se diferencian de los
segundos por contar en realidad con dos imgenes, una que es el propio
icono y otra que acta como mscara, marcando las zonas que son
transparentes y las que son visibles.
Para aadir un icono deberemos previamente recuperarlo del archivo en
que se encuentra, para lo cual deberemos crear un objeto TIcon y usar
el mtodo LoadFromFile(), al que pasaremos como parmetro el nombre
del archivo, extensin incluida. A continuacin llamaremos al mtodo
AddIcon() del TImageList pasando como parmetro el objeto TIcon
creado.
Si la imagen a aadir se encuentra almacenada en un archivo BMP,
tendremos que crear un objeto TBitmap y utilizar el mtodo
LoadFromFile(), usando a continuacin el mtodo AddMasked() para
aadir la imagen al TImageList. Este mtodo adems de la referencia
alTBitmap, como primer parmetro, necesita tambin un color, mediante
el cual se establecer la parte transparente de la imagen, dato este
que no es posible obtener directamente como en el caso de los iconos.
En lugar de recuperar las imgenes de disco tambin podemos crear
objetos TBitmap dibujando directamente en ellos, mediante la propiedad
Canvas, aadiendo finalmente la imagen al TImageList. Esto nos
permitira generar las imgenes dinmicamente, durante la ejecucin,

en lugar de tener que guardarlas en la fase de diseo y recuperarlas


posteriormente.
13.8.3. Obtener imgenes de un TImageList
Obviamente, la utilidad de este componente sera nula si no fuese
posible recuperar las imgenes que almacena, bien dibujndolas
directamente en la superficie de un determinado control o simplemente
devolviendo una referencia a ellas.
Podemos saber el nmero de imgenes existentes en cada momento en el
TImageList mediante la propiedad Count. El ndice de la primera imagen
ser el cero, mientras que la del ltimo ser el valor devuelto por
Count menos uno.
Para recuperar una referencia a una imagen, bien en forma de icono o
de mapa de bits, usaremos los mtodos GetIcon() o GetBitmap(),
respectivamente, a los que pasaremos como primer parmetro el ndice
de la imagen a recuperar y como segundo una referencia a un TIcon o un
TBitmap, en los que se devolver la imagen.
Tambin podemos dibujar la imagen directamente, por ejemplo en la
superficie del formulario o en un control TImage, usando para ello el
mtodo Draw(). Este mtodo toma como primer parmetro una referencia
al objeto TCanvas en el que se va a dibujar, referencia que podremos
obtener de la propiedad Canvas de la que disponen muchos controles.
Los dos siguientes parmetros, de tipo entero, nos servirn para
indicar la posicin en que se ha de dibujar la imagen, cuyo ndice se
facilita en ltimo lugar.
13.8.4. En la prctica
Como se ha comentado anteriormente, el uso principal de este
componente es servir como contenedor de imgenes para los componentes
que vamos a conocer en los puntos siguientes. En la mayora de las
ocasiones las imgenes del componente TImageList se definen en la fase
de diseo, y al asociarse con un control TTreeView o TListView no es
necesario usar ninguno de los mtodos con que cuenta TImageList, ya
que son esos dos controles los que se encargan de obtener las imgenes
que necesitan, dibujndolas en el lugar apropiado.

13.9. Listas jerrquicas


Si ha trabajado con el Explorador de Windows ya conoce las bases del
funcionamiento del control TtreeView. Cada nodo del rbol en un
control TtreeView consiste de una etiqueta y un nmero opcional de
imgenes de mapa de bits. Cada nodo puede tener una lista de subnodos
asociados. Haciendo clic en un nodo, el usuario puede expandir o
contraer la lista asociada de subnodos.

13.9.1. Definir elementos en la fase de diseo


Al hacer clic en la propiedad items del TtreeView aparece un nuevo
formulario. En la parte derecha de el existen cuatro datos que hacen
referencia a cuatro propiedades del objeto TTreeNode correspondiente
al elemento de la lista seleccionado en cada momento. Mediante estas
cuatro propiedades podemos establecer el ttulo del elemento y
asociarle una serie de imgenes que podrn mostrarse de acuerdo a su
estado. Para crear un nuevo elemento simplemente hacemos clic en el
botn New Item y damos los datos. Luego para aadirle subelementos a
ese elemento, estando seleccionado, presionamos New SubItem. Los
campos Image Index, Selected Index y State Index de este formulario
hacen referencia a los indices de un componente TimageList que
contiene la lista de imgenes que queremos utilizar.
13.9.2. Definir elementos durante la ejecucin
Con el fin de permitir la insercin de nuevos elementos en la lista,
el objeto al que hace referencia la propiedad Items cuenta con varios
mtodos, entre los cuales los dos ms habituales son Add() y
AddChild(). El primero de ellos aade un nuevo elemento al mismo nivel
que otro dado de referencia, mientras que el segundo crea un nuevo
nivel debajo del elemento que se facilita como referencia. En ambos
casos se toman los mismos parmetros: la referencia al TTreeNode de
referencia y el ttulo a asignar al nuevo elemento. El valor devuelto
por estos mtodos es una referencia a un TTreeNode, que nos permite
acceder al elemento que se acaba de aadir con el fin de establecer
sus propiedades.
Para eliminar un determinado elemento de la lista lo nico que hemos
de hacer es llamar al mtodo Delete(), facilitando como nico
parmetro una referencia al elemento a borrar. En caso de que deseemos
dejar completamente vaca la lista bastar con realizar una llamada al
mtodo Clear().
13.9.3. Propiedades de TTreeView
Adems de las propiedades lgicas de un control como TTreeView, cuyo
funcionamiento general ya conocemos, este control cuenta, adems, con
algunas especficas que nos permiten, por ejemplo, modificar la forma
en que se visualizan los elementos en la lista, as como asociar uno o
ms componentes TImageList, con el fin de asociar imgenes a los
elementos.
Los diferentes elementos que conforman la lista tienen una
relacin
de padre-hijo, cuyo enlace puede ser resaltado mediante el uso de
lneas de conexin. Para hacer que estas lneas sean visibles, la
propiedad ShowLines deber tener el valor True.
Cada uno de los elementos de la lista puede ser hijo del anterior, a
la vez que padre de los siguientes. Para facilitar la visualizacin y

operacin del usuario en ejecucin, a la izquierda de los elementos


que son padres de otros es posible mostrar unos botones que, adems de
indicar si la rama se encuentra o no desplegada, servirn para abrir o
cerrar dicha rama. La existencia o no de estos botones viene
determinada por el valor de la propiedad ShowButtons. Podemos hacer
aparecer estos botones tambin en la raz del rbol, dando el valor
True a la propiedad ShowRoot.
Con el fin de reflejar an ms claramente la relacin padres/hijos
existente entre los elementos de una lista, es posible aplicar una
identacin, de tal forma que cada hijo se dibuje unos puntos ms a la
derecha que su padre. Este nmero de puntos lo podemos fijar, tanto en
la etapa de diseo como de ejecucin, asignndolo a la propiedad
Indent.
Como se coment anteriormente, cada uno de los elementos de un control
TTreeView puede estar precedido por una imagen, que ser obtenida de
un componente TImageList. Para asociar un componente con otro, el
primero dispone de las propiedades Images y StateImages, capaces de
contener una referencia a un TImageList cada una.
El componente TImageList al que hace referencia la propiedad Images
contendr las imgenes normales a usar con los elementos de la lista,
mientras que el referenciado por la propiedad StateImages almacenar
imgenes de estado, unas imgenes que pueden mostrarse adicionalmente
a la imagen normal.
Como podremos ver posteriormente en un ejemplo, el ttulo o texto que
contiene cada uno de los elementos puede ser modificado directamente
por el usuario del programa durante la ejecucin, lo que facilita
enormemente la tarea del programador ya que no tiene necesidad alguna
de escribir cdigo para ofrecer esta posibilidad. No obstante, en caso
de que no nos interese que el usuario pueda modificar el texto de los
elementos de la lista, lo nico que hemos de hacer es dar el valor
True a la propiedad ReadOnly.
13.9.4. Propiedades de TTreeNode
Las propiedades que acabamos de ver afectan al control TTreeView en su
conjunto, pero a veces necesitaremos hacer referencia a las
propiedades de un elemento individual, para lo cual usaremos el objeto
TTreeNode que representa a cada uno de ellos. Como se ha indicado
anteriormente, podemos acceder a estos objetos mediante la propiedad
Items, que cuenta con una propiedad Count, mediante la cual podemos
saber el nmero de elementos existentes, y unos mtodos que permiten
aadir y eliminar elementos de la lista.
Adems de la propiedad Text, mediante la cual podemos establecer el
texto mostrado en un elemento, un TtreeNode cuenta con otras
propiedades adicionales, de las cuales vamos a conocer algunas
seguidamente.

Cada elemento de la lista adems de contar con un ttulo, almacenado


en la propiedad Text, tambin puede tener asociado un dato, para lo
cual se usar la propiedad Data. Esta propiedad es de tipo Pointer,
permitiendo almacenar la direccin de cualquier bloque de datos que
necesitemos enlazar con el elemento.
En una lista normal, almacenada por ejemplo en un TListBox, los
elementos tienen un ndice que les identifica de forma nica. Los
elementos de un TTreeView cuentan con dos ndices, uno relativo a la
posicin que ocupan en su rama, cuyo valor se almacena en la propiedad
Index del TTreeNode, y otro que es absoluto, siendo nico en toda la
lista, que se almacena en la propiedad Absoluteindex.
Como se ha dicho antes, un elemento de la lista puede contener a su
vez otros elementos, actuando como padre. Podemos usar la propiedad
HasChildren de un TTreeNode para saber si ste tiene hijos, obteniendo
el nmero de hijos existentes de la propiedad Count, y accediendo a
ellos mediante la propiedad Items, que es a su vez una matriz de
objetos TTreeNode.
Tambin se coment anteriormente el hecho de que cada elemento de la
lista tena un nivel, segn el cual era hijo o padre de otros. Este
nivel se almacena en la propiedad Level, que ser cero para el nivel
ms alto, la raz, y se ir incrementando progresivamente para
elementos de ramas inferiores.
En el punto anterior hemos visto que el control TTreeView puede estar
asociado con dos componentes TImageList, que servirn para facilitar
imgenes a adjuntar a los elementos. Para determinar qu imagen
aparecer a la izquierda de cada elemento, el objeto TTreeNode cuenta
con las propiedades ImageIndex, SelectedIndex y StateIndex. Cada una
de ellas almacena el ndice de una imagen, que puede ser -1 en caso de
que no se desee utilizar. La propiedad ImageIndex hace referencia a la
imagen que se mostrar junto al elemento cuando ste se encuentre en
estado normal, mientras que SelectedIndex contendr el ndice de la
imagen a mostrar cuando el elemento est seleccionado. La tercera de
las propiedades, StateIndex, nos servir para adjuntar una imagen
adicional, que servir como indicacin de estado.
13.9.5. Mtodos de TTreeView
De igual forma que otros controles, cuando se pulsa sobre el rea de
un control TTreeView con el cursor del ratn se genera un evento
OnClick. Tambin dispone este control de los eventos de ratn y
teclado habituales en otros componentes. Cuando se detecta una
pulsacin de ratn en un cierto punto del control, podemos saber qu
es lo que hay en ese punto realizando una llamada al mtodo
GetHitTestInfoAt(), pasando como parmetros las coordenadas del citado
punto. Este mtodo devolver uno de los valores que se enumeran en la
tabla 13.4, indicando sobre qu elemento se ha pulsado. Si lo nico
que nos interesa es obtener una referencia al TTreeNode sobre el que

se ha pulsado, en lugar de GetHitTestInfoAt() podemos usar el mtodo


GetNodeAt(), al que pasando los dos mismos parmetros nos devolver
una referencia al elemento pulsado, o bien el valor N1 en caso de que
la pulsacin se haya efectuado en un punto en el que no exista
elemento alguno.
Constante
HtAbove
HtBelow
htToLeft
htToRight
htNoWhere
htOnItem
htOnButton
htOnIcon
htOnIndent
htOnLabel
htOnRight
htOnStateIcon

El punto sobre el que se ha pulsado est ...


Encima del rea que ocupa el control.
Debajo del rea que ocupa el control.
A la izquierda del rea que ocupa el control.
A la derecha del rea que ocupa el control.
Debajo del ltimo elemento existente en la lista.
En el ttulo o imagen de un elemento.
En el botn de un elemento.
En la imagen de un elemento.
En el espacio de identacin.
En el ttulo del elemento.
A la derecha de un elemento.
Sobre el icono de estado de un elemento.

Tabla 13.4. Valores que puede devolver el mtodo GetHitTestInfoAt


El contenido de un control TTreeView, el texto de sus elementos para
ser ms concretos, puede ser guardado en un archivo en disco y
posteriormente recuperado. Para ello disponemos de los habituales
mtodos SaveToFile() y LoadFromFile() que, como siempre, tomarn como
parmetro el nombre del archivo en el que se desea guardar o del que
se ha de recuperar la informacin del control.
Durante la ejecucin, el usuario puede cerrar y abrir las ramas de un
TTreeView pulsando sobre los elementos apropiados. Como veremos en un
momento,
nosotros
tambin
podemos
abrir
y
cerrar
ramas
programdamente, mediante los mtodos del objeto TTreeNode. El control
TTreeView
dispone
de
dos
mtodos,
llamados
FullExpand()
y
FullCollapse(), mediante los cuales podemos expandir totalmente el
contenido del control, expandiendo todas las ramas, o bien cerrarlo
dejando un slo elemento, el raz.

13.9.6. Mtodos de TTreeNode


Tambin el objeto TTreeNode cuenta con algunos mtodos tiles que nos
permitirn manipular de forma individual los elementos contenidos en
la lista, actuando complementariamente a las propiedades que conocimos
en un punto anterior.

En caso de que un cierto elemento tenga hijos, caso ste en que la


propiedad HasChildren ser True, podemos desplegar o cerrar la rama
mediante los mtodos Expand() y Collapse(), respectivamente. Ambos
mtodos toman un parmetro de tipo Boolean, mediante el cual
indicaremos si deseamos que se abran o cierren de forma recursiva
todas las ramas que puedan existir en niveles inferiores.
Anteriormente decamos que el texto de un elemento de la lista poda
ser editado directamente por el usuario, simplemente pulsando sobre
l, haciendo aparecer el cursor de edicin. Esto ocurre, por ejemplo,
en el Explorador de Windows cuando se renombra un archivo o
directorio. Nosotros tambin podemos iniciar la edicin de un
elemento, desde el cdigo de nuestro programa, realizando una simple
llamada al mtodo EditText(). La accin de edicin puede ser cancelada
en cualquier momento, con una llamada al mtodo CancelEdit().
La eliminacin de un elemento de la lista puede realizarse de
diferentes formas, y una de ellas consiste en utilizar el mtodo
Delete() del objeto TreeNode correspondiente. Si deseamos eliminar
slo los elementos hijo que tiene un determinado elemento, podemos
usar el mtodo DeleteChildren().
13.9.7. En la prctica
Vamos a ver en la prctica cmo podemos utilizar un control TTreeView,
mediante un ejemplo que nos permitir almacenar en un archivo ndices
de libros, conservando una cierta jerarqua en la que el primer nivel
estar ocupado por los ttulos de los libros, el segundo por los
nombres de cada captulo y el tercero por los ttulos de los
apartados. Para comenzar vamos a insertar en una fcha los componentes
que puede ver en la figura 13.11. La mayor parte del formulario est
ocupado por el control TTreeView, mientras que a la derecha podemos
ver seis TButton y un componente TImageList.

Figura 13.11. Aspecto del formulario a disear

A continuacin tendr que utilizar un editor de imgenes, Delphi


incorpora uno al que puede acceder mediante la opcin Image Editor del
men Tools, para crear cinco pequeos iconos, de 16 por 16 puntos, que
seguidamente recuperaremos en el componente TImageList, en el orden
que se muestra en la figura 13.12. Como puede ver, estos iconos
representan un libro cerrado en dos colores diferentes, como puede ser
rojo y amarillo, un libro abierto en esos dos mismos colores y una
pgina o documento. El color transparente de estas cinco imgenes ser
el blanco, ya que es ste el color que tienen como fondo.
Como puede ver, en el formulario no existe ningn componente TEdit o
similar, ya que la edicin de los ttulos de los elementos se
realizar directamente en el control TTreeView, lo que es mucho ms
intuitivo y simple para el usuario.

Figura 13.12. Carga de las imgenes en el componente TImageList


Creacin de un nuevo libro
Al pulsar el botn Nuevo libro tendremos que aadir un nuevo elemento
a la lista, que estar en el primer nivel, sin tener relacin alguna
de padre/hijo con el resto de los elementos de la lista. Por ello
pasaremos al mtodo Add() como primer parmetro el valor Mil, en lugar
de una referencia a un objeto TTreeNode, consiguiendo as que el nuevo
elemento se aada al nivel de raz al final de la lista.
Inicialmente asignaremos a este elemento un ttulo por defecto, pero
de inmediato invitaremos al usuario a que introduzca el verdadero
ttulo del libro, para lo cual realizamos una llamada al mtodo
EditText() del TTreeNode recin aadido. Tambin establecemos los
ndices correspondientes a las imgenes a usar junto al ttulo del
libro, que sern los del libro en color rojo.
Por ltimo, antes de dar por terminado el proceso, hacemos que el
nuevo elemento se convierta en el elemento actual de la lista, para lo

cual basta con asignar el nuevo TtreeNode a la propiedad Selected del


control TTreeView, como puede ver en el cdigo que se muestra a
continuacin.
{ Al pulsar el botn NuevoLibro }
procedure TForm1.NuevoLibroClick(Sender: TObject);
Var
NuevoNodo: TTreeNode;
begin
{ Aadimos un nuevo nodo al primer nivel }
NuevoNodo := Indices.Items.Add(Nil, 'Nuevo libro');
{ Establecemos las imgenes }
with NuevoNodo Do
Begin
ImageIndex := 0;
SelectedIndex := 0;
EditText; { y editamos el texto }
End;
{ Seleccionando el nuevo nodo como actual }
Indices.Selected := NuevoNodo;
End;
Insercin de un nuevo captulo
El proceso por el cual se aade un nuevo captulo es similar al que
acabamos de ver, aunque existen algunas diferencias. Lo primero que
hemos de tener en cuenta es que para aadir un captulo debe haber
seleccionado un libro en la lista, es decir, si la lista est vaca o
no hay un elemento seleccionado, no sabremos dnde hay que aadir el
captulo. Por ello lo primero que haremos ser comprobar el valor de
la propiedad Selected, de tal forma que si contiene Nil avisamos
mediante un mensaje al usuario, indicndole que debe seleccionar un
libro.
Suponiendo que hay un elemento seleccionado en la lista, ste no tiene
por qu ser necesariamente el ttulo del libro, ya que puede estar
seleccionado cualquier otro elemento, como puede ser un captulo o un
apartado, casos en los cuales la propiedad Selected no sera Nil.
Puesto que el captulo se ha de aadir como un hijo del elemento que
contiene el ttulo del libro, tendremos que obtener una referencia a
ese elemento. Para ello comenzamos por obtener el ndice absoluto del
elemento que hay seleccionado actualmente, recorriendo a continuacin
la lista en sentido inverso hasta encontrar un elemento cuyo nivel,
que se almacena en la propiedad Level, sea cero. En ese momento
estamos seguros de que hemos encontrado el ttulo del libro, cuya
referencia usamos a continuacin en la llamada al mtodo AddChild(),
tras lo cual establecemos los iconos, expandimos el libro al que se ha
aadido el captulo y entramos en el modo de edicin, con una llamada
a EditText(), a fin de que el usuario pueda directamente introducir el
nombre del captulo, sin ms.

{ Al pulsar el botn NuevoCapitulo }


procedure TForm1.NuevoCapituloClick(Sender: TObject);
Var
N: Integer;
NuevoNodo: TTreeNode;
begin
{ Si no hay un nodo seleccionado actualmente }
If Indices.Selected = Nil Then
{ no podemos saber a qu libro se desea aadir }
ShowMessage('Seleccione antes el libro al que desea
aadir el capitulo.')
Else
Begin
{ Obtenemos el ndice absoluto del nodo seleccionado }
N := Indices.Selected.AbsoluteIndex;
{ y vamos subiendo por el rbol hasta encontrar el nodo
correspondiente al libro }
While Indices.Items[N].Level <> 0 Do
Dec(N);
{ Aadimos un nuevo nodo estableciendo el titulo y sus
imgenes }
NuevoNodo := Indices.Items.AddChild(Indices.Items[N],
'Nuevo captulo');
NuevoNodo.ImageIndex := 2;
NuevoNodo.SelectedIndex := 2;
{Expandimos el nodo al que se acaba de aadir el captulo)
Indices.Items[N].Expand(False);
{ Seleccionamos el nuevo nodo como el actual }
Indices.Selected := NuevoNodo;
NuevoNodo.EditText; { y editamos el ttulo }
End;
end;
Insercin de un nuevo apartado
La insercin de un nuevo apartado en un captulo, se llevar a cabo de
forma similar a la descrita hace un momento, aunque en este caso
debemos tener en cuenta que debe haber seleccionado un captulo al que
aadir el apartado, ya que si el elemento que hay elegido en ese
momento es el ttulo de un libro, no ser posible saber a qu captulo
aadirlo. Tras esta comprobacin se obtiene una referencia al
captulo, recorriendo los elementos en sentido inverso tal y como
hemos hecho antes, y llamando seguidamente a AddChild() para aadir el
nuevo elemento.
{ Al pulsar el botn NuevoApartado }
procedure TForm1.NuevoApartadoClick(Sender: TObject);
Var
N: Integer;
NuevoNodo: TTreeNode;
begin

{ Si no hay un nodo seleccionado o si el actual es un libro,


no sabemos a qu captulo aadir }
If (Indices.Selected=Nil) Or (Indices.Selected.Level=0) Then
ShowMessage('Seleccione el captulo al que desea aadir el
apartado.')
Else
Begin
{ Obtenemos el ndice absoluto del nodo actual }
N := Indices.Selected.AbsoluteIndex;
{ y subimos por el rbol hasta encontrar el nodo
correspondiente al capitulo }
While Indices.Items[N].Level <> 1 Do
Dec(N);
{ Aadimos un nuevo nodo y establecemos su ttulo e
imgenes }
NuevoNodo := Indices.Items .AddChild(Indices.Items[N],
'Nuevo apartado');
NuevoNodo.ImageIndex := 4;
NuevoNodo.SelectedIndex := 4;
{ Expandimos el nodo al que se ha aadido }
Indices.Items[N].Expand(False);
NuevoNodo.EditText; { y editamos el ttulo }
End;
end;
Eliminacin de un elemento
A diferencia de la insercin, para eliminar un determinado elemento de
la lista no es necesario diferenciar entre si es un libro, un captulo
o un apartado. Tan slo basta con comprobar que hay un elemento
seleccionado,
mediante
la
propiedad
Selected,
realizando
a
continuacin una llamada al mtodo Delete(). En caso de que el
elemento borrado tuviese hijos, stos tambin sern eliminados.
{ Al pulsar el botn Eliminar }
procedure TForm1.EliminarClick(Sender: TObject);
begin
With Indices Do { Si hay un nodo seleccionado }
If Selected <> Nil Then
Items.Delete(Selected); { lo eliminamos }
end;
Guardar y recuperar la informacin
Como se dijo anteriormente, el mtodo SaveToFile() tan slo guarda en
disco el texto de los elementos, dentndolo adecuadamente para que al
recuperarlo, mediante LoadFromFile(), se pueda deducir fcilmente el
nivel de cada elemento y, por tanto, la relacin existente entre cada
uno de ellos. Sin embargo, en ese archivo no se almacena el contenido
de otras propiedades, como Imageindex o Selectedindex, por lo que al
recuperar la informacin del archivo en disco es necesario recorrer

todos los elementos, asignando el icono que


nivel, como puede ver en el cdigo siguiente.

corresponda

segn

el

{ Al pulsar el botn Guardar }


procedure TForm1.GuardarClick(Sender: TObject);
begin
{ Grabamos el contenido en un archivo }
Indices.SaveToFile('INDICES.DAT');
end;
{ Al pulsar el botn Recuperar }
procedure TForm1.RecuperarClick(Sender: TObject);
Var
N: Integer;
begin
With Indices Do
Begin
{ Cargamos el contenido del archivo }
LoadFromFile('NDICES.DAT');
{ y restablecemos las imgenes segn el nivel }
For N := 0 To Items.Count - 1 Do
Begin
Items[N].ImageIndex := Items[N].Level * 2;
Items[N].SelectedIndex := Items[N].Level * 2;
End;
End;
end;
Cierre y apertura de ramas
En el componente TImageList que insertamos en el formulario existan
cinco imgenes, de las cuales hasta ahora slo hemos usado tres. Las
imgenes que muestran los libros abiertos se usarn en el momento en
que una rama correspondiente a un libro o captulo sea abierta,
volvindose a la imagen original cuando se cierre.
Cada vez que se va a abrir una rama se genera un evento OnExpanding,
en el que se reciben como parmetros una referencia al elemento que se
va a abrir y una variable, de tipo Boolean, mediante la cual podemos
evitar la operacin, simplemente asignndole el valor False. De forma
anloga, cuando se va a cerrarla rama se genera un evento
OnCollapsing, que recibe los mismos parmetros mencionados.
Ser, por tanto, en los mtodos asociados a los eventos OnExpanding y
OnCollapsing donde modifiquemos el valor de las propiedades Imageindex
y SelectedIndex del elemento que se abre o se cierra, segn se muestra
a continuacin.
{ Al cerrar un nodo }
procedure TForm1.IndicesCollapsing(Sender: TObject;

Node: TTreeNode; Var AllowCollapse: Boolean);


begin
{ Restauramos las imgenes originales }
Node.ImageIndex := Node.Level * 2;
Node.SelectedIndex := Node.Level * 2;
end;
{ Al expandir un nodo }
procedure TForm1.IndicesExpanding(Sender: TObject;
Node: TTreeNode; var AllowExpansion: Boolean);
begin
{ Si no estamos en el ltimo nivel }
If Node.Level <> 2 Then
Begin
{ Usamos las imgenes de los libros abiertos }
Node.Imageindex := Node.Level * 2 + 1;
Node.SelectedIndex := Node.Level * 2 + 1;
End;
end;
Al ejecutar el programa la lista aparecer inicialmente vaca, y la
nica opcin factible ser la de aadir un nuevo libro. A continuacin
podr insertar captulos y apartados, construyendo jerarquas como la
que se muestra en la figura 13.13, correspondiente al programa que
acabamos de construir.

Figura 13.13. El programa en funcionamiento con el ndice de un libro

13.10. El control TListView


Este control facilita la visualizacin de datos de una forma distinta.
La mayor diferencia que existe entre TListView y TTreeView es que en
el primero los elementos de la lista no tienen ninguna relacin
jerrquica entre s, es decir, unos elementos no son hijos o padres de
otros, como s ocurre en el control que hemos conocido en el punto
anterior.
Por tanto, este control es apropiado para presentar listas de datos o
elementos independientes, cada uno de los cuales puede tener asociado
un icono y unos datos adicionales, que pueden estar o no visibles
dependiendo del modo de visualizacin que est seleccionado en un
momento determinado.
Al igual que ocurre con todas las listas, los elementos de un
TListView estn accesibles mediante una propiedad llamada Items, que
es en realidad una matriz, en este caso de objetos TListItem. Cada uno
de estos objetos mantiene los datos relativos a cada elemento, como es
su ttulo, datos asociados, icono que se adjunta al mostrarlo en el
control, etc.
13.10.1. Propiedades de TListView
Adems de la citada propiedad Items, el control TlistView cuenta con
unas cuantas propiedades ms, mediante las cuales podemos asociar a
este control uno o varios componentes TImageList, con las imgenes o
iconos a usar con los elementos, establecer el modo de visualizacin o
definir las columnas que existirn en el modo de detalle.
Las propiedades LargeImages, SmallImages y StateImages son las tres
del mismo tipo, pudiendo almacenar cada una de ellas una referencia a
un componente TImageList. La primera de ellas hace referencia a un

almacn con iconos grandes, la segunda a un conjunto de


pequeos y la tercera a unas imgenes adicionales de estado.

iconos

Este control es capaz de presentar los elementos que contiene de


cuatro formas diferentes, pudiendo seleccionar una u otra mediante la
propiedad ViewStyle. Esta propiedad puede tomar cualquiera de los
valores enumerados en la tabla 13.5, y en caso de modificarse el valor
en ejecucin, con una simple asignacin, la visualizacin de los datos
se actualizar de forma inmediata.
Constante

Modo de visualizacin

vsIcon
vsSmallIcon
vsList
vsReport

Con iconos grandes.


Con iconos pequeos.
En forma de lista.
Con detalles o en modo informe.

Tabla 13.5. Valores posibles para la propiedad ViewStyle


En el primer modo de visualizacin los elementos sern dispuestos en
la ventana junto con un icono, que ser tomado del TImageList al que
hace referencia la propiedad LargeImages. El segundo modo dispone los
elementos de igual forma, pero usando los iconos referenciados por
SmallImages. En el tercer modo los elementos aparecen en forma de
lista, de arriba a abajo y de izquierda a derecha, junto con el icono
pequeo a su izquierda. El modo vsReport, por ltimo, adems del
ttulo muestra unos datos adicionales, que se almacenan en una
propiedad de cada objeto TListItem.
Al igual que ocurre con el TTreeView, los ttulos asociados a los
elementos pueden ser editados por el usuario durante la ejecucin, a
no ser que demos el valor True a la propiedad ReadOnly.
13.10.2. Propiedades de TListItem
Cada uno de los elementos de un TListView cuenta con un ttulo, que se
almacena en la propiedad Caption; una referencia a un icono o imagen
normal, en la propiedad ImageIndex, y otra a una imagen de estado, en
la propiedad Stateindex.
Adems, cada objeto TListItem cuenta con una propiedad llamada
Subitems, que es un objeto TStrings en el que podemos almacenar una
serie de cadenas con datos adicionales asociados a cada uno de los
elementos.
Al igual que los elementos de un TTreeView, los de un TListView
tambin pueden tener asociados otros datos, cuya direccin se almacena
en forma de Pointer en la propiedad Data. Esto nos permite asociar
registros de informacin o incluso objetos a cada uno de los elementos
de la lista.

13.10.3. Mtodos de TListView


Uno de los mtodos ms tiles de TListView es el mtodo Arrange(), que
nos permite reorganizar los elementos mostrados en el control siempre
que el modo de visualizacin actual sea vsIcon o vsSmallIcon. Esta
reorganizacin es necesaria, sobre todo, cuando se han aadido o
eliminado elementos durante la ejecucin. El mtodo Arrange() toma
como parmetro una de las constantes que se muestran en la tabla 13.6,
indicando el orden en que se han de disponer los elementos.
Constante

Disposicin de los elementos

ArDefault
ArAlignBottom
ArAlignLeft
ArAlignRight
ArAlignTop

Segn el estilo de alineacin del control.


A lo largo del lmite inferior del control.
A lo largo del lmite izquierdo del control.
A lo largo del lmite derecho del control.
A lo largo del lmite superior del control.

Tabla 13.6. Posibles parmetros para el mtodo Arrange


El control TListView tambin cuenta con un mtodo GetItemAt(), que nos
permite obtener una referencia al elemento que se encuentra en una
determinada posicin, cuyas coordenadas pasamos como parmetro al
llamar al mtodo. Si el valor devuelto es Nill significar que en esa
posicin no hay elemento alguno.
13.10.4. Mtodos de TListItem
Aparte de los mtodos Add() y Delete(), mediante los cuales podemos
aadir o eliminar elementos de la lista, cada TListItem cuenta con un
mtodo EditCaption(), que activa la edicin del ttulo del elemento, y
un mtodo CancelEdit(), que cancela dicha operacin.
En cualquier momento podemos hacer visible un determinado elemento de
la lista, realizando una llamada al mtodo MakeVisible() del TListItem
correspondiente. Este mtodo toma como parmetro un valor de tipo
Boolean, mediante el cual indicaremos si es necesario mostrar
totalmente el elemento o si por el contrario es factible una
visualizacin parcial.
13.10.5. Definicin de columnas
Cuando el modo de visualizacin seleccionado en el control, mediante
la propiedad ViewStyle, es vsReport, los elementos son mostrados como
una lista dividida en columnas, que habremos de definir mediante la
propiedad Columns. Esta propiedad es una matriz de objetos TListColum,
cada uno de los cuales cuenta con las propiedades Caption, Alignment y
Width, mediante las que podemos establecer el ttulo, alineacin y
anchura de cada columna.

En la etapa de diseo podemos definir las columnas de un control


TListView haciendo doble clic sobre la propiedad Columns, lo que nos
permitir acceder al editor especfico que se muestra en la figura
13.14, en el cual disponemos de los botones necesarios para aadir y
eliminar columnas. En el Inspector de objetos podremos establecer
adems el ttulo, alineacin y ancho de cada una de ellas.

Figura 13.14. El editor especfico para la propiedad Columns


Durante la ejecucin del programa podemos tanto modificar las columnas
definidas en la fase de diseo, accediendo a ellas mediante la
propiedad Columns, como aadir nuevas columnas y eliminar otras
existentes, ya que disponemos de los habituales mtodos Add() y
Delete().
Generalmente ser necesario definir tantas columnas como datos se
hayan aadido a la propiedad SubItems de cada TListItem ms una, en la
cual
se
mostrar
el
ttulo
del
elemento.
Las
columnas
son
redimensionables en tiempo de ejecucin, por lo que el usuario puede
adecuarlas a sus preferencias.
13.10.6. En la prctica
Veamos en la prctica cmo podemos utilizar un control TListView para
permitir la visualizacin de unos datos de diferentes formas, en este
caso para mostrar los registros de la tabla de alumnos, la cual
usaremos por ltima vez en este ejemplo.
Inserte en un formulario un control TListView, un componente
TImageList, un TTable y un TPopupMenu. Asigne a la propiedad Align del
TListView el valor alClient, de tal forma que l aspecto del
formulario quedar inicialmente como se muestra en la figura 13.15,
con el TListView ocupando todo el fondo del formulario. Los otros tres
componentes no son visuales, por lo que no importa su disposicin.
Recupere en el componente TImageList una de las imgenes que
representaban un libro cerrado de las usadas anteriormente, y asigne a
las propiedades Largelmages y Smalllmages del TListView el nombre del
mismo TImageList. Por tanto, vamos a utilizar una misma imagen para la
visualizacin en los dos modos de iconos, grandes y pequeos. En la

prctica se crearan dos componentes TImageList, uno con las imgenes


pequeas y otro con las grandes.

Figura 13.15. Aspecto del formulario con el control TlistView


A continuacin haga doble clic sobre la propiedad Columns del
TListView, para hacer aparecer el editor de columnas, y defina las
cuatro columnas que se mostraron anteriormente en la figura 13.14.
Seleccione en la opcin de anchura el elemento tem Width,
consiguiendo as que el ancho de cada columna se ajuste inicialmente
al necesario para mostrar el dato ms largo.
Tomemos ahora el componente TTable, asignando a las propiedades
DatabaseName y TableName los valores necesarios para poder acceder a
la tabla de libros y dando el valor True a la propiedad Active. A
continuacin abra el editor de campos, haciendo doble clic sobre el
componente, y aada todos los campos disponibles.
Por ltimo, para finalizar el diseo de la interfaz, haga doble clic
sobre el componente TPopupMenu, con el fin de abrir el diseador de
mens, y componga una lista de opciones como la que se muestra en la
figura 13.16. Estas opciones nos permitirn, durante la ejecucin,
alternar entre los diferentes modos de visualizacin posibles. Asocie
este men al control TListView, desplegando la lista adjunta a la
propiedad PopupMenu de este control y seleccionando el nico valor
disponible.
Ahora tendremos que escribir el cdigo necesario para conseguir que
nuestro programa funcione, comenzando por recuperar los datos de la
tabla de alumnos y definir los elementos correspondientes en el
control TListView. El ttulo de cada uno de los elementos ser el

nombre del
edad, sern
esta forma
cada uno de

alumno, mientras que los dems datos, sexo, provincia y


almacenados en la propiedad SubItems de cada TListItem. De
tendremos tantos elementos como alumnos existan, teniendo
ellos asociada informacin adicional.

Figura 13.16. Opciones del men emergente


El proceso de lectura de los datos y creacin de los elementos lo
vamos a llevar a cabo al crear el formulario, en el mtodo asociado al
evento OnCreate. Como puede ver en el cdigo siguiente, lo nico que
hacemos es leer la tabla hasta el final, creando un nuevo elemento por
cada registro.
{ Al crear el formulario }
procedure TForm1.FormCreate(Sender: TObject);
begin
With Table1 Do // Accedemos a la tabla
While Not EOF Do // mientras no lleguemos al final
// Aadimos un nuevo elemento a la lista
With ListView1.Items.Add Do
Begin
{ Asignando el titulo y los datos adicionales en
SubItems }
Caption := Table1Nombre.value;
SubItems.Add(Table1Sexo.Value);
SubItems.Add(Table1Provincia.Value);
SubItems.Add(Table1Edad.AsString);
Next; // Pasamos al registro siguiente
End;
end;
A continuacin tendremos que escribir el cdigo correspondiente al
evento OnClick de cada una de las opciones del men emergente, que
sern las que nos permitan cambiar de un modo de visualizacin a otro.
Desde el editor de mens haga doble clic sobre cada opcin, y escriba
las sentencias que se muestran a continuacin, que como puede ver se
limitan a la asignacin del valor adecuado a la propiedad ViewStyle.
{ Segn la opcin que se seleccione en el men emergente,
activamos un modo de visualizacin u otro }

procedure TForm1.Iconograndes1ClicktSender: TObject);


begin
ListView1.ViewStyle := vsIcon;
end;
procedure TForm1.Iconospequeos1ClicktSender: TObject);
begin
ListView1.ViewStyle := vsSmallIcon;
end;
procedure TForm1.Lista1Click(Sender: TObject);
begin
ListView1.ViewStyle := vsList;
end;
procedure TForm1.Detalles1Click(Sender: TObject);
begin
ListView1.ViewStyle := vsReport;
end;
Ya puede ejecutar el programa, en el que inicialmente se mostrarn
slo los nombres de los alumnos con el icono adjunto. Pulse el botn
derecho del ratn y seleccione otro modo de visualizacin, para poder
comparar las diferencias existentes entre unos y otros. En la figura
13.17 puede ver el modo de visualizacin vsReport en el que, adems
del icono y el nombre, se muestran tambin los datos adicionales
almacenados en la propiedad SubItems de cada TListItem, de acorde con
las columnas definidas en la propiedad Columns.

Figura 13.17. Aspecto del programa con la lista de elementos

13.11. Texto con formato


El control TRichEdit es seguramente uno de los ms tiles, ya que
permite que el usuario introduzca en nuestros programas texto con

formato. Un control TRichEdit es como un control TMemo y dispone de


muchas de las propiedades que ya conocemos de aquel control contando,
adems, con una serie de propiedades mediante las cuales es posible
definir los atributos del texto y de los prrafos. El texto con
formato manipulado en un TRichEdit puede ser posteriormente guardado y
recuperado en archivos con formato RTF, que tambin pueden ser ledos
por otros editores, como Word para Windows.
13.11.1. Atributos por defecto y de seleccin
A medida que se introduce texto en un TRichEdit, ste va tomando unos
atributos por defecto cuyas caractersticas se establecen mediante la
propiedad DefAttributes. Esta propiedad hace referencia a un objeto
TTextAttributes, que cuenta con una serie de propiedades mediante las
cuales podemos elegir la familia de letra. Name; su tamao, Size o
Height; su color, Color; el estilo, Style, y si est o no protegido,
Protected.
Las primeras cinco propiedades ya las conocemos, porque son iguales
que las disponibles en los objetos TFont. La propiedad Protected es de
tipo Boolean, indicando si el texto est o no protegido. Un texto
protegido es de slo lectura, por lo que no puede modificarse ni
borrarse.
Modificando
el
valor
de
la
propiedad
DefAttributes
estaremos
modificando los atributos del texto que se va a escribir a
continuacin, pero no los del texto que ya hay escrito. Estos
atributos estn accesibles mediante la propiedad SelAttributes que, al
igual que la anterior, es un objeto TTextAttributes, por lo que cuenta
con las mismas propiedades comentadas antes.
Gracias a la propiedad SelAttributes podemos obtener los atributos de
un texto que haya seleccionado en el control TRichEdit, as como
modificar alguno de sus apartados.
13.11.2. Atributos de prrafo
Adems de los atributos propios del texto, que acaban de comentarse,
un TRichEdit tambin es capaz de mantener unos atributos adicionales
asociados a cada prrafo de texto. Estos atributos permiten, por
ejemplo, establecer una sangra o una alineacin diferente para cada
prrafo.
La propiedad Paragraph de un TRichEdit es un objeto de tipo
TParaAttributes, objeto que cuenta con las propiedades siguientes:
Alignment: Nos permite establecer la alineacin del prrafo, cuyas
lneas pueden estar ajustadas a la izquierda, derecha o centradas.
FirstIndent: Identacin en puntos de la primera lnea de un prrafo.

LeftIndent: Identacin general del prrafo, expresada tambin en


puntos desde el margen izquierdo del control.
Numbering: Esta propiedad puede tomar los valores nsNone o nsBullet.
En este segundo caso el prrafo ir precedido de un bolo o marca de
inicio de prrafo.

Tab: Matriz de enteros mediante la cual es posible establecer la


posicin de cada uno de los puntos de parada de tabulacin. Existirn
tantos puntos como indique la propiedad TabCount.
13.11.3. Mtodos de TRichEdit
Las lneas de texto de un TRichEdit, al igual que las de un TMemo,
estn accesibles mediante la propiedad Unes, que como sabemos es un
objeto de tipo TStrings. Este objeto cuenta con los mtodos
SaveToFile() y LoadFromFile(), que nos permiten guardar y recuperar el
texto, incluyendo su formato.
El control TRichEdit tambin dispone de un mtodo Print(), que nos
permite imprimir el texto contenido en el control conservando todo su
formato. Al llamar a este mtodo lo nico que habremos de facilitar
ser un ttulo para el documento a imprimir.
13.11.4. En la prctica
Para ver en funcionamiento el control TRichEdit vamos a servimos de un
pequeo programa, que nos permitir introducir texto estableciendo
atributos de negrita y subrayada, adems de poder disponer bolos al
inicio de cada prrafo. Este programa es simplemente una demostracin
breve de las posibilidades de este control, que usted puede completar
permitiendo seleccionar el tipo y tamao de letra, ajuste de cada uno
de los prrafos, etc.
Comencemos insertando en un formulario un control TRichEdit y tres
controles TCheckBox, segn la disposicin que se muestra en la figura
13.18. Observe que en el ttulo de cada TCheckBox se ha dispuesto una
tecla de acceso rpido, de tal forma que podamos activar o desactivar
cada opcin sin necesidad de abandonar el control TRichEdit, con una
simple combinacin de la tecla <Alt> y la letra que aparece subrayada.
A continuacin tendremos que escribir el cdigo correspondiente a la
pulsacin de los tres TCheckBox, que bsicamente lo que har ser
comprobar si la opcin asociada est o no activa, mediante la
propiedad Checked, activando o desactivando en consecuencia el
atributo que proceda. Seguidamente puede ver el cdigo que tiene que
escribir para cada uno de los mtodos del evento OnClick de cada
TCheckBox.

Figura 13.18. Aspecto del formulario con el control TRichEdit


{ Al pulsar sobre el primer CheckBox }
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
With RichEdit1.SelAttributes Do
If CheckBox1.Checked Then // Si est marcado
// Activamos la negrita
Style := Style + [fsBold]
Else //en caso contrario la desactivamos
Style := Style - [fsBold];
// Devolvemos el foco al TRichEdit
RichEdit1.SetFocus;
end;
{ Al pulsar sobre el segundo CheckBox }
procedure TForm1.CheckBox2Click(Sender: TObject);
begin
With RichEdit1.SelAttributes Do
If CheckBox2.Checked Then // Si est marcado
// activamos la itlica
Style := Style + [fsitalic]
Else // si no la desactivamos
Style := Style - [fsitalic];
RichEdit1.SetFocus;
End;
{ Al pulsar el tercer CheckBox }
procedure TForm1.CheckBox3Click(Sender: TObject);
begin
With RichEdit1.Paragraph Do
If CheckBox3.Checked Then // Si est marcado
// activamos los bolos
Numbering := nsBullet
Else //en caso contrario los desactivamos
Numbering := nsNone;

RichEdit1.SetFocus;
end;
Al ejecutar el programa podr utilizar un atributo normal, con letra
negrita, con letra cursiva o con una combinacin de ambas. Observe que
la activacin o desactivacin de estos atributos slo afecta al texto
que se escriba a continuacin, o bien al que haya seleccionado en ese
momento.

Figura 13.19. Aspecto del programa en funcionamiento

13.12. Barras de botones


Hasta ahora, todas las opciones de los ejemplos propuestos en ste y
en captulos anteriores se han dispuesto, principalmente, en forma de
mens o bien usando controles TButton independientes. Cada vez es ms
habitual, sin embargo, el uso de barras de botones que permiten el
acceso a las mismas opciones son un simple movimiento de ratn. Un
ejemplo claro lo puede encontrar en las propias barras de botones de
Delphi.
Para crear una barra de botones hay que usar el componente TToolBar,
que encontraremos en la pgina Win32 a la derecha del control
TStatusBar. Al insertar una barra de botones en el formulario, podr
ver que automticamente se ajusta a la parte superior, ocupndola de
izquierda a derecha. Lo que en realidad se obtiene es un contenedor
con un borde en la parte superior, sin ningn botn en su interior.
13.12.1. Insercin de botones
Una vez tenemos el control TToolBar en el formulario, la siguiente
accin que desearemos llevar a cabo ser la insercin de los botones.
Para ello bastar con desplegar el men emergente, pulsando el botn
derecho del ratn sobre la barra de botones, y seleccionar la primera
opcin: New Button. De forma inmediata aparecer un botn cuadrado en
la parte izquierda de la barra de botones. Obviamente podemos insertar

tantos botones como necesitemos. Observe tambin que la segunda opcin


del mismo men, New Separator, permite insertar un espacio separador
entre dos botones consecutivos.
Cada uno de los botones contenidos en el control TtoolBar es un
componente TToolButton, que guarda muchas similitudes con el TButton
que ya conocemos. Por defecto, los TToolButton son botones simples que
pueden tener un ttulo y un icono y que al ser pulsados generan un
evento OnClick.
Para acceder durante la ejecucin a los botones de un control TToolBar
se usa la propiedad Buttons, que es una matriz de objetos TToolButton.
Es posible saber cuntos botones existen en la barra consultando el
valor de la propiedad ButtonCount.
13.12.2. Propiedades de TToolBar
Las propiedades del componente TToolBar establecen el funcionamiento
general de la barra de botones, que afecta a todos los botones
contenidos en ella. El comportamiento concreto de cada TToolButton se
fija con las propiedades particulares de ese objeto, que veremos en un
punto posterior.
Todos los botones de una barra de botones, a excepcin de los
separadores y divisores, tienen las mismas dimensiones. stas se
establecen con las propiedades ButtonHeight y ButtonWidth. Dichos
botones pueden estar demarcados con unos bordes que se fijarn de
forma independiente para cada margen con la propiedad EdgeBorders.
Inicialmente tan slo se muestra el bode superior.
Lo normal es que cada uno de los botones de la barra muestre una
pequea imagen en su interior, aunque de forma adicional tambin
pueden contar con un ttulo. Las propiedades Images, DisabledImages y
HotImages permiten asociar el control TToolBar con tres componentes
TImageList: una con las imgenes por defecto, otro con las imgenes a
usar cuando el botn est desactivado y otro conteniendo aquellas que
se usarn cuando el cursor del ratn pase sobre el botn.
Por defecto los ttulos de los botones no se muestran, dado que la
propiedad ShowCaptions del TToolBar es inicialmente False. Bastar con
dar el valor True a dicha propiedad para hacer que los ttulos
aparezcan.
Si queremos que la barra de botones tenga un aspecto plano, tan de
moda en las ltimas aplicaciones aparecidas, tan slo tenemos que dar
el valor True a la propiedad Flat. De esta forma los botones no
resaltarn en la barra hasta en tanto no se site el cursor del ratn
sobre ellos, momento en el que, adems, mostrarn la imagen del
TImageUst apuntado por la propiedad HotImages.

13.12.3. Propiedades de TToolButton


Un botn de este tipo puede actuar de cinco formas diferentes, segn
el valor que se asigne a la propiedad Style. Las posibilidades son:
tbsButton, tbsCheck, tbsDivider, tbsDropDown y tbsSeparator. El primer
tipo, que es el tomado por defecto, corresponde a un botn normal que,
al ser pulsado, genera un evento OnClick y vuelve a su estado
original. El estilo tbsCheck hace que el botn pueda estar en dos
estados: pulsado o no pulsado. Al hacer clic sobre un botn de este
tipo se dar el valor True a la propiedad Down, lo que provoca que el
botn quede visualmente hundido. Una nueva pulsacin devuelve el valor
False a la propiedad Down y el aspecto original al botn.
Los estilos tbsDivider y tbsSeparator son similares, ya que ambos
insertan un separador entre dos botones consecutivos, si bien el
primero hace que ese espacio aparezca como una barra vertical,
mientras que el segundo no incluye elemento visual alguno. Por ltimo
tenemos el estilo tbsDropDown, que hace que el botn tenga asociado un
men desplegable, al estilo de los botones Open o Run de Delphi.
Si usamos un botn con el estilo tbsDropDown, tendremos que asociar un
men con las opciones que se desplegarn. Este men ser un
TPopupMenu, que se asociar con el TToolButton mediante la propiedad
DropdownMenu de ste ltimo. Este tipo de botones tienen una opcin
por defecto, que es la que se ejecuta al pulsar el botn sin desplegar
el men. Para establecer dicha opcin se usa la propiedad MenuItem,
que cuenta con una lista en la que es posible elegir la opcin que
corresponda.
Para indicar qu imagen es la que hay que mostrar en el interior del
botn, tomndola de los componentes TImageList asociados al TToolBar,
se usa la propiedad ImageIndex, asignndole el ndice de la imagen que
corresponda.
13.12.4. Uso de una barra de botones
Prcticamente todo el trabajo de creacin de una barra de botones se
efecta en la fase de diseo, insertando los botones, asociando
imgenes, estableciendo el estilo de cada uno de ellos, etc. Una vez
que la barra de botones est creada, basta con hacer doble clic sobre
cada botn y escribir el cdigo que corresponda, igual que haramos
con una opcin de men o un control TButton cualquiera.
Por lo dems, el trabajo con una barra de botones no supone ninguna
complejidad adicional. Durante la ejecucin es posible eliminar
botones de los existentes, simplemente dando el valor False a la
propiedad Visible del componente TToolButton correspondiente. Tambin
podemos alterar otros elementos, como la imagen asociada, el ttulo,
etc., aunque no es lo habitual.

14. Reutilizacin del trabajo

14.1. Introduccin
En ocasiones, al disear las interfaces de una aplicacin y escribir
el cdigo asociado, se repiten algunas operaciones comunes en el
desarrollo. Los cuadros de dilogo suelen incluir algunos conjuntos de
botones comunes, ciertas acciones estn accesibles desde diferentes
puntos del programa, etc. Delphi 5 pone a nuestra disposicin diversos
mtodos para reutilizar el trabajo, evitando as la repeticin de
procesos con la consecuente prdida de tiempo en ellos.

14.2. Listas de acciones


Hasta ahora conocemos al menos dos elementos mediante los cuales el
usuario puede poner en marcha una determinada accin: las opciones de
un men y los botones. No es extrao que una misma opcin est
accesible mediante un botn existente en una barra de botones, una
opcin del men principal y, adems, otra opcin en un men emergente.
Es algo que podemos ver en el propio Delphi. Suponga que est creando
un programa que, entre otras, dispone de operaciones para copiar,
cortar y pegar informacin, operaciones que desea poner al alcance del
usuario mediante el tpico submen Edicin que existe en casi todas
las aplicaciones, una serie de botones existentes en un TToolBar y un
men emergente.
Suponiendo que cada opcin tenga asociado un ttulo, un corto mensaje
de ayuda, una pequea imagen asociada y una tecla de acceso rpido, se
ver forzado a establecer todas estas opciones para cada uno de los
botones del TToolBar, cada uno de los elementos del TMainMenu y los
elementos del TPopupMenu. Un trabajo no complejo pero realmente
repetitivo. Adems, los eventos OnClick generados por los botones y
las opciones del men debern unificarse, ya que la opcin a ejecutar
es la misma en todos los casos.
14.2.1. El componente TActionList
El ltimo componente de la pgina Standard, cuyo icono parece la unin
de un botn, un cursor de ratn y un men, es el que nos permitir
unificar y simplificar la programacin de las acciones que se han
expuesto en el punto anterior, de tal forma que nos ahorremos gran
parte del trabajo. Este componente cuenta con un editor especfico,
que haremos aparecer con un doble clic sobre el TActionList, mediante
el cual es posible definir las acciones disponibles en la aplicacin.
Cada una de estas acciones es un objeto TAction.
Como puede apreciarse en la figura 14.1, el editor dispone de los
tpicos botones que facilitan la creacin, eliminacin y disposicin
de los elementos. En la parte izquierda puede ver las propiedades del
TAction seleccionado en ese momento.

Las distintas acciones pueden agruparse en categoras, aunque en la


figura 14.20 no existe ninguna.
Adems de los botones y las teclas <Insert> y <Supr>, podemos usar las
distintas opciones del men emergente del componente TActionList para
manipular las acciones existentes o insertar otras nuevas.

Figura 14.1. Editor del componente TActionList


El componente TActionList dispone de una propiedad Images a la que
podemos asociar un componente TImageList, del que se extraern las
imgenes que necesiten las acciones.
14.2.2. Propiedades del objeto TAction
Como se ha apuntado hace un momento, cada una de las acciones se
representa mediante un objeto TAction que, como puede ver en la figura
14.1, cuenta con sus propiedades particulares. Bsicamente podemos
establecer el ttulo de la accin, con la propiedad Caption; el
mensaje de ayuda asociado, con la propiedad Hint; la tecla de acceso
rpido,
propiedad
ShortCut,
y
la
imagen
asociada,
propiedad
Imageindex.
Mediante las propiedades Enabled y Visible podemos hacer que la accin
est o no disponible o visible. La propiedad Checked permite mostrar
una marca junto al ttulo de la accin.
Tenga en cuenta que estas propiedades afectan a todos aquellos puntos
en que aparezca la accin. Si desactivamos una accin, dando el valor
False a la propiedad Enabled, estaremos desactivndola en el men
principal, men emergente, barra de botones y cualquier otro punto en
que la estemos usando.

Cuando una accin ha de ser ejecutada, porque se haya pulsado el botn


o seleccionado la opcin a la que est asociada, se generar un evento
OnExecute. En el mtodo correspondiente a este evento introduciremos
el cdigo de la accin, de forma nica, sin tener que compartir
mtodos entre eventos de botones, opciones de men y otros controles.
14.2.3. La propiedad Action
Disponen de esta propiedad componentes como TToolButton, TMenuItem o
TButton. Mediante ella podemos asociar una cierta accin con el
componente que nos interese, de tal forma que ste tome su ttulo,
mensaje de ayuda, icono asociado, etc., del objeto TAction que
corresponda. Adems, la actuacin del usuario sobre el componente
provocar el evento OnExecute citado hace un momento.
Al desplegar
ver aparecer
una de ellas
como Caption,

la lista de la propiedad Action de cualquier control,


las acciones disponibles en ese momento. Seleccionando
podr apreciar de inmediato los cambios en propiedades
Hint o ShortCut.

14.2.4. Uso de una lista de acciones


Veamos un ejemplo muy simple de uso de una lista de acciones,
basndonos en el ejemplo citado antes de una aplicacin que disponga
de las opciones de copiar, cortar y pegar. Comenzaremos insertando un
componente TImageList con las tres imgenes que van a representar las
opciones, tal y como puede ver en la figura 14.2. A continuacin
insertaremos el componente TActionList y crearemos las tres acciones
vistas en la figura 14.1, fijando el ttulo, mensaje de ayuda, tecla
de acceso rpido e ndice del icono asociado.

Figura 14.2. Componente TImageList con las imgenes

A continuacin inserte en el formulario un componente TMainMenu y haga


doble clic sobre l. Inserte una opcin, llamndola Edicin, que
actuar como submen. Las opciones de este men sern, como puede
apreciarse en la figura 14.3, las tres acciones disponibles. No hace
falta qu establezca propiedad alguna de las opciones, basta con que
despliegue la lista de la propiedad Action y elija la que corresponda,
sin ms.
Repita la operacin que acabamos de efectuar pero creando un men
emergente, insertando un control TPopupMenu, haciendo doble clic sobre
l y eligiendo directamente el valor adecuado para la propiedad Action
de cada opcin.

Figura 14.3. Men principal con las opciones de edicin


Por ltimo, inserte un componente TToolBar y use su
para insertar tres botones. Elija individualmente cada
despliegue la lista asociada a la propiedad Action,
accin que corresponda. D el valor True a la propiedad

men emergente
uno de ellos y
para elegir la
ShowHint.

Puesto que lo que nos interesa es ver cmo utilizar una lista de
acciones, no la finalidad en s de las propias acciones, haga doble
clic sobre cada elemento del TActionList insertando cualquier cdigo,
por ejemplo una llamada al mtodo ShowMessage() para indicar que se ha
seleccionado la opcin.
procedure TForm1.CopiarExecute(Sender: TObject);
begin
ShowMessage('Copiar');
end;
procedure TForm1.CortarExecute(Sender: TObject);
begin
ShowMessage('Cortar');
end;
procedure TForm1.PegarExecute(Sender: TObject);
begin
ShowMessage('Pegar');

end;
Llegados a este punto, ya puede ejecutar el programa y ver el
resultado. Observe que las opciones tanto del men principal como del
men emergente muestran a su izquierda los mismos iconos que hay en la
barra de botones. Los botones de la barra, por su parte, muestran como
mensaje de ayuda el ttulo de las opciones del men. Todas estas
opciones y botones comparten el mismo cdigo, ya que estn asociadas a
las mismas acciones.

Figura 14.4. El programa en funcionamiento

14.3. Componentes compuestos


Si un cierto formulario, que ya tenemos diseado, es necesario varias
veces, ya sea en la misma aplicacin o en otras diferentes, la forma
ms fcil de reutilizarlo consiste en aadirlo al Depsito de objetos.
Esto es tan fcil como pulsar el botn secundario del ratn sobre el
formulario, seleccionando a continuacin la opcin Add to Repository.
En la ventana que aparece, similar a la de la figura 14.5, podr
introducirse un ttulo y una descripcin del formulario, as como el
nombre del autor e, incluso, un icono que le identifique.

Figura 14.5. Ventana para aadir un formulario al Depsito de objetos


Esta posibilidad, ya existente en versiones previas de Delphi, no
soluciona, sin embargo, otro problema: reutilizar ciertos grupos o
conjuntos de componentes junto con su cdigo asociado. Con este fin,
en Delphi 5 se han aadido los frames o marcos.
Un marco es, en cierta forma, muy parecido a un formulario. Su
finalidad es servir como contenedor de componentes, alojando tambin
el cdigo asociado a los eventos de stos. Lo interesante, sin
embargo, es que el marco puede, posteriormente, ser usado como un
componente nico, insertndose en un formulario siempre que se
precise.
14.3.1. Creacin de un nuevo marco
Puede crear un nuevo marco eligiendo la opcin New Frame del men
File, o bien seleccionando la opcin New de ese mismo men, para abrir
el Depsito de objetos, escogiendo despus el objeto Frame. En
cualquier caso, ver aparecer un recuadro muy similar a un formulario.
Existen, no obstante, algunas diferencias notables. Observe que el
marco no dispone de propiedades como Caption o BorderIcons, propias de
un formulario.
En el interior del marco puede insertar otros componentes. En la
figura 14.6, por ejemplo, puede ver cmo se han insertado dos
etiquetas de texto y una lista combinada.

Figura 14.6. Un marco con algunos componentes en su interior


Si tras insertar los componentes deseados en el marco, asigna el valor
True a su propiedad AutoSize, podr ver cmo las dimensiones se
ajustan automticamente, de tal manera que el tamao del marco es
justo el preciso para contener los componentes alojados en l. Tambin
puede darse un valor a la propiedad Align, de tal forma que,
posteriormente, el marco se ajuste directamente a un margen de su
contenedor.
14.3.2. Reutilizar el marco en el mismo proyecto
Un marco no es til de por s, de igual manera que no lo es un botn
de forma aislada. Los marcos estn diseados para incluirse en un
contenedor, ya sea ste un formulario, un TGroupBox o incluso otro
marco.
En cualquier caso, para insertar un marco en su contenedor hay que
seleccionar el primer objeto, en el margen izquierdo, de la pgina
Standard de la Paleta de componentes. Al pulsar sobre el contenedor
con el botn principal del ratn, ver aparecer una ventana (vase la
figura 14.7) en la que podr elegir entre los marcos disponibles.

Figura 14.7. Ventana para seleccionar un marco del proyecto


Al seleccionar uno de los marcos, ste se insertar en su contenedor
como si de cualquier otro componente se tratase. En caso de que se
diese algn valor a la propiedad Align, el marco se ajustar
automticamente al margen que proceda.

Es posible incluir el mismo marco mltiples veces en un mismo


formulario o contenedor, de igual manera que puede insertar varios
botones.
14.3.3. Reutilizar el marco en otros proyectos
En caso de que un mismo marco pueda ser til en diferentes proyectos,
no slo en aquel donde se ha diseado, existe un mtodo ms simple
para facilitar su reutilizacin. Este consiste en aadir el marco a la
Paleta de componentes, como si de un componente ms se tratase. Cmo
hacer esto? Tan fcil como pulsar el botn secundario del ratn sobre
el marco y, a continuacin, elegir la primera opcin disponible: Add
To Palette. Tras aadir el marco, podr ver que en la Paleta de
componentes existe otra pgina. Esta, llamada Templales, contendr
todos los marcos que aadamos, como puede verse en la figura 14.8.
Ahora basta con seleccionar el marco e incluirlo en el formulario,
como si de cualquier otro control se tratase.

Figura 14.8. La Paleta de componentes tiene una pgina con los marcos
Tenga en cuenta que al reutilizar un marco no slo consigue incluir un
componente formado de otros, sino tambin todo el cdigo asociado que
haya podido escribir. Es decir, no se trata tan sol de componer una
plantilla de controles para despus insertarlos con mayor facilidad,
sino de reutilizar una funcionalidad completa.
14.3.4. Un ejemplo
Utilizar los marcos es algo bastante sencillo. Para comprobarlo,
inicie un nuevo proyecto y, a continuacin, cree un nuevo marco
insertando en l dos etiquetas de texto y una lista combinada, como se
mostr anteriormente. Asigne a la propiedad Items de la lista
combinada los nombres de los meses. Abra la pgina de eventos en el
Inspector de objetos y, teniendo seleccionada la lista combinada, haga
doble clic sobre el evento OnClick, introduciendo el cdigo siguiente:
procedure TfrmSeleccionMes.cbMesesClick(Sender: TObject);
Const
DiasMes: Array[0..11] of Smallint =
(31,28,31,30,31,30,31,31,30,31,30,31);
begin
LbDias.Caption:=IntToStr(DiasMes[cbMeses.ItemIndex])+' das';
end;

Como puede ver, partiendo de la seleccin del mes se obtiene el nmero


de das que ste tendr, sin tener en cuenta los aos bisiestos, y se
asigna a la etiqueta que hay en la parte inferior.
D el valor alTop a la propiedad Align del marco y el valor True a su
propiedad AutoSize. Por ltimo, abra el men contextual del marco y
adalo a la Paleta de componentes.
Ahora abra el formulario que haba inicialmente en el proyecto que, en
este momento, estar vaco. Inserte desde la Paleta de componentes el
marco recin creado, ver que de manera inmediata se sita en la parte
superior del formulario. Disponga ms abajo un control TPanel y, en su
interior, inserte otra copia del marco. Tambin aadiremos un botn,
de tal forma que la ventana quede como puede verse en la figura 14.9.
Al pulsar el botn se ejecutar el cdigo siguiente:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(SelectorMes.cbMeses.Text);
end;
El identificador SelectorMes es el nombre que hemos dado a uno de los
marcos aadidos al formulario. Observe que dicho identificador se
utiliza como un componente, de tal forma que mediante el operador . es
posible acceder a su contenido, en este caso la lista combinada
cbMeses.

Figura 14.9. El formulario con dos copias del mismo marco


Al ejecutar el programa podr seleccionar un mes de cualquiera de las
dos listas combinadas disponibles, viendo aparecer debajo el nmero de
das del mes elegido. Observe que el funcionamiento de los dos marcos
es independiente, estn creados a partir del mismo molde, pero son dos
componentes separados.

15. Creacin de componentes


15.1 Introduccin
Desde hace ya algn tiempo el hombre con el afn de facilitarse las
cosas ha construido usando componentes o pequeas partes que se
ensamblan para formar un todo. Esas partes son por lo general ms
maniobrables, ms entendibles, en una palabra, ms sencillas. La
creacin de software no ha escapado a la mxima Mantenlo bien simple
(Keep it so simple) y ha abordado los problemas de complejidad de la
misma manera. La posibilidad que brinda Delphi de crear nuevos
componentes es una de las ms interesantes. Con la creacin de
componentes los programadores pueden crear soluciones propias y
compartirlas con los dems enriqueciendo las posibilidades del
entorno. Un componente no es ms que un objeto descendiente de la
clase TComponent que es el ancestro comn a todos ellos e implementa
las caractersticas bsicas que le permiten ser mostrado en la paleta
de componentes e insertarse en los formularios en tiempo de diseo.
15.2. Niveles de acceso a los componentes
Delphi define cuatro niveles de acceso a los campos, mtodos y
propiedades de un componente que en definitiva no es ms con un objeto
descendiente de la clase Tcomponent.
Los nivelos son los siguientes:
Private: Las propiedades y los mtodos que se encierren bajo esta
clusula son nicamente accesibles desde la unit donde se encuentran
declarados ocultando tambin la implementacin a objetos que se
encuentren fuera de esta.
Protected: La clusula protected hace que las declaraciones en su
interior sean, al igual que en el caso de private inaccesibles desde
fuera de la unit. La nica diferencia entre ellas es que en este caso
los descendientes tendrn acceso.
Public: Todas las declaraciones en este caso sern accesibles desde
dentro o fuera de la unit. En este caso se define lo que se conoce
como interface del objeto, es decir la parte visible para el usuario.
Published: Hace lo que public y adems lo declarado en ella se muestra
en tiempo de diseo en el inspector de objetos. Por tanto debe usarse
published solo para las propiedades pues al usarla para mtodos solo
conseguiremos que estos sean pblicos.

15.3 Creando un componente.


Delphi nos da un pequeo asistente para ayudarnos a lograr la
estructura mnima de una Unit para la creacin de un nuevo componente.

Seleccione la opcin File del men y luego New.

Figura 15.1
Dentro de la formulario New Items elija Component y aparecer un nuevo
formulario en el que se mostrarn los siguientes campos:

Class Name: Aqu debemos especificar el nombre del nuevo


componente.

Ancestor type: Introduciremos aqu el ascendiente a partir del


cul derivaremos nuestro componente.

Palette Page: Indicaremos aqu la pgina de la paleta en la cul


queremos que aparezca el nuevo componente.

Al aceptar el contenido del formulario se generar automticamente la


unit correspondiente al componente as como la declaracin de la clase
de nuestro componente en cdigo similar al siguiente:
unit RealEdit;
interface
uses
Windows, Messages,
Dialogs,
StdCtrls;

SysUtils,

type
TRealEdit = class(TEdit)

Classes,

Graphics,

Controls,

Forms,

private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TRealEdit]);
end;
end.
Observe
que
delphi
incluye
automticamente
el
procedimiento
RegisterComponents que registrar el componente en el entorno
permitiendo su visualizacin en la paleta de componentes y su edicin
con el Object Inspector.
Una vez aqu podemos comenzar a aadir las propiedades y los mtodos
que formarn parte del nuevo componente o modificar comportamientos
heredados de la superclase.
En ocasiones nos preguntaremos cul ser un buen ancestro para nuestro
nuevo
componente
con
el
objetivo
de
sacar
mejor
partido
a
funcionalidades ya existentes. He aqu varias normas:

TComponent - El punto de partida para los componentes no


visuales.

TWinControl - El punto de partida si es necesario que el


componente disponga de handles.

TGraphicControl - Un buen punto de partida para componentes


visuales que no sea necesario que dispongan de handles, es decir,
que no reciban el foco. Esta clase dispone del mtodo Paint y de
Canvas.

TCustomControl - El punto de partida ms comn. Esta clase


dispone de window handle, eventos y propiedades comnes y,
principalmente, canvas con el mtodo Paint.

De lo anterior se puede inferir que la condicin de si nuestro


componente es visual o no lo define la clase usada como base. As si
heredamos de Tcomponent estaremos creando un componente no visual y

por otra parte si heredamos de TcustomControl por ejemplo estaremos


creando un componente visual.

15.4 Creando un componente visual.


La eleccin del nombre del nuevo componente que aparece en el cdigo
anterior a sido intencional pues en lo adelante ilustraremos un
ejemplo de implementacin de un componente para la validacin de la
entrada de un nmero real en un rango determinado. Para ello
aadiremos dos propiedades una MinVal que representa el valor mnimo y
MaxVal el mximo. Chequearemos que el usuario haya introducido un
nmero real y que este se encuentra en el rango permitido mostrando un
mensaje de error en caso contrario.
La definicin de la clase quedara de esta manera:
type
TRealEdit = class(TEdit)
protected
FMinVal: real;
FMaxVal: real;
procedure SetMinVal( AMinVal: real
procedure SetMaxVal( AMaxVal: real
procedure DoExit;
published
property MinVal: real read FMinVal
property MaxVal: real read FMaxVal
property OnExit;
end;

);
);
override;
write SetMinVal;
write SetMaxVal;

Al declarar las propiedades MinVal y MaxVal bajo la clusula published


aseguraremos que estas aparezcan en el inspector de objetos y de esa
manera el programador podr cambiar sus valores en el Object
Inspector. Es importante especificar para ellas los procedimientos y
funciones que bajo las clusulas read y write servirn para acceder a
los datos reales de las propiedades que se almacenan en FMinVal y
FmaxVal en este caso definimos los mtodos SetMinVal y SetMaxVal para
cuando se establecen los valores y en el caso de la lectura lo hacemos
directamente situando tan solo los nombres de los campos.
...
Implementation
procedure TRealEdit.SetMinVal( AMinVal: real );
begin
FMinVal := AMinVal;
end;
procedure TRealEdit.SetMaxVal( AMaxVal: real );
begin

FMaxVal := AMaxVal;
end;
procedure TRealEdit.DoExit;
var
Value: real;
Code: integer;
begin
Val( Text, Value, Code );
if (code = 0) and ( Value>=FMinVal ) and (Value<=FMaxVal)
then inherited DoExit
else
begin
application.messagebox('El
valor
del
campo
es
incorrecto',
'Error', MB_OK);
SetFocus;
end;
end;
procedure Register;
begin
RegisterComponents('Samples', [TRealEdit]);
end;
...
Lo interesante de la implementacin es la reimplementacin del
procedimiento DoExit. Por definicin el procedimiento DoExit heredado
se invoca cuando se produce un evento del tipo OnExit. Este ltimo se
produce siempre que un componente visual pierde el foco es decir deja
de estar activo. El nuevo DoExit de nuestro componente permite que una
vez que el mismo pierde el foco, se compruebe que se ha editado
realmente un nmero real y que este se encuentra en el rango entre el
valor de MinVal y MaxVal. De cumplirse la condicin anterior se
ejecuta el DoExit heredado causando un comportamiento normal, de lo
contrario se muestra un cuadro de mensaje indicando el error y se le
regresa el foco al componente en cuestin.

15.5 Creando un componente no visual.


Los componentes del tipo no visual realizan una funcin determinada
pero no son visibles en tiempo de ejecucin. Es posible sin embargo
insertarlos en una forma en tiempo de diseo y editar incluso sus
propiedades a travs del Object Inspector.
Como ejemplo en este caso implementaremos un componente cuya funcin
ser determinar el equivalente en grados celcius de un valor dado en
Farenheit.
La unit queda de esta manera:
unit FaC;

interface
uses
Classes;
type
TFaC = class(TComponent)
private
FFValue: real;
function GetValueInCelcius: real;
protected
public
property Celcius: real read GetValueInCelcius;
published
property Farenheit: real read FFValue write FFValue;
end;
procedure Register;
implementation
function TFaC.GetValueInCelcius: real;
begin
Result:=(5*(FFValue-32))/9;
end;
procedure register;
begin
registercomponents('Samples', [TFaC]);
end;
end.
Observe que en el ejemplo anterior hemos heredado de TComponent por
tratarse de un componente no visual.

15.6 Creando un bitmap para el componente.


Cada componente necesita un bitmap para representarlo en la paleta de
componentes. Si no se especifica uno, Delphi utilizar uno por
defecto.
El bitmap no se incluye en el cdigo fuente del componente, sino que
debe incluirse en un archivo aparte con la extensin .DCR (dynamic
component resource). Este fichero puede crearse con el propio editor
de imgenes que incorpora Delphi.
El nombre del archivo .DCR debe coincidir con el nombre con que se ha
salvado la unidad que contiene el componente. El nombre de la imagen
bitmap (que debe estar en maysculas) debe coincidir con el nombre del

componente. Los dos ficheros (el de la unidad *.pas y el de el bitmap


*.dcr) deben residir en el mismo directorio.
En nuestro componente visual, si hemos salvado la unidad con el nombre
realedit.pas nuestro archivo de recursos deber tener el nombre
realedit.dcr. Dentro de este archivo se encontrar el bitmap, al que
pondremos el nombre TRealEdit. El tamao del bitmap debe ser de 24x24
pixels.

15.7 Instalando componentes creados.


Instalar un componente en la paleta de componentes es muy sencillo.
Basta con seguir los siguientes pasos:

Elegir la opcin Options y luego Install Components del men de


Delphi.

Pulsar sobre el botn Add para seleccionar la unidad que contiene


el cdigo fuente del componente y luego hacer clic sobre OK.

Delphi compilar la unidad y reconstruir el archivo COMPLIB.DCL.


Si se encuentran errores al compilar, se nos informar de ello.
Basta con corregir el error, salvar la unidad y repetir el
proceso anterior.

Si la compilacin tiene xito, nuestro componente entrar a


formar parte de la paleta de componentes.

Nota: Es una buena idea antes de comenzar hacer una copia de seguridad
del archivo COMPLIB.DCL para evitar posibles problemas derivados de
fallos al compilar.

15.8 Introduccin a los editores de propiedades.


Hasta ahora nos hemos centrado en la creacin de componentes sin
preocuparnos de cmo se introducan los valores de las distintas
propiedades definidas en ellos. Ha llegado el momento de centrarnos en
este aspecto. Como todos sabemos para introducir y leer el valor de
las propiedades en tiempo de diseo utilizamos el inspector de
objetos. El inspector de objetos nos muestra en una primera columna el
nombre de la propiedad y en una segunda el valor de dicha propiedad.
Para introducir un nuevo valor lo tecleamos y listo. Pero esto es tan
slo apariencia. Los componentes interactan con el inspector de
objetos a travs de los editores de propiedades. Desde el punto de
vista del usuario, es el inspector de objetos el responsable de editar
las propiedades, pero detrs de la escena hay una serie de objetos,
los editores de propiedades, que se encargan de definir las
capacidades de edicin de las diversas propiedades de un componente.
En tiempo de diseo, cuando se selecciona un componente, el inspector
de objetos crea instancias de los editores de propiedades necesarios
para editar las propiedades definidas en el componente seleccionado.

Cuando termina la edicin, el mismo inspector de objetos destruye los


editores de propiedades creados.
Delphi incluye una serie de editores de propiedades por defecto que
son suficientes para la mayora de las propiedades con las que
trabajamos habitualmente. La potencia de Delphi permite que creemos
nuestros propios editores y que incluso reemplacemos los que una
determinada propiedad tiene por defecto.

15.9 Responsabilidades de un editor de propiedades.


Un editor de
principales:

propiedades

debe

dar

respuesta

dos

aspectos

Definir cmo debe ser editada la propiedad. Aqu hay dos


posibilidades: el valor de la propiedad puede ser modificado
sobre el propio inspector de objetos (bien sea introduciendo un
nuevo valor o seleccionndolo de una lista de valores), o se
puede utilizar un cuadro de dilogo para dotar de mayor
flexibilidad a la edicin (Por ejemplo la propiedad color)

Convertir el valor de la propiedad a un valor de tipo string. El


inspector de objetos siempre trabaja con strings. Aunque la
propiedad sea de tipo integer o float o sea un mtodo, el
inspector de objetos slo trata con representaciones de tipo
string de dichas propiedades. Es el editor de propiedades el que
debe suministrar al inspector de objetos de dicha representacin
un string de la propiedad. Esta "traduccin" puede ir desde lo
ms sencillo (utilizar la funcin IntToStr) hasta lo ms complejo
(programar una rutina para la traduccin). Todo depender del
tipo de propiedad con la que estemos tratando.

15.10 Pasos necesarios para escribir un editor de propiedades.


Los pasos que es necesario seguir
propiedades son los siguientes:

para

escribir

un

editor

de

Crear una nueva unit en la que definiremos el editor de


propiedades. Ms adelante hablaremos detalladamente sobre este
punto, ya que no es tan trivial como puede parecer en principio.

Aadir la unidad dsgnintf a la clusula uses del editor


propiedades. En esta unidad estn definidos los editores
propiedades por defecto que utiliza Delphi, adems de
importantsima clase TPropertyEditor, la cul es la clase base
todos los editores de propiedades.

Crear una nueva clase que descienda de TPropertyEditor o de


alguno de sus descendientes. Por convencin, el nombre de los
editores de propiedades finaliza con la palabra Property. Por

de
de
la
de

ejemplo TIntegerProperty, TStringProperty... A continuacin se


muestran los principales editores de propiedades por defecto que
incorpora Delphi.
Editor de
propiedades
TPropertyEditor
TIntegerProperty

Tipo
Clase base para todos los editores de
propiedades
Byte, word, integer, Longint

TCharProperty

Char

TEnumProperty

Tipos enumerados

TSetProperty
TFloatProperty
TStringProperty
TClassProperty
TMethodProperty
TComponentProperty

Sets
Single, Double, Extended, Comp, Currency
Strings
Cualquier objeto
Cualquier mtodo (eventos)
Para propiedades que hacen referencia a
componentes

Implementar los mtodos necesarios para dotar


propiedades con las funcionalidades deseadas.

Registrar el
Library(VCL)

editor

de

propiedades

en

la

al

Visual

editor

de

Component

Ms
adelante
profundizaremos
en
todos
aspectos
segn
vayamos
desarrollando distintos editores, pero ahora ha llegado del momento de
crear nuestro primer editor de propiedades.

15.11 Un editor de propiedades para nmeros binarios.


Vamos a desarrollar nuestro primer editor de propiedades, que ser
editable sobre el propio inspector de objetos. Para ello pongmonos en
la siguiente situacin: imaginemos que hemos creado un componente con
una propiedad de tipo integer que guarda un valor que debe
introducirse y visualizarse en base binaria y no en base decimal. Si
no creramos un editor de propiedades y dejramos que Delphi utilizase
el
editor
por
defecto
(TIntegerProperty
en
este
caso)
nos
encontraramos que tanto la introduccin como la visualizacin del
valor de la propiedad se realizara en base decimal, que no es lo que
queremos. Este es el tpico caso en el que desarrollando un simple
editor de propiedades ahorramos trabajo al futuro usuario de nuestro
componente, evitando que tenga que hacer la conversin entre decimal y
binario.
Como ya hemos comentado, tenemos que decidir de que clase vamos a
derivar nuestro editor. En nuestro caso es fcil, ya que la propiedad

almacenar un valor de tipo integer, as que de seguro te dars cuenta


que ha de ser TintegerProperty.
Muy bien, nuestra propiedad almacena un entero, pero no queremos que
el inspector de objetos nos muestre su valor decimal directamente,
queremos efectuar una conversin de dicho valor decimal a base binaria
y que slo entonces el inspector de objetos nos muestre el valor. Para
lograr esto debemos implementar (override) la funcin GetValue. Esta
funcin, definida en TPropertyEditor, es llamada por el inspector de
objetos para obtener la representacin del valor de la propiedad en
forma de string. Dentro de esta funcin debemos convertir el valor de
la propiedad de decimal a binario y, a continuacin, transformar este
valor en string, ya que como hemos mencionado el inspector de objetos
siempre muestra strings. De este modo la funcin GetValue queda as:
unit BinaryPropEd;
interface
uses DsgnIntf;
type
TBinIntegerProperty = class(TIntegerProperty)
public
function GetValue : string; override;
procedure SetValue(const Value : String); override;
end;
procedure Register;
implementation
Const
Bits16 : Array [1..16] of Integer =
(32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1);
function TBinIntegerProperty.GetValue : string;
Var
Num, i : integer;
begin
Num:=GetOrdValue;
Result := '0000000000000000';
for i := 1 to 16 Do
if ( Num >= Bits16[i] ) Then
begin
Num := Num - Bits16[i];
Result[i] := '1';
end;
if ( Num > 0 ) Then
raise EPropertyError.Create('Error converting
'+IntToStr(GetOrdValue) + ' to binary');

Insert('B',Result,1);
end;
...
end.
De la implementacin de esta funcin la parte ms importante es la
primera lnea:
Num:=GetOrdValue
Necesitamos obtener el valor que tiene en ese momento la propiedad
para trabajar sobre l. Para ello utilizamos el mtodo GetOrdValue,
definido de nuevo en TPropertyEditor, el cul se encarga de devolver
el valor de la propiedad en forma de ordinal (integer). De forma
anloga,
existen
los
mtodos
GetFloatValue,
GetMethodValue,
GetVarValue,
etc.
para
utilizar
con
el
tipo
de
propiedad
correspondiente.
Una vez almacenado el valor de la propiedad en la variable Num,
comienza la conversin del valor de decimal a binario, la cul es
fcil de entender. Es bueno notar que el nmero mximo de digitos
binarios soportados es 16, margen ms que suficiente para la mayora
de aplicaciones. Por ltimo tenemos que devolver un valor de tipo
string como resultado de la funcin. Para ello vamos almacenando en la
variable Result el string a devolver. Para finalizar, anteponemos la
letra 'B' a la cadena para indicar que se trata de base binaria. Y eso
es todo en lo que a esta funcin respecta. De este modo, cuando el
inspector de objetos deba mostrar el valor de la propiedad, llamar a
el mtodo GetValue el cul le devolver el string correspondiente.
Pero nos queda la otra mitad: estara bien que pudiramos introducir
el valor de la propiedad tanto en decimal como en binario segn nos
interesase pues vamos a ello.
Para conseguir esta funcionalidad debemos implementar (override) el
mtodo SetValue, definido de nuevo en la clase TPropertyEditor. Cuando
el usuario entra un nuevo valor usando el inspector de objetos, este
llama al mtodo SetValue, el cul debe efectuar la traduccin inversa
a la efectuada por el mtodo GetValue. Es decir, debe convertir el
string que contiene el nuevo valor de la propiedad al tipo de datos de
dicha propiedad. En nuestro caso, el string vendr en base decimal o
binaria (en este ltimo caso, la primera letra de la cadena ser una
'B') y habr que convertirlo a base decimal. Para ello implementaremos
el mtodo SetValue de la siguiente forma:
...
type
TBinIntegerProperty = class(TIntegerProperty)
public
function GetValue : string; override;
procedure SetValue(const Value : String); override;
end;

procedure Register;
implementation
...
procedure TBinIntegerProperty.SetValue(const Value : String);
Var
i, Total, Longitud : integer;
NumText : string;
begin
if UpperCase(Value[1])='B' then
begin
NumText:=Copy(Trim(Value),2,Length(Trim(Value))-1);
NumText:=Copy('0000000000000000',1,16-Length(NumText)) + NumText;
Total:=0;
for i:=1 to Length(NumText) do
begin
if not (NumText[i] in ['0','1']) then
raise EPropertyError.Create(NumText[i] + ' is not a valid
binary digit')
else if NumText[i]='1' then
Total:=Total+Bits16[i];
end;
SetOrdValue(Total);
end
else
SetOrdValue(StrToInt(Value));
end;
...
end.
En la implementacin de este mtodo primero comprobamos si el usuario
ha introducido el nuevo valor de la propiedad en base decimal o en
base binaria. En el primer caso, tan slo hay que convertir el string
a integer mediante la funcin StrToInt(Value) y, a continuacin,
utilizar
el
mtodo
SetOrdValue
para
almacenar
el
valor
correspondiente. De forma anloga, segn el tipo de la propiedad,
existen los mtodos SetFloatValue, etc.
En el caso de que la primera letra de la cadena sea una 'B', se
convierte la cadena con el valor binario a base decimal y se vuelve a
utilizar el mtodo SetOrdValue para almacenar el valor en la
propiedad.
Una vez implementados estos dos mtodos (GetValue y SetValue) ya
tenemos nuestro editor de propiedades terminado; tan slo nos queda un
pequeo, pero indispensable paso, registrarlo en la VCL.

15.12 Registro de un editor de propiedades.


De igual manera que debemos registrar en la VCL los componentes, con
los editores de propiedades debemos hacer lo mismo. Para ello

disponemos del mtodo RegisterPropertyEditor (definido en la unidad


DsgnIntf) que tiene la siguiente declaracin:
procedure RegisterPropertyEditor(PropertyType:PTypeInfo;
ComponentClass : TClass; const PropertyName : string; EditorClass :
TPropertyEditorClass);
PropertyType hace referencia al tipo de la propiedad al que se
aplicar el editor de propiedades. Para suministrar un valor a este
parmetro normalmente utilizaremos la funcin TypeInfo, por ejemplo,
TypeInfo(integer).
ComponentClass permite restringir el uso del editor de propiedades a
la clase especfica. Un valor de NIL registra el editor para todos los
componentes.
PropertyName especifica el nombre de la propiedad. Un valor distinto
de NIL registra el editor slo para la propiedad especificada,
mientras que un valor '' lo registra para todas las propiedades
EditorClass especifica el editor de propiedades que se registra (la
clase).
Jugando con estos parmetros, tenemos a nuestra disposicin un amplio
abanico de posibilidades para registrar nuestro editor de propiedades.
Vemos algunos ejemplos con nuestro recin creado editor:
RegisterPropertyEditor(TypeInfo(integer), NIL, '', TBinIntegerProperty)
Registra el editor de propiedades para todos los componentes que
tengan una propiedad de tipo entero. Est es la forma ms global de
registrar un componente y afecta a todos los componentes registrados
en la VCL. Si registramos nuestro editor as, veremos que todas las
propiedades de tipo integer nos aperecen en binario! Adems podemos
introducir un nuevo valor en decimal o en binario (anteponiendo la
letra B). Estamos sustituyendo el editor de propiedades que Delphi
utiliza para enteros por el nuestro! :) Esta es la forma ms global
de registrar un editor de propiedades.
RegisterPropertyEditor(TypeInfo(integer),TMiComponente,
'PropiedadBinaria',TBinIntegerProperty)
Registra el editor slo y exclusivamente para la propiedad
'PropiedadBinaria' del componente 'TMiComponente'. Esta es la forma
ms restringida de registrar un editor de propiedades.
Un buen consejo sera registrar el editor de la forma ms global
posible para que experimentes con l.
Tambin se puede crear un componente de "mentirita" y registrar slo
el editor para el mismo. Algo as:
...

Type
TMiComponente = class(TComponent)
...
property PropiedadBinaria : integer read FPropBin write FPropBin;
...
end;
...

15.13 Ubicacin de un editor de propiedades.


Como ya mencionamos al mostrar los pasos que se deben seguir para
crear un editor de propiedades, el primero de ellos es crear una
unidad donde situar el editor. En ese momento dijimos que no era una
eleccin tan trivial como pudiera parecer en un principio. En que
unit debemos situar el editor? en la misma unit donde est el
componente que tiene la propiedad que ser editada?, en una unit
aparte? Tenemos tres posibles ubicaciones:

La primera opcin es situar el editor de propiedades en la misma


unidad en que reside el componente que tiene la propiedad que
utiliza el editor de propiedades. Esta es la opcin ms
intuitiva; sin embargo no es la ms recomendable, sobre todo si
el editor utiliza un cuadro de dilogo.
El motivo es que Delphi slo utiliza el editor de propiedades en
tiempo de diseo. De hecho, el form que contiene el cuadro de
dilogo no es enlazado con la aplicacin, ni tampoco la clase del
editor de propiedades. Sin embargo, si se enlazan los recursos
asociados al cuadro de dilogo, recursos que en tiempo de
ejecucin lo nico que hacen es ocupar espacio, ya que no se
utilizarn para nada. Por tanto, estamos incrementando el tamao
del ejecutable a lo tonto :( Por otra parte, si el editor de
propiedades no utiliza cuadros de dilogo, el efecto no es tan
pernicioso pero sigue sin ser recomendable.

La segunda opcin es situar el editor de propiedades (si utiliza


un formulario cmo cuadro de dilogo) en la misma unidad del
cuadro de dilogo. De este modo, la aplicacin que usa el
componente no enlaza el editor de propiedades ni sus recursos
asociados.

La tercera opcin es situar el editor de propiedades en una


unidad de registro. Una unidad de registro es una unidad normal y
corriente
que
agrupa
varias
sentencias
de
registro
correspondientes
a
distintos
componentes
y
editores
de
propiedades que residen en distintas unidades. Esta es la opcin
ms recomendable si el editor de propiedades es utilizado por
varios componentes.

Por tanto, las dos ltimas opciones son las ms recomendables


dependiendo la eleccin de una u otra del uso que se vaya a dar al
editor de propiedades. De todas formas, no olvides aadir a la

clusula
editor.

uses

las

unidades

correspondientes

segn

donde

sites

el

unit BinaryPropEd;
interface
uses DsgnIntf;
type
TBinIntegerProperty = class(TIntegerProperty)
public
function GetValue : string; override;
procedure SetValue(const Value : String); override;
end;
procedure Register;
implementation
Const
Bits16 : Array [1..16] of Integer =
(32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1);
function TBinIntegerProperty.GetValue : string;
Var
Num, i : integer;
begin
Num:=GetOrdValue;
Result := '0000000000000000';
for i := 1 to 16 Do
if ( Num >= Bits16[i] ) Then
begin
Num := Num - Bits16[i];
Result[i] := '1';
end;
if ( Num > 0 ) Then
raise EPropertyError.Create('Error converting
'+IntToStr(GetOrdValue) + ' to binary');
Insert('B',Result,1);
end;
procedure TBinIntegerProperty.SetValue(const Value : String);
Var
i, Total, Longitud : integer;
NumText : string;
begin
if UpperCase(Value[1])='B' then
begin
NumText:=Copy(Trim(Value),2,Length(Trim(Value))-1);
NumText:=Copy('0000000000000000',1,16-Length(NumText)) + NumText;
Total:=0;

for i:=1 to Length(NumText) do


begin
if not (NumText[i] in ['0','1']) then
raise EPropertyError.Create(NumText[i] + ' is not a valid
binary digit')
else if NumText[i]='1' then
Total:=Total+Bits16[i];
end;
SetOrdValue(Total);
end
else
SetOrdValue(StrToInt(Value));
end;
procedure Register;
begin
RegisterPropertyEditor(TypeInfo(Integer),nil,'',TBinIntegerProperty);
end;
end.
Direcciones de inters en Internet
Existen en Internet numerosas pginas en las que podremos encontrar
informacin de Delphi.
Basta con teclear Delphi en el campo de
bsqueda de cualquier navegador y aparecern un buen nmero de
pginas. Aveces sin embargo es difcil distinguir aquello que es
importante de lo que no lo es, por ello te brindamos un listado con
algunas direcciones de Internet que tratan sobre Delphi.
Club Delphi
http://www.clubdelphi.com
Sin lugar a dudas, el centro ms importante de Delphi en Espaol. En
esta sitio encontrar interesantes artculos, cursos, componentes, una
extensa seccin de enlaces, ofertas de trabajo, un apartado de
respuestas a preguntas frecuentes, etc. El Club Delphi cuenta, aparte
de con esta web, con sus propios foros de discusin, a los que podr
suscribirse desde la direccin indicada ms arriba.

Comunidad Borland
http://community.borland.com
Adems de la informacin sobre Delphi que puede encontrarse en
http://www.borland.com, Borland cuenta con una sitio especfico para
desarrolladores. En el podr encontrar una comunidad centrada en
Delphi, con artculos de los especialistas ms conocidos, noticias y
todo tipo de recursos tiles.

Você também pode gostar