Programación visual de aplicaciones con C++ Builder

Curso de C++ Builder

Introducción El IDE Componentes La VCL Programación orientada a objetos en C++ Tratamiento de excepciones Programación con hebras Acceso a bases de datos Enlaces interesantes Todo en un ZIP

file:///D|/Manuales/index.html (1 of 2) [27/02/2003 16:23:49]

Programación visual de aplicaciones con C++ Builder

Índice

Ejercicios

Apéndices

© Francisco José Cortijo Bon & Fernando Berzal Galiano
Todos los derechos reservados por los autores sobre el contenido de este documento electrónico. Queda prohibido su uso comercial sin el consentimiento escrito de los autores. Cualquier uso de este material debe ser comunicado a los autores.

IDE | Componentes | VCL | OOP | Excepciones | Hebras | Bases de datos | Enlaces

file:///D|/Manuales/index.html (2 of 2) [27/02/2003 16:23:49]

Introducción

Curso de C++ Builder Introducción

Para ser un buen programador en C++ Builder existen distintos aspectos que se deben conocer:
q

q

q

q

El Entorno de desarrollo integrado de C++ Builder (el IDE). En la sección 2 se estudia el IDE de C++ Builder. Los componentes disponibles para crear aplicaciones Windows, y sobre éstos, sus propiedades más importantes, los métodos asociados y los eventos a los que pueden responder (sección 3). Un conocimiento genérico acerca de la biblioteca de clases visuales de Borland (la VCL), en definitiva, conocer a grandes rasgos la jerarquía de clases de la que forman parte los componentes (sección 4). Los conceptos fundamentales de la metodología de programación orientada a objetos (POO), el lenguaje C++ y cómo se debe usar bajo el estilo de C++ Builder (sección 5). Ciertas técnicas avanzadas de programación, como pueden ser el tratamiento de excepciones, la programación con hebras, la construcción de componentes personalizados, la interacción con bases de datos, la programación de aplicaciones para Internet...

q

En el transcurso del curso se pretende introducir al alumno en la programación de aplicaciones para Windows utilizando C++ Builder. Aunque se supone que éste ya posee cierta experiencia en la programación de C, y conocimientos muy básicos de programación orientada a objetos.

Página principal

file:///D|/Manuales/intro/1.html (1 of 2) [27/02/2003 16:23:49]

Introducción

© Francisco Cortijo Bon

file:///D|/Manuales/intro/1.html (2 of 2) [27/02/2003 16:23:49]

IDE

Curso de C++ Builder El IDE (Entorno de Desarrollo Integrado)

q q q q q q

2.1. Una visión general del IDE de C++ Builder.. 2.2. Un estudio detallado del IDE de C++ Builder.. 2.3. El sistema de ayuda. 2.4. Compilación, ejecución y depuración de programas. 2.5. El almacén de objetos. 2.6. Ejercicios: Ejemplos de aplicaciones simples y de consola .

IDE es el acrónimo de Integrated Development Environment o entorno de desarrollo integrado. C++ Builder es una aplicación Windows que proporciona un entorno de trabajo visual para construir aplicaciones Windows que integra distintos aspectos de la programación en un entorno unificado o integrado. La integración y facilidad de manejo hace que sea una herramienta indispensable para el desarrollo rápido de aplicaciones o RAD (Rapid Application Development). Guarda una gran similitud con el IDE de Visual Basic, aunque existen ciertas diferencias que veremos. El IDE de C++ Builder es una aplicación Windows 95 y como tal cumple con los estándares de aspecto, diseño y comportamiento que aconseja Microsoft a los desarrolladores de aplicaciones. En consecuencia, cualquiera que esté familiarizado con el manejo a nivel de usuario de Windows 95 no le supondrá ningún esfuerzo manejarlo con soltura.

2.1. Una visión general del IDE de C++ Builder.
El entorno de desarrollo se divide, básicamente, en tres partes. Una serie de ventanas, que pueden estar visibles u ocultas, constituyen la base de C++ Builder. El aspecto de la aplicación al inicio de una sesión de trabajo es el mostrado en la figura 2.1. Figura 2.1. Aspecto del C++ Builder al inicio de una sesión.

file:///D|/Manuales/intro/2.html (1 of 26) [27/02/2003 16:23:53]

IDE

En la parte superior se coloca la ventana principal, que contiene el menú principal, la barra de herramientas (a la izquierda) y la paleta de componentes (a la derecha). Debajo de la ventana principal, y a la izquierda se coloca el inspector de objetos. A la dercha del inspector de objetos está el área de trabajo de C++ Builder, que inicialmente muestra el diseñador de formularios, y escondido u oculto parcialmente tras éste
file:///D|/Manuales/intro/2.html (2 of 26) [27/02/2003 16:23:53]

IDE

aparece el editor de código. Veamos a grandes rasgos la misión de cada uno de ellos.

1. Ventana principal. En la ventana principal se ubican el menu principal, la barra de herramientas y la paleta de componentes (figura 2.2). Figura 2.2. Ventana principal de C++ Builder.

Menú principal. Permite el acceso a todas las operaciones y posibilita la configuración del programa. Barra de herramientas. Permite un acceso rápido a las operaciones que se realizan más frecuentemente. Paleta de componentes. Agrupa a los componentes que pueden incluirse en las aplicaciones.

file:///D|/Manuales/intro/2.html (3 of 26) [27/02/2003 16:23:53]

Para cambiar las propiedades de los objetos que forman la aplicación y seleccionar los eventos a los que debe responder la aplicación. 3. El inspector de objetos. Es una ventana cuadriculada sobre el que se disponen los componentes para diseñar las ventanas que formarán la aplicación. Figura 2. Diseñador de formularios.html (4 of 26) [27/02/2003 16:23:53] . El diseñador de formularios. Inspector de objetos.3. file:///D|/Manuales/intro/2. Figura 2.IDE 2.4.

file:///D|/Manuales/intro/2.html (5 of 26) [27/02/2003 16:23:53] . Un típico editor de texto multiventana para ver y editar el código de la aplicación. Figura 2.5.IDE 4. El editor de código. Editor de código. Está perfectamente integrado con el inspector de objetos y el diseñador de formularios.

IDE Existen otras partes del entorno. A continuación trataremos con más detalle las partes que hemos enumerado anteriormente. 1. 2. que ya iremos comentando conforme vayamos profundizando en el curso.html (6 of 26) [27/02/2003 16:23:53] . Menú Principal file:///D|/Manuales/intro/2.2. Un estudio detallado del IDE de C++ Builder.

.IDE Se puede decir que es la ventana principal del IDE de C++ Builder y siempre está visible.. Como veremos. etc. lógicamente. además de otros que ya iremos estudiando a lo largo del curso.6. Si nos acostumbramos a utilizarla agilizaremos el uso del entorno significativamente.) asociados a una aplicación. La barra de herramientas se puede personalizar (al igual que casi todas las partes del entorno) pulsando con el botón derecho y seleccionando Properties. recursos. consultar la lista completa de menús. En él podemos encontrar todas las operaciones disponibles. Help.. informándonos de cual es la funcionalidad de cada uno de ellos. La barra de herramientas. código fuente. 2. Su aspecto habitual es el que mostramos en la figura 2. asigan el nombre Project1 al proyecto con el que se va a trabajar. Edit. el concepto de proyecto es fundamental en C++ Builder ya que es el mecanismo de organizar sensatamente todos los ficheros (formularios. El menú principal. En el título del menú principal aparece el nombre de la aplicación (C++ Builder) y el nombre del proyecto/grupo de proyectos con el que actualmente se está trabajando. Tiene los menús comunes a cualquier aplicación Windows: File. file:///D|/Manuales/intro/2.7. Figura 2. Por defecto.7. Figura 2. Si pasamos el ratón sobre los iconos nos aparecerán unos globos o cuadros de ayuda. Search. Para más detalles acerca de los menús.html (7 of 26) [27/02/2003 16:23:53] . aunque éste deberá cambiarse. Barra de Herramientas La barra de herramientas tiene como objeto acelerar las operaciones más comunes del menú principal.

Todos los componentes (visuales y no visuales) están accesible rápida y cómodamente gracias a la paleta de componentes. Figura 2. Una estrategia alternativa (y menos utilizada) es seleccionar el componente en la ventana Components. Por conveniencia. seleccionándolo y colocándolo en un formulario.8. Conocer los componentes y su filosofía de trabajo (propiedades.8. Su aspecto es el que mostramos en la figura 2. A diferencia con Visual Basic. por lo que el usuario no puede elegir la ubicación de los componentes disponibles por defecto en la paleta de componentes. aunque se le pueden añadir más mediante las opciones del menú de componentes (opción Component del menú principal). Paleta de Componentes Los componentes constituyen los bloques básicos sobre la que se construyen aplicaciones Windows con C++ Builder basadas en la VCL (Visual Component Library) y son la base de la VCL. Cada pestaña de la paleta de componentes da acceso a un conjunto de iconos que representan a componentes que pueden usarse para diseñar la aplicación. En la sección 3 discutimos con más profundidad sobre los componentes disponibles en C++ Builder y en la sección 4 discutimos acerca de la estructura de la VCL. todos los componentes de C++ Builder se encuentran cargados por defecto. que se abre seleccionando View | Component List.IDE 3. Enlaces adicionales: file:///D|/Manuales/intro/2. La paleta de componentes. métodos y eventos) es fundamental para un programador. Cada componente tiene asignada una página. pinchar sobre el formulario donde se desea colocalo.html (8 of 26) [27/02/2003 16:23:53] . todos los componentes disponibles se encuentran organizados en distintas páginas o carpetas según su funcionalidad. aunque puede modificar la disposición de las páginas y añadir nuevas páginas o componentes ( Tools | Environment Options) Para colocar un componente en un formulario se debe seleccionar en la paleta de componentes el botón que representa al componente y a continuación. Podemos decir que es un gran almacén de componentes listos para ser incorporados a una aplicación.

Si se pincha dos veces en lugar de una. Pinchar sobre el componente para seleccionarlo. La posición de un componente siempre se ajusta al punto más próximo de la rejilla para facilitar su ajuste (su alineación). Si ésto no es lo que queremos basta con volver a activar el diseñador de formularios y continuar con la fase de diseño. 2. consultar la lista completa de componentes. Diseñador de Formularios Como hemos indicado anteriormente. Es una herramienta visual destinada a diseñar y presentar la interfaz de usuario (la apariencia externa) de una aplicación. Arrastrarlo hasta su posición final. métodos y eventos de componentes. el propio formulario) activo. En ningún caso se borrará manualmente lo que C++ Builder ha insertado automáticamente: podría provocar una inconsistencia interna y hacer inaprovechable el trabajo realizado. el código que C++ Builder ha insertado automáticamente desaparecerá porque no hemos introducido ningún código para ese gestor. se activa el editor de código para escribir el gestor del evento OnClick asociado a ese componente. agrupados por páginas. 4. Visualmente se sabe cuál es porque aparece enmarcado con trazos discontínuos en el diseñador de formularios. es una ventana cuadriculada quer sirve para diseñar las ventanas (o formularios) que formarán la aplicación (ver figura 2. consultar la relación de propiedades.IDE Para más detalles acerca de los componentes disponibles. 4. Pichar en el formulario: el componente ha quedado asociado al formulario. Para más detalles acerca de cómo configurar y manipular los componentes. Mediante el uso del ratón podemos colocar componentes de la paleta de componentes en el área de diseño. Se puede activar cualquier componente pinchando (un sólo click) sobre él. Lo único que tenemos que hacer es: 1. Siempre hay un componente (o en su defecto. un cuadro de diálogo o cualquier otra ventana. Buscar el componente en la paleta de componentes.html (9 of 26) [27/02/2003 16:23:53] .4). La opciones relacionadas con la rejilla pueden modificarse en Tools | Environment Options. Un formulario puede ser la ventana principal de un programa. 3. file:///D|/Manuales/intro/2. Cuando se guarde el proyecto.

de una de las herramientas más potentes y atractivas de C++ Builder.IDE EJERCICIO 1: Diseño de un formulario. Su aspecto es el que mostramos anteriormente en la figura 2. En la figura 2.9 mostramos el aspecto de las dos páginas en cuestión para el formulario que aparece por defecto al iniciar C++ Builder. sin duda.3. Inspector de Objetos Se trata. Se trata de una ventana que contiene dos páginas: Properties y Events. Figura 2.9. file:///D|/Manuales/intro/2. Las dos páginas (Properties y Events) del inspector de objetos.html (10 of 26) [27/02/2003 16:23:53] . 5.

Con el inspector de objetos podremos moldear los componentes de una aplicación según nuestras necesidades.9. En la parte superior se especifica el objeto activo (en la figura 2. llamado Form1). En definitiva. en cuanto a su apariencia (propiedades) y funcionalidad (eventos a los que puede responder). file:///D|/Manuales/intro/2.html (11 of 26) [27/02/2003 16:23:53] . Las propiedades del objeto activo aparecen en la página con la pestaña Properties y los eventos a los que puede responder en la página con la pestaña Events. el formulario.IDE Cada componente tiene asociado un conjunto de propiedades y métodos y un conjunto de eventos a los que puede responder. También se puede seleccionar desde el diseñador de formularios pinchando (un solo click) sobre el objeto. podemos modificar las propiedades de los componentes y construir los gestores de eventos a los que éstos pueden responder. Para seleccionar un objeto desde el inspector de objetos se despliega la lista de objetos y se selecciona el objeto en la lista.

Aparece por defecto asociada al editor (en la figura 2.10. en la parte inferior izquierda). No aparece por defecto. objetos y métodos asociados a la aplicación. En la ventana del editor pueden "pegarse" el gestor de proyectos y el inspector de clases (véase en la figura 2. Más información en este enlace. Para abrir esta ventana: View | ClassExplorer. se abre la carpeta de propiedades pinchando sobre la pestaña Properties.10 se muestra asociada al editor. y cuando se abre (View | Project Manager) se muestra como una ventana independiente.10. Editor de Código Permite editar el código de una aplicación de una forma cómoda.html (12 of 26) [27/02/2003 16:23:53] . El editor de código. se abre la carpeta de gestores de eventos seleccionando la pestaña Events. Por ejemplo. Si lo que se desea es asociarle un gestor de eventos. r r Inspector de clases: Es un navegador que muestra las clases.10) aunque estas dos herramientas pueden aparecer también como ventanas separadas. 6. Figura 2. podríamos poner el texto Escuchar saludo en un botón colocado sobre un formulario (modificando la propiedad Caption) y escribir un código para reprodicir un fichero . Admite coloreo simple de la sintaxis y distintos archivos abiertos simultáneamente. Administrador de proyectos: Es básicamente un navegador entre los diferentes ficheros que forman la aplicación. file:///D|/Manuales/intro/2.IDE Si lo que se desea es modificar sus propiedades.WAV que contiene una grabación (escribiendo un gestor para el evento OnClick) EJERCICIO 2: Uso del inspector de objetos para modificar propiedades. En la figura 2. en la parte superior izquierda.

html (13 of 26) [27/02/2003 16:23:53] . El menú contextual del editor de código.11) con algunas opciones bastante útiles.11. file:///D|/Manuales/intro/2. Figura 2.IDE Pulsando con el botón derecho aparece un menú contextual (figura 2.

C++ Builder nos permite el acceso a la totalidad del código fuente de la aplicación.IDE A diferencia con Visual Basic. Por esto es importante saber qué partes de ese código está mantenido automáticamente. y sobre todo ¡¡¡evitar modificarlo!!!. Al hacer doble click en un evento. El editor de código está relacionado muy estrechamente con el inspector de objetos.html (14 of 26) [27/02/2003 16:23:53] . No tenemos que preocuparnos de cuál es exactamente el prototipo que debemos de usar para la función que maneje el evento. el IDE genera automáticamente el código para la función manejadora para tal evento. ya que este se generará correctamente en la unidad de código asociada al Form actual. Cuando queramos eliminar un manejador de evento que ha sido generado automáticamente es conveniente no borrar "a mano" la función. 7. Lo mejor es borrar "el cuerpo" de dicha función (lo que el programador escribe) y dejar que el resto lo elimine C++ Builder (lo que ocurrirá cuando se guarde el archivo). Administrador de Proyectos file:///D|/Manuales/intro/2. EJERCICIO 3: Uso del inspector de objetos para escribir gestores de eventos con el editor de código.

Para visualizar el gestor de proyectos.IDE Un proyecto es un conjunto de archivos que trabajan en equipo para crear un archivo ejecutable independiente o una DLL. Un grupo de proyectos es un conjunto de proyectos. arrastrándolo hasta colocarlo sobre éste último (ver figura 2. Los proyectos que componen un grupo de proyectos. y será este el que se ejecute si elegimos la opción Run|Run. El gestor de proyectos puede "pegarse" al editor de código. El administrador de proyectos. Puede emplearse como navegador para seleccionar el módulo con el que se va a trabajar.10).12.html (15 of 26) [27/02/2003 16:23:53] . seleccionar View | Project Manager. file:///D|/Manuales/intro/2. En todo momento existe un único proyecto activo (en la figura 2. Figura 2. y los archivos que componen cada uno de esos proyectos. Project1). el administrador de proyectos.12. en forma de árbol. es lo que presenta.

cpp) y su correspondiente . Es el programa ejecutable resultante. normalmente) estará la declaración de los componentes de esa ventana. file:///D|/Manuales/intro/2. Más información sobre proyectos en C++ Builder y configuración de aplicaciones. A un grupo de proyectos se le pueden añadir proyectos. Unit1.. Su nombre es el nombre del proyecto. Cada uno de estos módulos estará formado por una pareja de ficheros: un . Para cada ventana (en la figura 2. al menos.12. Archivos objeto resultado de la compilación.IDE Los ficheros de proyecto especifican todos los recursos necesarios (ficheros .. habitualmente. archivos. en definitiva. módulos.cpp (en la figura 2. y que cuál es su cometido: EXT BPR CPP H OBJ EXE Descripción Es el archivo makefile del proyecto.h (que no se modificará. como en cualquier aplicación C++. Veamos brevemente qué tipos de archivos pueden formar parte de un proyecto/grupo de proyectos. Este fichero no está. . Archivos de cabecera de C++.cpp (en la figura 2. formado por una pareja de ficheros: un . etc. lógicamente. el administrador de proyectos es únicamente un organizador de archivos. Los ficheros de proyecto tienen extensión . Define qué y cómo se debe compilar. con la extensión . de un archivo de código que contiene la función principal (WinMain()). Puede abrirse en el editor de código con la opción Project|View Source. formularios.h: en el fichero .) que se necesitan para la construcción del ejecutable.html (16 of 26) [27/02/2003 16:23:53] .exe.h. ficheros de descripción de formularios. Todo proyecto en C++ Builder se compone. Cualquier aplicación típica tendrá al menos una ventana. nuevos o que ya existan. ya que no es necesario modificarlo. Además del fichero que contiene la función principal. Project1.bpr y el ejecutable que se genera tiene el mismo nombre que el proyecto y la extensión .h.cpp y su correspondiente .cpp. Form1) habrá un módulo. visible.12. un proyecto puede tener asociados una serie de módulos adicionales en los cuales pueden incluirse funciones y clases de objetos. Hemos dicho que.12. Archivos fuente de C++.cpp estarán los gestores de los eventos asociados a los componentes de esa ventana y en el .cpp).

por ejemplo. Aunque está en formato binario. Es un archivo de grupo de proyectos.13. sino que más bien es conocer los principios en los que éste se basa. en el caso de hacerlo en el editor de código.html (17 of 26) [27/02/2003 16:23:53] . El sistema de ayuda El sistema de ayuda será una de las herramientas que más útiles nos resultará en nuestro trabajo con C++ Builder. Contiene los valores de las propiedades de cada componente. Así. Ventana de ayuda que se despliega al pulsar F1 sobre la palabra clave Application file:///D|/Manuales/intro/2. 2. Figura 2. Describe qué proyectos conforman el grupo de proyectos. Especialmente la documentación de los componentes y clases predefinidas. RES DSK BPG HPP Un archivo de recursos. Archivos de cabecera creados automáticamente por C++ Builder. y los detalles concretos ya los buscaremos en la Ayuda cuando nos sean necesarios. La ayuda es una ayuda estándar de Windows por lo que no entraremos en más detalles. 2.13.3.15). Saber programar con C++ Builder no significa dominar todos y cada uno de los aspectos del entorno. se nos ofrecerá la ayuda correspondiente a la palabra que se encuentre bajo el cursor (figuras 2. Es el archivo que contiene la configuración del escritorio para un proyecto. puede verse como texto seleccionando View as text en el menú contextual que aparece al pulsar con el botón derecho del ratón cuando se está situado sobre el formulario. sólo comentar que pulsando F1 obtendremos una ayuda contextual.IDE TDS DFM Archivos temporales para la compilación incremental.14 y 2. Archivos de descripción de formulario.

IDE Figura 2. Ayuda detallada sobre Application variable (for standard applications). file:///D|/Manuales/intro/2.html (18 of 26) [27/02/2003 16:23:53] .14.

Ejemplo proporcionado en la ayuda sobre Application variable (VCL Reference).15.html (19 of 26) [27/02/2003 16:23:53] . file:///D|/Manuales/intro/2.IDE Figura 2.

IDE Pulsando F1 sobre cualquier opción de un menú se mostrará la ayuda asociada a esa opción (figura 2.16. Ventana de ayuda mostrada al pulsar F1 estando seleccionada la opción View | Project Manager file:///D|/Manuales/intro/2.16).html (20 of 26) [27/02/2003 16:23:53] . Figura 2.

Ayuda para completar código: Propiedades. Figura 2.html (21 of 26) [27/02/2003 16:23:53] . Las más importantes son: q Completar código. métodos y eventos asociados a la clase TApplication.) o el nombre de un puntero que referencia a un objeto seguido del operador de acceso flecha (->) se muestra la lista de propiedades.17). Al escribir el nombre de una clase seguido del operador de acceso punto (. file:///D|/Manuales/intro/2.17.IDE C++ Builder proporciona algunas facilidades muy útiles a la hora de escribir código. métodos y eventos asociados a esa clase (figura 2.

Figura 2.IDE q Patrones de código. Es posible configurar estas utilidades seleccionando Tools | Environment Options | Code Insight. 2. El objetivo final es la creación de un programa ejecutable correcto que funcione bajo Windows. Compilación.4. El ejecutable se construye tomando como referencia los ficheros que forman el proyecto activo. Al pulsar Ctrl+J se muestran los patrones de código (también llamados "esqueletos") que pueden insertarse en el código de nuestro programa.18). Para esta tarea se utilizan los menús Project y Run (figura 2. file:///D|/Manuales/intro/2. Pueden crearse y guardarse nuevos patrones. Submenús Project y Run del menú principal.html (22 of 26) [27/02/2003 16:23:53] . ejecución y depuración de programas.18.

IDE Project Run En la compilación se trata de la obtención del programa ejecutable (extensión . seleccionables al desplegar el menú Run (figura 2. C++ Builder proporciona facilidades para la depuración de programas. pero ejecuta las llamadas a funciones como una instrucción más.OBJ). sin mostrar la ejecución de las instrucciones de las funciones. Build. se mostraran en el editor de código y se puede acceder directamente a las líneas de código en las que se han detectado para facilitar su corrección. Si durante la compilación se detectaran errores. file:///D|/Manuales/intro/2.18).CPP) generando un fichero objeto (extensión . Genera el fichero ejecutable a partir de los ficheros objeto asociados al proyecto recompilando todos los módulos fuente. Compila el modulo fuente activo (extensión . Las más importantes son: q Step Over F8. aunque no se hayan modificado desde la última vez que se compilaron. Para ejecutar el programa basta con pinchar sobre el botón correspondiente de la barra de herramientas o seleccionar la opción Run | Run. Make.18).EXE). Genera el fichero ejecutable a partir de los ficheros objeto asociados al proyecto recompilando únicamente los módulos fuente que se q hayan modificado desde la última vez que se compilaron.html (23 of 26) [27/02/2003 16:23:53] . Ejecuta instrucción a instrucción el programa. y las más importantes son: q q Compile Unit. Las operaciones asociadas a este objetivo se encuentran en el menú que se despliega al seleccionar la opción Project del menú principal (figura 2.

Visualizar el contenido de una variable permanentemente. consiguiendo de esta forma reutilizar nuestros diseños. Además se pueden incorporar nuevos elementos que nosotros desarrollemos. cuadros de diálogo. Run to Cursor F4. Add Watch Ctrl+F5. Todos ellos están prediseñados y pueden servirnos como punto de partida para nuestros propios diseños. file:///D|/Manuales/intro/2.html (24 of 26) [27/02/2003 16:23:53] . que podemos utilizar para simplificar el desarrollo de aplicaciones. Ejecuta instrucción a instrucción el programa. Contiene formularios. DLLs. incluidas las instrucciones de las funciones llamadas. El almacén de objetos. Evaluar expresiones que involucren a las variables y modificar los valores de las variables. Add Breakpoint. de modo que cuando se ejecute el programa se detendrá su ejecución al llegar al siguiente punto de ruptura. Figura 2.IDE q q Trace Into F7. módulos de datos. Añade un punto de ruptura en la línea en la que está situado el cursor. El almacén de objetos Se accede al almacén seleccionando File | New. etc.19. asistentes. 2. Ejecuta desde el principio del programa hasta la línea en la que está situada el cursor. Para que la depuración sea más completa y versátil se incorporan las siguientes opciones en el mismo menú: q q q Evaluate/Modify Ctrl+F7.5.

IDE En este curso utilizaremos con frecuencia el almacén para crear nuevos proyectos (File | New | Application). etc.html (25 of 26) [27/02/2003 16:23:53] . Ejercicios Ejemplos de aplicaciones simples y de consola. para añadir nuevos formularios (File | New | Form) o ficheros de código (File | New | Unit). 2. para crear módulos de datos (File | New | Data Module). file:///D|/Manuales/intro/2. para crear aplicaciones de consola (File | New | Console Wizard).6.

html (26 of 26) [27/02/2003 16:23:53] .IDE Página principal © Francisco Cortijo Bon file:///D|/Manuales/intro/2.

.Menús Curso de C++ Builder Lista completa de menús Sobre el menú principal y sus submenús. File file:///D|/Manuales/appendix/menu/index.html (1 of 4) [27/02/2003 16:23:53] ..

Menús Edit Search View file:///D|/Manuales/appendix/menu/index.html (2 of 4) [27/02/2003 16:23:53] .

Menús Project Run Component file:///D|/Manuales/appendix/menu/index.html (3 of 4) [27/02/2003 16:23:53] .

Menús Database Tools Workgroups Help Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/menu/index.html (4 of 4) [27/02/2003 16:23:53] .

2. Win32: Componentes de cuadros de diálogo propios de Windows 95/NT.3. 3.1. a saber: q q q q q q Standard: Incluye los componentes comunes y más habituales de los programas Windows. Esto es tanto así que algunos componentes pueden utilizarse en ambos entornos (los componentes ActiveX). Internet: Componentes para distintos protocolos de acceso a Internet. La filosofía de los componentes en C++ Builder es exactamente la misma que en Visual Basic.html (1 of 5) [27/02/2003 16:23:54] . Páginas de componentes. Componentes visuales y no visuales. Data Access y Data Controls: Componentes especializados para acceso a bases file:///D|/Manuales/intro/3. propios de C++ Builder. Propiedades. 3. cuya única finalidad es la reutilización. Los componentes son unos elementos genéricos con una funcionalidad muy concreta. métodos y gestores de eventos a cada control. Additional: Los componentes de esta página son controles especializados. Páginas de componentes Como ya hemos comentado anteriormente los componentes se agrupan en la paleta de componentes en distintas páginas.1. métodos y gestores de eventos. 3.Componentes Curso de C++ Builder Componentes q q q 3. System: Esta página incluye controles muy especializados para interacción con el sistema. Un componente de la VCL es una clase que caracteriza a un control de Windows agregando propiedades. Cada uno de ellos está destinado a realizar una tarea típica en una aplicación.

tanto en tiempo de diseño como en tiempo de ejecución.2. Propiedades. Dialogs: Contiene cuadros de diálogo comunes en aplicaciones Windows listos para usar. un método de acceso asociado que se ejecuta al modificar la propiedad en tiempo de ejecución.html (2 of 5) [27/02/2003 16:23:54] . Midas: Esta página incluye componentes que permiten el desarrollo de aplicaciones multicapa con MIDAS. la mayoría de ellos se mantienen en C++ Builder sólo por compatibilidad con versiones anteriores. Para más detalles.1. Muchos componentes tienen propiedades en común. creados por otros desarrolladores puede que utilizando otros lenguajes de programación. los métodos que puede ejecutar y los eventos a los que puede responder. Las propiedades tienen. Por ejemplo. métodos y gestores de eventos De un componente podemos destacar tres aspectos: sus propiedades. Para modificar una propiedad file:///D|/Manuales/intro/3. consultar la lista completa de componentes. Hemos visto como pueden establecerse y modificarse las propiedades de los componentes en tiempo de diseño utilizando el inspector de objetos. Decision Cube: Incluye componentes para realizar análisis multidimensionales de datos con objeto de tomar decisiones. todos los componentes visuales tienen las propiedades Top y Left que controlan la posición del componente en el formulario. Win 3. Samples: Componentes de demostración (cómo hacer componentes personalizados). Active X: Los componentes de esta página son objetos Active X. Las propiedades son los elementos del componente que configuran su aspecto y controlan su comportamiento. Propiedades.1: Componentes propios de Windows 3.Componentes q q q q q q q de datos. QReport: Componentes para diseñar rápidamente informes y resúmenes. agrupados por páginas. normalmente. 3.

En definitiva. lo ejecuta. La VCL comprueba si existe un método de acceso asociado al especificador de escritura y si es así.html (3 of 5) [27/02/2003 16:23:54] . r EJERCICIO 4: Modificación y consulta de propiedades en tiempo de ejecución. Al consultar el valor de una propiedad se está accediendo al especificador de lectura. hay un especificador de lectura y un especificador de escritura. Métodos. A modo de resumen. la VCL dibuja de nuevo todo el formulario en la nueva ubicación. Al realizar un cambio. las propiedades tienen dos especificadores de acceso que se emplean al consultar o modificar el valor de una propiedad en tiempo de ejecución. En el caso concreto de la propiedad Left. Al consultar o modificar el valor de una propiedad se invocan. la VCL invoca el método de acceso a la propiedad. todos los componentes visuales tienen un método llamado Show() para mostralos y otro llamado Hide() para ocultarlos. las funciones respectivas asociadas: r Al asignar un nuevo valor a una propiedad se está accediendo al especificador de escritura. simplemente asigna el nuevo valor a la propiedad. Los métodos son funciones asociadas al componente que pueden invocarse para que el componente realice distintas acciones. Los especificadores de acceso asocian métodos de lectura o de escritura (funciones.Componentes basta (generalmente) con asignarle el nuevo valor. En la mayoría de los casos el especificador de lectura no hace más que devolver el valor de la propiedad. en definitiva) con las propiedades. En el ejemplo 3 invocamos al método Terminate() asociado a la aplicación que se estaba file:///D|/Manuales/intro/3. Por ejemplo. Si no existe. automáticamente.

html (4 of 5) [27/02/2003 16:23:54] . Se pueden tratar los eventos de un componente que necesitemos.Componentes ejecutando (Objeto Application) para terminar su ejecución como respuesta a la pulsación del botón. etc. pulsación de una tecla del teclado. Eventos. La forma de tratar un evento asociado a un componente en C++ Builder es sencilla: se activa el componente que va a responder al evento y utilizando el Inspector de Objetos (pestaña Events) se selecciona el evento al que debe responder y.) que pueden condicionar el comportamiento y apariencia del programa. file:///D|/Manuales/intro/3. Esto significa que cualquier programa está condicionado por lo eventos que ocurren en el entorno Windows. y dejar que los demás sean tratados por defecto. Cada componente poseerá una serie de eventos que puede recibir o generar. Un evento es cualquier suceso que puede ocurrirle a un componente (movimiento del ratón. pulsación de algún botón del ratón. Los eventos se manejan mediante los gestores o manipuladores de eventos. Un programa Windows está continuamente sondeando al sistema ante la ocurrencia de cualquier evento y de ocurrir. Windows avisa al programa enviándole un mensaje. cuando se active el editor de código. En C++ los métodos son miembros de una clase. Cuando se responde a un evento se dice que se está manipulando el evento. se escribe el código asociado al gestor del evento. EJERCICIO 5: Métodos asociados a componentes. Un programa Windows está ocioso la mayor parte del tiempo esperando a que ocurra algún evento. desplazamiento o redimensionamiento de una ventana. al igual que las propiedades. Se dice que Windows está orientado a eventos.

Por lo demás no existen más diferencias entre ellos. barras de scroll. cuadros de diálogo -no visibles en la fase de dieño-. frente a no visuales.html (5 of 5) [27/02/2003 16:23:54] . y se dice no visual en caso contrario (temporizadores. etc. Los componentes no visuales se pueden colocar en los formularios de la misma manera que los controles. 3. excepto. Componentes visuales y no visuales Se pueden establecer muchas clasificaciones para los componentes. etc).Componentes EJERCICIO 6: Gestores de eventos. Página principal © Francisco Cortijo Bon file:///D|/Manuales/intro/3. cuadros de edición. claro está.). aunque en este caso su posición es irrelevante. Un componente es visual cuando tiene una representación gráfica en tiempo de diseño y ejecución (botones. las derivadas de la visualización del componente.3. Una de ellas es la de visuales o controles.

file:///D|/Manuales/appendix/components/Standard. añadir el componente MainMenu al formulario y hacer doble click sobre él para acceder al diseñador de menús.Standard Curso de C++ Builder La paleta de componentes Página Standard Iconos de los componentes agrupados en la página Standard Esta página incluye los componentes comunes y más habituales de los programas Windows: Crea una barra de menú (que actúa como menú principal). MainMenu Edit Memo Muestra un área de edición de texto en la que el usuario puede introducir y modificar una única línea de texto. Se usa para mostrar textos de título. o incluso para mostrar resultados. Label encabezamientos. proceder como con el componente MainMenu. Para configurar el menú desplegable. Para añadir opciones al menú y a los submenús. Muestra un área de edición de texto en la que el usuario puede introducir y modificar múltiples líneas de texto. Crea menús desplegables (también llamados menús contextuales) que aparecen cuando se pincha con el botón PopupMenu derecho del ratón. ya que puede establecerse su valor (propiedad Caption) en tiempo de ejecución. Muestra texto que el usuario no puede seleccionar ni manipular.Paleta de componentes .html (1 of 2) [27/02/2003 16:23:55] .

Se usa para crear barras de herramientas y líneas de estado. Crea grupos de acciones que centralizan las respuestas de la plicación ante las acciones del usuario. por lo que el usuario puede seleccionar sólo una en un grupo. Este control puede emplearse para crear un grupo de estos controles que representen elecciones mutuamente exclusivas (al contrario que los CheckBox. Muestra una lista de eleciones. se permuta entre RadioButton ambos valores.html (2 of 2) [27/02/2003 16:23:55] . Es un control que combina aspectos de un componente ListBox y de un componente Edit: el usuario puede introducir datos en el área de edición o seleccionar en el área de lista. Presenta una opción binaria (Si/No . Los componentes que contiene están asociados al panel. por lo que el usuario puede seleccionar más de una opción en un grupo.de valores por incrementos prefijados. se permuta entre ambos valores. Contenedor para agrupar opciones relacionadas en un formulario. ListBox ComboBox ScrollBar GroupBox Muestra una lista de eleciones que está acompañada de una barra de scroll. file:///D|/Manuales/appendix/components/Standard. RadioGroup Contenedor que crea un grupo de componentes RadioButton en un formulario.Verdad/Falso) de manera que cuando se selecciona este control. Prociona una forma cómoda de modificar el área visible de un formulario o de una lista. Este control puede emplearse para crear un grupo de estos controles que representen elecciones que no CheckBox sean mutuamente exclusivas (al contrario que los RadioButton.Standard Button Crea un botón que el usuario puede pulsar para efectuar acciones. Presenta una opción binaria (Si/No .Verdad/Falso) de manera que cuando se selecciona este control.Paleta de componentes . También puede usarse para "desplazarse" en un rango -amplio. Panel ActionList Contenedor que puede contener otros componentes en un formulario.

Estos botones se agrupan. Crea una rejilla que puede usarse para mostrar cadenas en filas y columnas.Paleta de componentes .html (1 of 2) [27/02/2003 16:23:55] .Additional Curso de C++ Builder La paleta de componentes Página Additional Iconos de los componentes agrupados en la página Additional Los componentes de esta página son controles especializados: BitBtn SpeedButton MaskEdit StringGrid DrawGrid Crea un botón que puede contener un gráfico (tipo "bitmap"). como códigos postales o números de teléfono. dentro de un panel para crear una barra de herramientas. normalmente. Crea un botón que puede contener un gráfico pero no contiene texto. Crea una rejilla que puede usarse para mostrar datos en filas y columnas. como lo hace el componente Edit. salvo que proporciona la posibilidad de especificar formatos particulares. Permite la introducción y edición de datos. file:///D|/Manuales/appendix/components/Additional.

Dibuja figuras geométricas. Es un componente de texto no editable. rectángulos. file:///D|/Manuales/appendix/components/Additional. Añade un divisor a un formulario entre dos componentes alineados que permite al usuario redimensionar los controles en tiempo de ejecución pinchando y arrastrando la línea de división. sólo que StaticText tiene su propio gestor de ventana. cuadrados o rectángulos y cuadrados con bordes redondeados. círculos. como el componente Label.Paleta de componentes . Crea líneas o cuadros con apariencia tridimensional y como si estuviera esculpida (alto o bajorrelieve).Additional Image Shape Bevel ScrollBox CheckListBox Splitter StaticText ControlBar Chart Muestra un "bitmap" o un icono. como elipses. Es muy parecido al componente ListBox salvo que cada elemento de la lista tiene asociado un CheckBox. Muestra una lista de eleciones que está acompañada de una barra de scroll. Un visualizador equivalene a TTable. Un gestor para acompañar a barras de herramientas que se usa para poder mover este tipo de barras. Crea un contenedor redimensionable que muestra barras de scroll cuando sea necesario.html (2 of 2) [27/02/2003 16:23:55] .

Paracrear una lista de imágenes.html (1 of 2) [27/02/2003 16:23:56] .Paleta de componentes . Es una especialización del componente Memo: proporciona la posibilidad de 1) modificar propiedades acrerca de la fuente de letra (familia. TabControl PageControl ImageList Divisor de páginas mutuamente exclusivas accesibles por pestañas. tabulaciones. tamaño. color. Se emplea para gestionar eficientemente grandes conjuntos de imágenes o "bitmaps". y 3) marcación de texto y arrastre del mismo. indentación o numeración). Es una barra que muestra un rango y un indicador que muestra el valor actual y que permite modificarlo. 2) modificar propiedades de formato (alineamiento. Se emplea para construir cuadros de diálodo con múltiples páginas dentro de la misma ventana. RichEdit TrackBar file:///D|/Manuales/appendix/components/Win32.Win32 Curso de C++ Builder La paleta de componentes Página Win32 Iconos de los componentes agrupados en la página Win32 Esta página incluye componentes comunes de aplicaciones para 32 bits. añadir un componente ImageList al formulario y hacer doble click sobre él para acceder al editor de listas de imágenes. Una lista de imágenes es una colección de imágenes del mismo tamaño accesibles mediante un índice. negrita o itálica).

Paleta de componentes . colocándolos adecuadamente ajustando su posición y tamaño. Una ventana que se emplea para mostrar ficheros AVI (Audio Video Interleaved) o series de "bitmaps" dispuestos en secuencia. Gestiona botones rápidos y otros controles.html (2 of 2) [27/02/2003 16:23:56] . file:///D|/Manuales/appendix/components/Win32. Permite ver una lista en columnas.Win32 ProgressBar UpDown HotKey Animate Es una barra rectangular que se va "llenando" de izquierda a derecha. MonthCalendar Muestra un calendario que representa un solo mes. Este control puede dividirse en varias partes para proporcionar cabeceras para múltiples columnas. como una película. Muestra una colección de controles "CoolBand" dentro de bandas que pueden moverse y redimensionarse. Asigna una combinación de teclas a cualquier componente. Se emplea para mostrar cómo progresa una operación. La fecha DateTimePicker puede seleccionarse desde el calendario o empleando la barra de scroll o las flechas. Muestra un encabezamiento sobre columnas de texto o números. TreeView ListView HeaderControl StatusBar ToolBar CoolBar PageScroller Muestra un conjunto de objetos estructurados jerárquicamente. Área para indicar el estado de acciones o textos de pista amplios ("Hints") en la parte baja de la ventana. Son botones para incrementar y decrementar valores. Contiene objetos dentro del área de cliente que pueden desplazarse horizontal o verticalmente sin usar una barra de scroll sino empleando las flechas. Muestra una lista de elecciones que está acompañada de una barra de scroll para seleccionar fechas.

Paleta de componentes - System

Curso de C++ Builder La paleta de componentes

Página System
Iconos de los componentes agrupados en la página System

Esta página incluye controles muy especializados:

Timer PaintBox MediaPlayer OleContainer

Es un componente no visual que actúa como temporizador. Se emplea para ejecutar una serie de instrucciones (mediante el gestor del evento OnTimer) que deben ejecutarse cuando se alcanza el valor especificado como intervalo (propiedad Interval). Especifica un área rectangular sobre un formulario que delimita la zona en la que puede dibujarse desde una aplicación. Muestra una ventana con botones (similares a los de cualquier reproductor de audio o video) para reproducir video o sonido. Crea un área de cliente OLE (Object Linking and Embedding) en un formulario.

DdeClientConv Establece una conexión cliente a una aplicación servidora DDE (Dynamic Data Exchange).

file:///D|/Manuales/appendix/components/System.html (1 of 2) [27/02/2003 16:23:56]

Paleta de componentes - System

DdeClientItem Especifica los datos del cliente DDE (Dynamic Data Exchange) que se transfieren en una conversación DDE. DdeServerConv Establece una conexión servidora a una aplicación cliente DDE (Dynamic Data Exchange). DdeServerItem Especifica los datos del servidor DDE (Dynamic Data Exchange) que se transfieren en una conversación DDE.

file:///D|/Manuales/appendix/components/System.html (2 of 2) [27/02/2003 16:23:56]

Paleta de componentes - Internet

Curso de C++ Builder La paleta de componentes

Página Internet
Iconos de los componentes agrupados en la página Internet

Los componentes de esta página ofrecen diferentes protocolos de acceso a Internet:

Add to a form or data module to turn an application into a TCP/IP client. ClientSocket specifies a desired connection to a TCP/IP server, manages the open connection, and terminates the completed connection. Add to a form or data module to turn an application into a TCP/IP server. ServerSocket listens for requests for TCP/IP ServerSocket connections from other machines and establishes connections when requests are received. Converts an ordinary data module to a Web module and enables the Web server application to respond to HTTP request WebDispatcher messages. Converts an HTML template into a string of HTML commands that can be interpreted by a client application such as a PageProducer Web browser. The commands and HTML-transparent tags are replaced with customized content by the OnHTMLTag event. Assembles a sequence of HTML commands to generate a tabular display of the records from a TQuery object, which QueryTableProducer obtains its parameters from an HTTP request message. Assembles a sequence of HTML commands to generate a tabular display of the records from a TDataSet object. This DataSetTableProducer allows an application to create images of a dataset for an HTTP response message. ClientSocket
file:///D|/Manuales/appendix/components/Internet.html (1 of 2) [27/02/2003 16:23:57]

Paleta de componentes - Internet

DataSetPageProducer NMDayTime NMEcho NMFinger NMFTP NMHTTP NMMsg NMMsgServ NMNNTP NMPOP3 NMUUProcessor NMSMTP NMStrm NMStrmServ NMTime NMUDP PowerSock NMGeneralServer HTML NMURL

Converts an HTML template that contains field references into a string of HTML commands that can be interpreted by a client application such as a Web browser. Special HTML-transparent tags are replaced with field values. Gets the date and time from an internet/intranet daytime server. Sends text to an internet echo server, and echoes it back to you. Gets information about a user from an internet finger server, using the Finger protocol described in RFC 1288. Implements file transfer protocol. Invisible ActiveX control provides easy access for Internet File Transfer Protocol (FTP) services for transferring files and data between a remote and local machine. Invisible ActiveX control implements the HTTP Protocol Client, allowing users to directly retrieve HTTP documents if no browsing or image processing is necessary. Sends simple ASCII text messages across the internet or intranet using TCP/IP protocol. Receives messages sent with the TNMMsg component. Invisible ActiveX Client Control allows applications to access Networking News Transfer Protocol (NNTP) news servers. It provides news reading and posting capabilities. Invisible ActiveX control that retrieves mail from UNIX or other servers supporting POP3 protocol. MIME encodes or UUEncodes files and decodes MIME-encoded or UUEncoded files. ActiveX control that gives applications access to SMTP mail servers and mail posting capabilities. Sends streams to a stream server across the internet or an intranet. Receives streams sent with the TNMStrm component. Gets the date and time from Internet time servers, as described in RFC 868. Invisible WinSock ActiveX Control provides easy access to User Datagram Protocol (UDP) network services. It implements WinSock for both client and server and represents a communication point utilizing UDP network services. It can also be used to send and retrieve UDP data. Serves as a base for creating controls for dealing with other protocols, or for creating custom protocols. Serves as a base class for developing multi-threaded internet servers, such as custom servers or servers that support RFC standards. Invisible ActiveX control implements an HTML viewer, with or without automatic network retrieval of HTML documents, and provides parsing and layout of HTML data, as well as a scrollable view of the selected HTML page. The HTML component can also be used as a nonvisual HTML parser to analyze or process HTML documents. Decodes URL data into a readable string, and encodes standard strings into URL data format.

file:///D|/Manuales/appendix/components/Internet.html (2 of 2) [27/02/2003 16:23:57]

Paleta de componentes - Data Access

Curso de C++ Builder La paleta de componentes

Página Data Access
Iconos de los componentes agrupados en la página Data Access

Esta página incluye componentes especialzados para acceso a bases de datos:

DataSource Acts as a conduit between a dataset component such as TTable and data-aware components such as TDBGrid. Retrieves data from a physical database table via the BDE and supplies it to one or more data-aware components through a Table DataSource component. Conversely, it also sends data received from a component to a physical database via the BDE. Uses SQL statements to retrieve data from a physical database table via the BDE and supplies it to one or more data-aware Query components through a TDataSource component. Conversely, uses SQL statements to send data from a component to a physical database via the BDE. Enables an application to access server stored procedures. Sends data received from a component to a physical database via StoredProc the BDE. Database Sets up a persistent connection to a database, especially a remote database requiring a user login and password.

file:///D|/Manuales/appendix/components/Data_Access.html (1 of 2) [27/02/2003 16:23:58]

Paleta de componentes - Data Access

Provides global control over a group of Database components. A default TSession component is automatically created for each C++Builder database application. You must use the TSession component only if you are creating a multithreaded database application. Each database thread requires its own session component. BatchMove Copies a table structure or its data. Can be used to move entire tables from one database format to another. Lets you use cached updates support with read-only datasets. For example, you could use a TUpdateSQL component with a "canned" query to provide a way to update the underlying datasets, essentially giving you the ability to post updates to a UpdateSQL read-only dataset. You associate a TUpdateSQL component with a dataset by setting the dataset's UpdateObject property. The dataset automatically uses the TUpdateSQL component when cached updates are applied. NestedTable Retrieves the data in a nested dataset field and supplies it to data-aware controls through a datasource component. Session

file:///D|/Manuales/appendix/components/Data_Access.html (2 of 2) [27/02/2003 16:23:58]

Paleta de componentes - Data Controls

Curso de C++ Builder La paleta de componentes

Página Data Controls
Iconos de los componentes agrupados en la página Data Controls

Esta página incluye componentes especialzados para gestión de bases de datos:

DBGrid

DBNavigator DBText DBEdit DBMemo DBImage DBListBox DBComboBox

Data-aware custom grid that enables viewing and editing data in a tabular form similar to a spreadsheet. Makes extensive use of TField properties (set in the Fields editor) to determine a column's visibility, display format, ordering, and so on. Data-aware navigation buttons that move a table's current record pointer forward or backward. The navigator can also place a table in Insert, Edit, or Browse state, post new or modified records, and retrieve updated data to refresh the display. Data-aware label that displays a field value in the current record. Data-aware edit box that displays or edits a field in the current record. Data-aware memo box that displays or edits BLOB text in the current record. Data-aware image box that displays, cuts, or pastes bitmapped BLOB images to and from the current record. Data-aware list box that displays a scrolling list of values from a column in a table. Data-aware combo box that displays or edits a scrolling list of values from a column in a table.

file:///D|/Manuales/appendix/components/Data_Controls.html (1 of 2) [27/02/2003 16:23:58]

Paleta de componentes - Data Controls

DBCheckBox DBRadioGroup

Data-aware check box that displays or edits a Boolean data field from the current record. Data-aware group of radio buttons that display or set column values. DBLookupListBox is a data-aware list box that derives its list of display items from either a Lookup field defined for a dataset or a secondary data source, data field, and key. In either case, a user is presented with a restricted list of choices DBLookupListBox from which to set a valid field value. When a user selects a list item, the corresponding field value is changed in the underlying dataset. To specify list box items using a lookup field, the dataset to which you link the control must already define a lookup field. DBLookupComboBox is a data-aware combo box that derives its drop-down list of display items from either a lookup field defined for a dataset or a secondary data source, data field, and key. In either case, a user is presented with a DBLookupComboBox restricted list of choices from which to set a valid field value. When a user selects a list item, the corresponding field value is changed in the underlying dataset. To specify combo box list items using a lookup field, the dataset to which you link the control must already define a lookup field. DBRichEdit A multiline edit control that can display and edit a rich text memo field in a dataset. A DBCtrlGrid control displays multiple fields in multiple records in a tabular grid format. Each cell in the grid displays DBCtrlGrid multiple fields from a single record. DBChart Place the component on a form and right-click it to display the third-party developer's Help topics.

file:///D|/Manuales/appendix/components/Data_Controls.html (2 of 2) [27/02/2003 16:23:58]

html (1 of 2) [27/02/2003 16:23:59] . See Creating and using a client dataset Establishes a DCOM connection to a remote server in a multi-tiered database application. ClientDataSet file:///D|/Manuales/appendix/components/MIDAS.Paleta de componentes . See Connecting to the SocketConnection application server Establishes an OLEnterprise connection to a remote server in a multi-tiered database application. See Creating a data provider for the application server and Providing from and resolving to a dataset Encodes data from a dataset into packets than can be sent to client applications and applies updates that are received Provider from client applications to a dataset or database server. See Creating a data provider for the application server.MIDAS Curso de C++ Builder La paleta de componentes Página MIDAS Iconos de los componentes agrupados en la página MIDAS Esta página incluye componentes que permiten el desarrollo de aplicaciones multicapa con MIDAS: Implements a database-independent dataset that can be used independently in a single-tiered application. See Connecting to OLEnterpriseConnection the application server Encodes data from a dataset into packets than can be sent to client applications and applies updates that are received DataSetProvider from client applications to that dataset. See Connecting to the DCOMConnection application server Establishes a TCP/IP connection to a remote server in a multi-tiered database application. or to represent data received from a server in a multi-tiered database application.

file:///D|/Manuales/appendix/components/MIDAS.html (2 of 2) [27/02/2003 16:23:59] .MIDAS SimpleObjectBroker RemoteServer MIDASConnection Locates a server for a connection component from a list of available application servers. TCP/IP.Paleta de componentes . (For backward compatibility only) Establishes a DCOM. See Brokering connections. (For backward compatibility only) Establishes a DCOM connection to a remote server in a multi-tiered application. or OLEnterprise connection to a remote server in a multi-tiered application.

DecisionGrid Displays single and multidimensional data in table form. See Using decision cubes. See Creating and Using decision grids.Decision Cube Curso de C++ Builder La paleta de componentes Página Decision Cube Iconos de los componentes agrupados en la página Decision Cube Esta página incluye componentes para realizar análisis multidimensionales de datos con objeto de tomar decisiones: DecisionCube A multidimensional data store. See Creating decision datasets with the Decision Query DecisionQuery editor. See Using decision sources. DecisionPivot Use to open or close decision cube dimensions or fields by pressing buttons.html [27/02/2003 16:23:59] . DecisionSource Defines the current pivot state of a decision grid or a decision graph.Paleta de componentes . See Using decision pivots. Specialized form of TQuery used to define the data in a decision cube. Displays fields from a decision grid as a dynamic graph that changes when dimensions are modified. See Using decision DecisionGraph graphs. file:///D|/Manuales/appendix/components/Decision_Cube.

resúmenes. arrays. etc. listas. QuickRep QRSubDetail QRStringsBand QRBand QRChildBand The basic report form on which you build all your reports. Drop bands on a TQuickRep component and set the BandType property to tell how the band will behave during report generation. matrices. Create reports by dropping bands and printable components on the TQuickRep component and connecting it to a dataset. If you have bands with expanding components and want other components to be moved down accordingly you can create a child band and put the moving components on it. It's also useful if you have very long bands that span multiple pages. Puede usarse un visalizador previo para comprobar los resultados. Se pueden incorporar cabeceras y pies de páginas. It is a visual component that takes the shape of the currently selected paper size. Estos informes pueden realizarse a partir de cualquier fuente de datos: TTable. etc.html (1 of 2) [27/02/2003 16:24:00] .QReport Curso de C++ Builder La paleta de componentes Página QReport Iconos de los componentes agrupados en la página QReport Esta página incluye componentes para diseñar rápidamente informes y resúmenes. Typically you would set up a master/detail relationship between table or query components and create a similar relationship with TQRSubDetail components. Links additional datasets into a report. file:///D|/Manuales/appendix/components/QReport. Automáticamente se realizan cálculos similares a como se hacen en una hoja de cálculo. TQuery. Drops bands containing strings onto a report.Paleta de componentes . agrupaciones con cabeceras y pies.

Calculated fields and text field types can be printed. Prints static or other non-database text. and static text. footers. Prints all graphics formats supported by C++Builder. QRCompositeReport Allows you to combine more than one report together. Set any preceding text in the Text property. TQRDBText works even with dataset controls disabled to improve speed. QRChart Allows you to take a TChart component and drop it onto your Quick Report form. QRTextFilter Lets you export the contents of your report into text format.Paleta de componentes . You connect the component to the data field by setting the DataSource and DataField properties. file:///D|/Manuales/appendix/components/QReport. QRDBRichText Provides a Quick Report wrapper for accessing DBRichText fields in your reports. Supports all image formats supported by the TPicture class. It can be static text or you can change it during QRMemo report generation.html (2 of 2) [27/02/2003 16:24:00] . current page number. A data-aware version of the TQRLabel that prints the value of a database field. Text can span multiple lines and QRDBText pages. Enter the text to be displayed in the Caption property. Input a valid QuickReport expression in the Expression property. You can split text on QRLabel multiple lines and even multiple pages. and so on. circles. You can set the field to expand vertically as needed and then span multiple pages if necessary. QRShape Draws simple shapes like rectangles. QRHTMLFilter Lets you export the contents of your report into HTML. calculations. QRDBImage Prints images stored in binary (BLOB) fields. various numeric fields. including String fields. and page breaks. QRExprMemo Allows you to programmatically generate contents using Quick Report expressions. Prints a large amount of text that does not come from a database field. QRCSVFilter Lets you export the contents of your report into a comma-delimited database source file. QRPreview Brings up a form that allows you to preview a report on the screen and print it. QRImage Displays a picture on a report.QReport QRGroup Allows you to group bands together and provides control for headers. QRRichText Allows you to embed rich text into your report. date fields and memo fields. Prints system information such as report title. and lines on a report. QRExpr Prints database fields. Select the data to print in the Data QRSysData property. Unlike regular data-aware components.

Cada ventana de diálogo (excepto la asociada al componente PrinterSetup) tiene la propiedad Options que afecta a su apariencia y comportamiento.Paleta de componentes .html (1 of 2) [27/02/2003 16:24:00] . Este método devuelve un valor lógico: true si el usuario elige OK en la ventana de diálogo. usar las propiedades Handle. Una ventana de diálogo se abre al llamar al método Execute(). Left. file:///D|/Manuales/appendix/components/Dialogs. Top y Position. Para modificar en tiempo de ejecución su posición. Estas ventanas de diálogo proporcionan un interface consistente para realizar operaciones sobre ficheros como abrir. Una ventana de diálogo puede cerrarse desde un programa mediante el método CloseDialog().Dialogs Curso de C++ Builder La paleta de componentes Página Dialogs Iconos de los componentes agrupados en la página Dialogs Esta página incluye las diferentes ventanas de diálogo comunes en aplicaciones Windows. false si el usuario elige Cancel o sale de la ventana de diálogo sin salvar los cambios. guardar e imprimir.

html (2 of 2) [27/02/2003 16:24:00] . Muestra una ventana de diálogo común de Windows para especificar información de impresión. FindDialog ReplaceDialog Muestra una ventana de diálogo común de Windows para especificar la cadena a buscar. Es idéntica SavePictureDialog a la ventana asociada a SaveDialog salvo que contiene una región para previsualización de imágenes.Paleta de componentes . FontDialog ColorDialog PrintDialog Muestra una ventana de diálogo común de Windows para especificar la familia. Muestra una ventana de diálogo común de Windows para seleccionar y guardar ficheros. PrinterSetupDialog Muestra una ventana de diálogo común de Windows para configurar impresoras. Muestra una ventana de diálogo modal común de Windows para seleccionar y abrir ficheros gráphicos. Muestra una ventana de diálogo común de Windows para especificar color. Muestra una ventana de diálogo modal común de Windows para seleccionar y guardar ficheros gráphicos. file:///D|/Manuales/appendix/components/Dialogs.Dialogs OpenDialog SaveDialog OpenPictureDialog Muestra una ventana de diálogo común de Windows para seleccionar y abrir ficheros. Es idéntica a la ventana asociada a OpenDialog salvo que contiene una región para previsualización de imágenes. tamaño y estilo de letra. Muestra una ventana de diálogo común de Windows para especificar la cadena a buscar y la cadena por la que se va a reemplazar.

html (1 of 2) [27/02/2003 16:24:01] .1 Iconos de los componentes agrupados en la página Win 3.1 Curso de C++ Builder La paleta de componentes Página Win 3. Muchos de estos controles tienen su versión actualizada en componentes incluidos en la página Win32.1.1 Esta página incluye controles propios de Windows 3.1 Sustituir por TabSet Outline NoteBook Header TabControl TreeView PageControl HeaderControl Página Win32 Win32 Win32 Win32 Win32 DBLookupCombo DBLookupComboBox Data Controls TabbedNoteBook PageControl file:///D|/Manuales/appendix/components/Win_3. Estos controles no deberían usarse al desarrollar nuevas aplicaciones.Paleta de componentes . En la siguiente tabla se indica qué control debería usarse en su lugar: Control Win 3.1 para permitir compatibilidad con aplicaciones antiguas.Win 3.

Paleta de componentes . Creates notebook-like tabs. file:///D|/Manuales/appendix/components/Win_3. You can use the TabSet component with the Notebook component to enable users to change TabSet pages. FileListBox Displays a scrolling list of files in the current directory. Users can change directories in a directory list box. Used with the Notebook component. it enables users to change pages. Creates a component that contains multiple pages. FilterComboBox Specifies a filter or mask to display a restricted set of files. Users select a page by clicking the tab TabbedNotebook at the top of the page Notebook Creates a component that can contain multiple pages. Outline Displays information in a variety of outline formats. DirectoryListBox Displays the directory structure of the current drive. each with its own set of controls.Win 3. Users can resize each section of the region to display different amounts of Header data.1 DBLookupList Data-aware list box that displays values looked up from columns in another table at runtime. DBLookupCombo Data-aware combo box that displays values looked up from columns in another table at runtime. DriveComboBox Displays a scrolling list of available drives.1.html (2 of 2) [27/02/2003 16:24:01] . Creates a sectioned region for displaying data.

Pie Performance Graph CSpinButton CSpinEdit CGauge CDirectoryOutline CColorGrid CCalendar IBEVentAlerter file:///D|/Manuales/appendix/components/Samples.Paleta de componentes .Samples Curso de C++ Builder La paleta de componentes Página Samples Iconos de los componentes agrupados en la página Samples Esta página incluye ejemplos de componentes personalizados que pueden construirse e incorporarse a la paleta de componentes. El código fuente está disponible en el directorio \EXAMPLES\CONTROLS\SOURCE de la instalación.html [27/02/2003 16:24:01] .

VtChart Lets you create true 3D charts. Graph Pinnacle Graph.ActiveX Curso de C++ Builder La paleta de componentes Página Active X Iconos de los componentes agrupados en la página Active X Los componentes de esta página son objetos ActiveX. Choose Properties to display a tabbed control panel that lets you define the values.Paleta de componentes . lets you design a spreadsheet with its full-featured Designer. Lets you create highly customized charts. Chartfx file:///D|/Manuales/appendix/components/ActiveX. Son aplicaciones completas y portables creadas por otros desarrolladores. lets you create 2D graphs. lets you customize a spelling checker. F1Book Formula One. and end-user functionality of the chart component. appearance. VSSpell Visual Speller.html [27/02/2003 16:24:02] .

html [27/02/2003 16:24:02] .1 file:///D|/Manuales/appendix/components/index. en 14 páginas. siguiendo el criterio de utilidad en este curso. Las páginas cuyo título está precedido por el símbolo español. están traducidas al Standard Additional Win32 System Dialogs Data Access Data Controls QReport Decision Cube Internet MIDAS ActiveX Samples Win 3. por defecto. En la siguiente tabla agrupamos las páginas según nuestra conveniencia.Paleta de componentes Curso de C++ Builder La paleta de componentes La paleta de componentes se estructura.

Recordar que basta con hacer doble click en OnCreate (pestaña Events del inspector de objetos) del componente MainForm.Ejercicio 4. } //------------------------------------------------------------ A continuación. observar que su título quedó fijado a Form de Prueba después de modificar la propiedad Caption del formulario. } // Lectura // Escritura file:///D|/Manuales/intro/ejemplos/ej4. Para ello escribiremos un gestor para el evento OnCreate asociado al componente MainForm. Modificación y consulta de propiedades en tiempo de ejecución Sobre el formulario que estamos empleando.html (1 of 3) [27/02/2003 16:24:02] . Para modificar su valor en tiempo de ejecución haremos que. modificaremos el color del formulario (propiedad Color) siempre que el valor de esta propiedad esté establecido al valor por defecto (clBtnFace): //-----------------------------------------------------------void __fastcall TMainForm::FormCreate(TObject *Sender) { MainForm->Caption = "Primer programa con C++ Builder". if (MainForm->Color == clBtnFace) MainForm->Color = clWhite. Escribiremos el siguiente fragmento de código: //-----------------------------------------------------------void __fastcall TMainForm::FormCreate(TObject *Sender) { MainForm->Caption = "Primer programa con C++ Builder". por ejemplo. Modificación y consulta de propiedades en tiempo de ejecución Curso de C++ Builder Ejercicio 4. el título se establezca en el momento de la creación de la ventana.

1.Ejercicio 4. el resultado es el mostrado en la figura E4. Modificación y consulta de propiedades en tiempo de ejecución //------------------------------------------------------------ Finalmente. } //-----------------------------------------------------------// Lectura // Escritura // Escritura Si generamos el ejecutable y ejcutamos el programa. CheckBox->Checked = false. file:///D|/Manuales/intro/ejemplos/ej4.1. if (MainForm->Color == clBtnFace) MainForm->Color = clWhite. El programa al iniciar su ejecución después de modificar propiedades en tiempo de ejecución. Figura E4.html (2 of 3) [27/02/2003 16:24:02] . estableceremos que cuando empiece la ejecución del programa se encuentre desactivado el CheckBox: //-----------------------------------------------------------void __fastcall TMainForm::FormCreate(TObject *Sender) { MainForm->Caption = "Primer programa con C++ Builder".

Ejercicio 4. Modificación y consulta de propiedades en tiempo de ejecución Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/ej4.html (3 of 3) [27/02/2003 16:24:02] .

Ejercicio 5. Métodos asociados a componentes Modificaremos el gestor del evento OnCreate del componente MainForm para que no se muestren los dos botones de radio. RadioButton1->Hide(). // Lectura // Escritura // Escritura // Hide() es el metodo que oculta el // componente sobre el que se aplica.1. el resultado es el mostrado en la figura E5.1. if (MainForm->Color == clBtnFace) MainForm->Color = clWhite.html (1 of 2) [27/02/2003 16:24:03] . } //--------------------------------------------------------------- Si generamos el ejecutable y ejcutamos el programa. Métodos asociados a componentes Curso de C++ Builder Ejercicio 5. Figura E5. RadioButton2->Hide(). El programa al iniciar su ejecución después de modificar propiedades en tiempo de ejecución y de llamar al método Hide() asociado a los componentes RadioButton file:///D|/Manuales/intro/ejemplos/ej5. //--------------------------------------------------------------void __fastcall TMainForm::FormCreate(TObject *Sender) { MainForm->Caption = "Primer programa con C++ Builder". CheckBox->Checked = false.

Métodos asociados a componentes Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/ej5.Ejercicio 5.html (2 of 2) [27/02/2003 16:24:03] .

Gestores de eventos Construiremos el gestor del evento asociado a modificar el componente CheckBox de forma que cuando se active (inicialmente está desactivado) se muestren los dos botones de radio y se active el botón de OK.Ejercicio 6. } else { RadioButton1->Hide().1. cuando se activa el CheckBox produce el siguiente resultado: Figura E6. Para ello. escribiremos el gestor asociado al evento OnClick del componente CheckBox: //-----------------------------------------------------------void __fastcall TMainForm::CheckBoxClick(TObject *Sender) { if (CheckBox->Checked == true) { RadioButton1->Show(). RadioButton2->Show(). LabelOutput->Caption = "". OKButton->Enabled = true. Gestores de eventos Curso de C++ Builder Ejercicio 6. RadioButton2->Hide(). } } //------------------------------------------------------------ Al ejecutar el programa. RadioButton1->Checked = true. los botones de radio se volverán a ocultar y el botón de Ok se desactivará. El programa al activar el CheckBox file:///D|/Manuales/intro/ejemplos/ej6. Cuando se desactive.html (1 of 3) [27/02/2003 16:24:03] . OKButton->Enabled = false.

que está operativo (propiedad Enabled) únicamente cuando el CheckBox está activado.2. file:///D|/Manuales/intro/ejemplos/ej6. desconocido/a". y en consecuencia. escribiremos el gestor del evento asociado a hacer click sobre el botón OK. } else { if (Edit->Text == "") LabelOutput->Caption = "Escogió Opción 2. " + Edit>Text. desconocido/a". Observar el siguiente código y dos resultados de la ejecución (figuras E6. } } //------------------------------------------------------------ Figura E6. Resultado al seleccionar la opción 1 estando el cuadro de edición vacío. Gestores de eventos Finalmente. Sr/Sra. cuando pueden emplearse los botones de radio. else LabelOutput->Caption = "Escogió Opción 2.3): //-----------------------------------------------------------void __fastcall TMainForm::OKButtonClick(TObject *Sender) { if (RadioButton1->Checked) { if (Edit->Text == "") LabelOutput->Caption = "Escogió Opción 1. Sr/Sra.2 y E6.Ejercicio 6. else LabelOutput->Caption = "Escogió Opción 1. " + Edit>Text. Sr/Sra.html (2 of 3) [27/02/2003 16:24:03] . Sr/Sra.

Resultado al seleccionar la opción 2 habiendo escrito algo en el cuadro de edición. Gestores de eventos Figura E6.3.html (3 of 3) [27/02/2003 16:24:03] .Ejercicio 6. Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/ej6.

html (1 of 2) [27/02/2003 16:24:03] .C++ Builder Curso de C++ Builder Introducción El IDE Componentes La VCL Programación orientada a objetos en C++ Tratamiento de excepciones Programación con hebras Acceso a bases de datos Enlaces interesantes Todo en un ZIP Índice Ejercicios Apéndices file:///D|/Manuales/contents.

Queda prohibido su uso comercial sin el consentimiento escrito de los autores.C++ Builder © Francisco José Cortijo Bon & Fernando Berzal Galiano Todos los derechos reservados por los autores sobre el contenido de este documento electrónico.html (2 of 2) [27/02/2003 16:24:03] . Cualquier uso de este material debe ser comunicado a los autores. file:///D|/Manuales/contents.

file:///D|/Manuales/intro/4. los ficheros. Pero este conjunto de funciones es muy grande. Por todo esto es que los entornos de programación visuales. 4.2. Un paseo por la VCL. Restricciones al uso de la VCL en C++ Builder. que es un conjunto de funciones que proporciona el sistema operativo para poder habilitar la comunicación. Clases de formularios y aplicaciones. Es el sistema operativo quién realiza todas estas tareas. La VCL es un marco de trabajo visual y orientado a objetos.4.3. no son las aplicaciones quienes manejan los recursos del sistema como pueden ser la memoria. Clases de componentes. 4.5.1. las ventanas y hasta los controles gráficos. En Windows. Figura 4.html (1 of 7) [27/02/2003 16:24:04] . Estas peticiones se realizan mediante lo que se denomina la API de Windows. poco estructurado y difícil de manejar. Controles de edición y Editor.VCL Curso de C++ Builder La VCL (Biblioteca de Componentes Visuales) q q q q q 4. Normalmente estos marcos de trabajo son orientados a objetos y se implementan como bibliotecas del lenguaje base.1. han desarrollado diversos Marcos de Trabajo. Ejercicios: Pizarra. 4. Y la aplicación se limita a realizar peticiones de lo que necesita. 4. en su afán de aportar simplicidad y estructuración a la programación en Windows. La VCL como interface. Un marco de trabajo es una fase intermedia que se coloca por encima de la API para aportar mayor sencillez a las aplicaciones. por ello también se suelen denominar bibliotecas de clases.

y su marco de trabajo. En 1995.VCL Tan importantes son los marcos de trabajo. Los marcos de trabajo C++ (OWL y MFC) 2. que dominar un entorno de programación visual. MFC es una biblioteca de clases menos abstracta que el OWL y más cercana a la API. suele traducirse en conocer el leguaje base del entorno. Aunque MFC se usa más que OWL (Microsoft. técnicamente. OWL (Object Windows Library o Biblioteca de Objetos para Windows) fue un marco de trabajo desarrollado por Borland e incorporado a los compiladores Borland C++ (versiones 3 y sucesivas) y supuso un importante hito en la programación para Windows por su potencia y facilidad de uso.. Microsoft desarrolló su propio marco de trabajo. métodos y eventos). También resulta más sencillo que OWL para los programadores que conocen la API.html (2 of 7) [27/02/2003 16:24:04] . Delphi empleaba como base al lenguaje Object Pascal (una ampliación file:///D|/Manuales/intro/4.. Los marcos de trabajo se pueden clasificar en dos categorías: 1. La VCL. Delphi ofrecía el desarrollo rápido de aplicaciones (RAD) empleando componentes (objetos que pueden ubicarse en formularios y manipulados por medio de propiedades. el MFC (Microsoft Foundation Class o Biblioteca Fundamental de Clases de Microsoft) y lo incorporó a los compiladores Microsoft Visual C++ (actualmente incluso en Borland C++ 5). Borland lanzó al mercado Delphi. que supuso la revolución en la programación para Windows e inició el desarrollo rápido y sencillo de aplicaciones visuales.) la arquitectura de OWL es. Esta forma de trabajo se hizo más popular con Visual Basic. mejor que MFC.

1. El objetivo final de la VCL es crear clases que representan a componentes. está escrita en Object Pascal.3 describimos con más detalle las clases más importantes de la VCL. de hecho. Jerarquía de clases de la VCL. Un paseo por la VCL Conocer en profundidad la VCL se nos antoja imposible. Es file:///D|/Manuales/intro/4. aunque algunas clases no hagan referencia componentes concretos: realizan tareas de gestión interna y se emplean como clases bases para derivar mediante herencia otras clases. 4. métodos y eventos). La VCL desarrollada para Delphi es la misma que se emplea como núcleo de C++ Builder. además de innecesario.1. 4.html (3 of 7) [27/02/2003 16:24:04] ..2 mostramos una pequeña parte de la jerarquía de clases que forman la VCL. por lo que se ejecutaban mucho más rápido que los de Visual Basic..2.2 y 4. La VCL hace un uso extensivo del concepto de herencia. En las secciones 4. En la figura 4. Figura 4.VCL de Pascal que incorpora programación orienta a objetos) y permitía la creación de programas ejecutables independientes que no requerían intérprete. Lo más relevante desde el punto de vista técnico es que Borland creó la VCL (Visual Class Library o Biblioteca de Componentes Visuales) que es un marco de trabajo para crear aplicaciones Windows diseñada en torno al concepto de componente (propiedades.

La funcionalidad de TComponent permite que los objetos aparezcan en la paleta de componentes y que sean manipulados por el diseñador de formularios. Directamente de TObject heredan aquellas clases que no son componentes. No se suelen crear objetos directamente a partir de ellas. no son clases abstractas. instanciación. Rigurosamente hablando.. Las clases que conforman la parte superior de la jerarquía de la VCL (TObject. si lo es que lo haga C++ Builder en tiempo de ejecución. y no necesitan ser almacenadas en disco. pero las podemos considerar como tales en la práctica. Suele ser una buena idea derivar nuestras propias clases de TObject. TPersistent Esta clase tiene que ver con la habilidad de un objeto de almacenarse en disco o en memoria. aunque consideramos conveniente relizar una somera descripción de la jerarquía de clases que conforman la VCL. además de otras capacidades comunes a los componentes. como puede ser información de la clase.VCL posible construir aplicaciones Windows de gran calidad con C++ Builder sin un conocimiento exhaustivo de la VCL. TComponent Ésta es una de las clases más importantes de la VCL. porque no tienen métodos virtuales puros (ver sección 5. TObject Es el ancestro de todas las clases de la VCL.html (4 of 7) [27/02/2003 16:24:04] . porque aunque no sea normal que el programador haga uso de los métodos proporcionados por TObject.5. Encapsula el comportamiento común de los objetos en C++ Builder.2). Los componentes no visuales derivan directamente de TComponent mientras file:///D|/Manuales/intro/4. Esta clase proporciona toda la funcionalidad que requiere un componente básico. y agrupar comportamientos comunes de las clases de la VCL. así como otros detalles internos de C++ Builder que no es preciso conocer. asignarse a otros objetos. ya que la mayoría de los objetos que se manejan en una aplicación son componentes. TPersistent y TComponent) se denominan clases "abstractas" porque sirven para estructurar..

que a su vez deriva de TComponent.VCL que los componentes visuales derivan de TControl. Clases de Formularios y Aplicaciones Son controles en si mismas. TWinControl Son los controles típicos de Windows. TControl Proporciona la funcionalidad de los componentes visuales (controles). pero no se presentan en la paleta de componentes. pero no pueden recibir el foco: el usuario podrá verlos pero no interactuar con ellos. TApplication La clase TApplication encapsula una aplicación Windows por lo que caracteriza las operaciones fundamentales de un programa en Windows. file:///D|/Manuales/intro/4. Un manejador de ventana es un identificador que proporciona Windows para el control. Esta funcionalidad es principalmente el aspecto visual que deben ofrecer los componentes en tiempo de ejecución. contener otros controles. establecer los textos de sugerencia de los botones y barras de estado. y además poseen un manejador de ventana. ocupándose de tareas como gestionar el paso de mensajes. TGraphicControl Generaliza a los controles que tienen una representación visual. clases derivadas de TControl. TControl proporciona mayor funcionalidad que la que requieren los componentes visuales: los componentes individuales derivan de TGraphicControl o de TWinControl. que pueden recibir el foco. 4. gráficos o dibujos. proporcionar la ayuda contextual.html (5 of 7) [27/02/2003 16:24:04] . por lo que podemos decir que Windows tiene un conocimiento directo de la existencia del mismo. TApplication simplifica el interface entre el programador y el sistema operativo. Poseen una propiedad Canvas que permite acceder a su área de dibujo. Suelen ser controles para visualizar texto (no editable en tiempo de ejecución). Por esta razón se suelen denominar controles a los componentes visuales.2.

ventanas secundarias o cualquier otro tipo de ventana que se pueda imaginar. Todas las aplicaciones de C++ Builder tienen un puntero a un objeto TApplication denominado Application.3. Básicamente. cuadros de diálogo. Como Application se crea automáticamente no aparece en la paleta de componentes ni está disponible en el inspector de objetos para manipular "visualmente" sus propiedades. Los formularios se emplean como ventanas principales. Propiedades. En cualquier caso. TForm La clase TForm caracteriza a los formularios en la VCL. file:///D|/Manuales/intro/4. incorpora a todos los componentes que aparecen en la paleta de componentes del IDE de C++ Builder (ver sección 3. algunas propiedades pueden establecerse en tiempo de diseño seleccionando las páginas Forms o Applicaction después de seleccionar Project | Options. etc. Clases de componentes Este grupo abarca un amplio espectro de clases. métodos y eventos de aplicaciones. 4. ejecutar cuadros de mensajes.html (6 of 7) [27/02/2003 16:24:04] .VCL procesamiento de "teclas rápidas". gestión de excepciones. Propiedades. que se crea automáticamente.1) lo que implica que se pueden colocar sobre un formulario. métodos y eventos de formularios.

Editor. agrupados por páginas. 4. Página principal © Francisco Cortijo Bon file:///D|/Manuales/intro/4. q q q Pizarra . Controles de edición y Editor. y no en la pila. métodos y eventos de componentes. existen algunos aspectos que deben ser tenidos en cuenta: q Los objetos de la VCL deben crearse siempre dinámicamente (con new). Restricciones al uso de la VCL en C++ Builder La VCL se desarrolló originariamente en y para Delphi.5. Ejercicios: Pizarra. Controles de edición . No se puede usar herencia múltiple con clases VCL.VCL Lista completa de componentes.4.html (7 of 7) [27/02/2003 16:24:04] . por lo que está construida en Object Pascal. La VCL no asigna valores por defecto a las funciones. Aunque esto no supone normalmente consideraciones especiales. Propiedades. q q 4. Esto es así porque deben de localizarse en el heap.

Application->Run(). int) { try { Application->Initialize(). si retomamos el ejemplo inicial de este curso (proyecto Inicial). USEFORM("main. } catch (Exception &exception) { Application->ShowException(&exception). Recordar que el formulario principal se llamó. finalmente. C++ Builder instancia la variable Application. //-------------------------------------------------------------------------WINAPI WinMain(HINSTANCE. &MainForm). MainForm).cpp".html (1 of 2) [27/02/2003 16:24:04] . A modo de ejemplo.res"). llama a sus métodos Initialize(). En Inicial. Application->CreateForm(__classid(TMainForm). HINSTANCE. LPSTR.h> #pragma hdrstop USERES("Inicial. } //-------------------------------------------------------------------------- Atrás file:///D|/Manuales/intro/vcl/application. Inicial.cpp.La variable Application Curso de C++ Builder Sobre la variable Application Cuando un programa empieza a ejecutarse. CreateForm() y Run(). observar el contenido del fichero que C++ Builder crea como fichero principal de la aplicación. } return 0.cpp: //-------------------------------------------------------------------------#include <vcl. MainForm.

html (2 of 2) [27/02/2003 16:24:04] .La variable Application © Francisco Cortijo Bon file:///D|/Manuales/intro/vcl/application.

2. Hint especifica el texto que debe aparecer en el cuadro de ayuda o texto de sugerencia asociado a la aplicación.TApplication . Pueden emplearse las funciones GetShortHint() y GetLongHint() para obtener las dos partes de la propiedad Hint Hint y ShowHint file:///D|/Manuales/appendix/tapplication. Este cuadro aparece cuando ocurre el evento OnHint. ShowHint determina si los cuadros de sugerencia estarán activados o desactivados para toda la aplicación. métodos y eventos q q q 1. por ejemplo. Propiedades de las aplicaciones.Propiedades. Eventos de las aplicaciones. 3.Propiedades. Por defecto se muestra únicamente el cuadro asociado al componente sobre el que está el ratón por lo que usualmente se emplea esta propiedad para mostrar la información extensa de este componente en una barra de estado.html (1 of 4) [27/02/2003 16:24:05] . métodos y eventos Curso de C++ Builder TApplication . Métodos de las aplicaciones. Propiedad Active Descripción Especifica si la aplicación está activa y tiene el foco. Propiedades de las aplicaciones. 1.

CurrentHelpFile. Método BringToFront() Descripción Establece la última ventana activa como la que se muestra por encima de todas las demás. 2. Métodos de las aplicaciones. Generan un evento OnHelp. y si no hay un gestor para este evento. el programador no usa este método ya que las líneas de código para la creación de formularios las añade automáticamente C++ Builder. Pueden establecerse en tiempo de diseño seleccionando Project | Options | Application. Muestra un mensaje al usuario en cuadro de diálogo que puede incorporar botones. Se emplean para gestionar la ayuda asociada a una aplicación. HelpFile y Para especificar el fichero de ayuda asociado a la aplicación.TApplication . Crea un nuevo formulario. Icon y Title Especifican el icono y el texto. Para ocultarla. MainForm y ShowMainForm ShowMainForm especifica si la aplicación debe mostrar la ventana principal al iniciar su ejecución. respectivamente.Propiedades. se gestiona a través de WinHelp. que aparecen en la barra de tareas de Windows cuando se minimiza la aplicación. establecer esta propiedad a false antes de la llamada a Application->Run y asegurarse de que la propiedad Visible del formulario esté también a false. CreateForm() HelpCommand().html (2 of 4) [27/02/2003 16:24:05] . Devuelve un valor que depende del botón seleccionado para cerrar el cuadro de diálogo. Generalmente. métodos y eventos MainForm especifica qué formulario actúa como ventana principal de la aplicación. HelpContext() y HelpJump() MessageBox() file:///D|/Manuales/appendix/tapplication.

html (3 of 4) [27/02/2003 16:24:05] . mientras Terminate() termina la ejecución de una aplicación. Pueden emplearse las funciones GetShortHint() y GetLongHint() para obtener las dos partes de la propiedad Hint file:///D|/Manuales/appendix/tapplication. OnHint ocurre cuando el cursor se coloca sobre un control o una opción de un menú que puede mostrar un cuadro de sugerencia. Para especificar qué excepciones pueden gestionarse en la aplicación. construir un gestor para el evento OnException.Propiedades. Una aplicación se activa cuando se genera la aplicación (empieza a ejecutarse) o cuando estaba activa otra aplicación y una ventana de la aplicación a la que se refiere recibe el foco. Evento Descripción Ocurren cuando se activa o desactiva la aplicación. Muestra un cuadro de diálogo cuando se produce una excepción que no es gestionada por la aplicación.TApplication . Proporciona una manera de gestionar excepciones por defecto en la aplicación. Se suele usar para modificar la apariencia del cuadro. Se suele escribir un gestor para este evento cuando se quiere mostrar el texto largo de sugerencia en la barra de estado. métodos y eventos Minimize() y Restore() Run() y Terminate() Minimize() minimiza una aplicación y la aloja en la barra de tareas de Windows. Run() ejecuta la aplicación. Eventos de las aplicaciones. mientras que Restore() reestablece el tamaño que tenía la aplicación antes de ser minimizada. respectivamente. ShowException() HandleException() 3. OnActivate y OnDeactivate OnHint y OnShowHint OnShowHint ocurre cuando la aplicación va a mostar un cuadro de sugerencia. Una aplicación se desactiva cuando el usuario selecciona otra aplicación.

Propiedades.TApplication . Ocurre cuando se pulsa una tecla. Se emplea cuando se desea modificar el comportamiento por defecto de una aplicación cuando se manifiesta alguna excepción que no es tratada por el programa. métodos y eventos OnMinimize y OnRestore OnHelp Ocurren cuando la aplicación se minimiza o se reestablece al tamaño normal. respectivamente. Ocurre cuando la aplicación recibe una petición de ayuda. OnException OnShortCut Se emplea este gestor para realizar acciones antes de que el formulario o los controles del formulario gestionen los eventos oportunos a la pulsación de teclas. Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tapplication. Los métodos HelpContext() y HelpJump() gestionan automáticamente este evento.html (4 of 4) [27/02/2003 16:24:05] .

por este orden: 1. 2.html [27/02/2003 16:24:05] . y 3.Eventos asociados a las teclas Curso de C++ Builder Sobre los eventos asociados a la pulsación de teclas Cuando se pulsa una tecla se desencadenan los siguientes eventos. OnKeyPress. OnKeyDown. OnKeyUp Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tip/tip_tecla.

r r 1.2. q 1. Métodos de los formularios. Eventos de los formularios. Propiedades en tiempo de diseño y ejecución.1. Propiedades en tiempo de ejecución.TForm . 3. file:///D|/Manuales/appendix/tform. Propiedades en tiempo de diseño y ejecución.html (1 of 6) [27/02/2003 16:24:06] . 1. Propiedades de los formularios. Indica si el formulario está activo (si puede recibir el foco). métodos y eventos Curso de C++ Builder TForm .Propiedades. Propiedad ActiveControl Enabled Descripción Establece qué componente tiene el foco cuando se abre el formulario. Propiedades de los formularios.Propiedades.1. q 2. 1. métodos y eventos q 1.

Altura y anchura (en píxeles) del formulario. Al modificar estas propiedades se actualizan Width y Height.Propiedades. Para especificar si un formulario es o no parte de una aplicación multiformulario. Coordenadas X e Y del formulario (su esquina superior izquierda) en la pantalla. Color de fondo del formulario. HorzScrollBar Controlan conjuntamente las barras de desplazamiento de un y formulario. métodos y eventos AutoScroll. Permite especificar las propiedades de la fuente de letra que se usará en el formulario. Especifica qué cursor se muestra cuando está sobre el formulario.TForm . Para especificar el fichero de ayuda asociado a la aplicación y gestionar la ayuda contextual. VertScrollBar BorderIcons BorderStyle Caption y Name Color Cursor Font Indica qué iconos aparecen en la barra de título de un formulario. Indica qué tipo de borde debe tener el formulario. Caption indica la cadena que aparece en la barra de título del formulario mientras que Name indica con qué nombre se refiere al formulario en la aplicación (en el código). Se aplica a todos los componentes ubicados en el formulario. Altura y anchura (en píxeles) del área de cliente del formulario (el área de cliente es la que queda dentro de los bordes del formulario y por debajo de la barra de título y de la barra de menú). Determina el tamaño y la posición del formulario.html (2 of 6) [27/02/2003 16:24:06] . Icon Height y Width ClientWidth y ClientHeight Left y Top Position FormStyle HelpFile y HelpContext file:///D|/Manuales/appendix/tform. Establece el icono que se verá en la barra de título cuando se muestre el formulario en tiempo de ejecución y cuando se minimize.

Para establecer el estado inicial del formulario (normal.Propiedades. WindowState 1. . Suele usarse con el gestor del evento OnPaint. ShowHint determina si los cuadros de sugerencia estarán activados o desactivados para el formulario. mapas de bits. El valor devuelto cuando se cierra un formulario modal (abierto con el método ShowModal()). si es modal. métodos y eventos Hint y ShowHint Hint especifica el texto que debe aparecer en el cuadro de ayuda o texto de sugerencia asociado al formulario. Propiedades en tiempo de ejecución. Este cuadro aparece cuando ocurre el evento OnHint. etc. si es visible. texto.. Canvas ClientRect ModalResult FormState file:///D|/Manuales/appendix/tform. Proporciona información acerca del estado en que se encuentra un formulario (si se está creando. minimizado o maximizado) o consultar su estado. La propiedad Canvas da acceso a esta superficie para dibujar líneas. por ejemplo.TForm ..html (3 of 6) [27/02/2003 16:24:06] . El lienzo es la superficie del formulario sobre la que se puede dibujar. Propiedad Active Descripción Indica si el formulario está activo (si tiene el foco). Por defecto se muestra únicamente el cuadro asociado al componente sobre el que está el ratón por lo que usualmente se emplea esta propiedad para mostrar la información extensa de este componente en una barra de estado. en el área de cliente.2. Los métodos Show() y ShowModal() hacen que un formulario sea visible y lo colocan por encima de todos.). Coordenadas de los cuatro puntos que delimitan el área de cliente del formulario. Visible Indica si el formulario es visible o no.

Esta última llama al manipulador del evento OnCloseQuery. poniendo a verdad la propiedad Active. file:///D|/Manuales/appendix/tform. Close() cierra el formulario tras llamar a CloseQuery() para asegurarse de que es correcto cerrarlo.Propiedades. Métodos de los formularios. ShowModal() ejecuta (abre) el formulario modalmente: debe cerrarse para que el usuario pueda seguir trabajando con la aplicación. Refresh(). Repaint() y Update() Redibujar un formulario. respectivamente. Oculta el formulario (establece la propiedad Visible a falso). el componente especificado en la propiedad ActiveControl recibe el foco. Método BringToFront() y SendToBack() Hide() Print() Show() y ShowModal() Close() y CloseQuery() Descripción Coloca al formulario en primer plano o en último. Left. Devuelve verdad si el formulario puede recibir el foco (si las propiedades Visible y Enabled están a verdad). ScreenToClient() Invalidate(). Establece simultáneamente los valores de las propiedades Top. Imprime el contenido del formulario. Además.TForm . SetFocus() CanFocus() SetBounds() ClientToScreen() Convierte las coordenadas del área de cliente en coordenadas de y pantalla y viceversa. Width y Height. métodos y eventos 2.html (4 of 6) [27/02/2003 16:24:06] . Activa el formulario y lo coloca en primer plano. Para mostrar formularios.

TForm . OnClick y OnDblClick file:///D|/Manuales/appendix/tform. Eventos asociados al movimiento y pulsación con el ratón. Un formulario se activa cuando se recibe el foco y se desactiva cuando el foco pasa a otro formulario de la misma aplicación. Evento OnActivate y OnDeactivate Descripción Ocurren cuando se activa o desactiva un formulario. cuando se pincha con él sobre el formulario. El evento OnClose ocurre cuando se cierra un formulario. respectivamente. OnCreate y OnDestroy OnClose y OnCloseQuery OnMouseDown.html (5 of 6) [27/02/2003 16:24:06] . Una acción puede desencadenar varios eventos y el orden en ocurren puede ser muy importante: Eventos asociados a la creación y destrucción de un formulario. OnCreate ocurre cuando se crea inicialmente el formulario (sólo ocurre un evento de este tipo por formulario) y OnDestroy cuando se destruye. Eventos de los formularios. Eventos asociados a la pulsación de alguna tecla. 3. Para responder a los eventos que suceden al mover el ratón o OnMouseUp.Propiedades. Hace una llamada a OnCloseQuery para asegurarse de que es correcto cerrarlo. métodos y eventos Release() Destruye un formulario y libera toda la memoria asociada. OnMouseMove.

Ocurre cuando se pulsa una tecla. Ocurre cuando se recibe una petición de ayuda en el formulario. métodos y eventos OnKeyDown. Ocurre cuando se modifica el tamaño del formulario. a veces es preciso redibujar "manualmente" el formulario. Ocurren cuando se oculta o se muestra el formulario.html (6 of 6) [27/02/2003 16:24:06] . OnKeyUp y OnKeyPress OnHelp OnHide y OnShow Para responder a los eventos que suceden al pulsar alguna tecla sobre el formulario. respectivamente).Propiedades. Esto ocurre muy frecuentemente. y aunque los componentes del formulario se redibujan por sí mismos generalmente. justo después de redimensionar el formulario. OnShow ocurre justo antes de que el formulario se haga visible.TForm . Ocurre cuando el formulario necesita ser redibujado (refrescado). OnPaint OnResize OnShortCut Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tform. antes de que ocurra OnKeyDown. respectivamente (cuando su propiedad Visible se establece a falso o verdad. Ocurre antes de que cualquier control sea redibujado.

cuando se destruye el formulario se generan los siguientes eventos. El destructor del formulario (si existe). OnActivate.Eventos asociados a la creación y destrucción de formularios Curso de C++ Builder Sobre los eventos asociados a la creación y destrucción de formularios Cuando se crea un formulario se generan los siguientes eventos. OnPaint. 3. OnShow. OnCreate. 3. Atrás file:///D|/Manuales/appendix/tip/tip_form.html (1 of 2) [27/02/2003 16:24:06] . 4. que enumeramos ordenadamente: 1. OnCloseQuery. 2. 5. De la misma manera. que enumeramos ordenadamente: 1. OnDestroy. OnClose. El constructor del formulario. 4. 2.

html (2 of 2) [27/02/2003 16:24:06] .Eventos asociados a la creación y destrucción de formularios © Francisco Cortijo Bon file:///D|/Manuales/appendix/tip/tip_form.

2. que enumeramos ordenadamente: 1. OnMouseUp. cuando el usuario pulsa dos veces sobre un formulario o un control se generan los siguientes eventos. 2. tan sólo hay que atender al evento OnClick. Así. OnMouseUp.html (1 of 2) [27/02/2003 16:24:06] . OnClick. 3. OnMouseDown. Atrás file:///D|/Manuales/appendix/tip/tip_raton. Si se quiere atender a la pulsación del ratón sobre un formulario o un control.Eventos asociados al ratón Curso de C++ Builder Sobre los eventos asociados al ratón Los eventos del ratón presentan ciertas particularidades que se deben conocer. Si se tienen que utilizar OnMouseDown y OnMouseUp hay que tener en cuenta que OnClick lleva involucrado los eventos OnMouseDown y OnMouseUp. 3. una pulsación del ratón genera los siguientes eventos. OnMouseDown. 4. OnClick. De la misma manera. OnDblClick. que enumeramos ordenadamente: 1.

html (2 of 2) [27/02/2003 16:24:06] .Eventos asociados al ratón © Francisco Cortijo Bon file:///D|/Manuales/appendix/tip/tip_raton.

file:///D|/Manuales/appendix/tcomponent.1. 1. Propiedad Align Descripción Establece distintas posiciones y ajustes del componente relativos al componente que lo contiene. si es verdad que existen algunas propiedades comunes. métodos y eventos Curso de C++ Builder TComponent .1.Propiedades. Otras propiedades de uso corriente. Propiedades de los componentes.Propiedades. q 2. Eventos de los componentes.2. Métodos de los componentes. 1. Propiedades de los componentes. que comentaremos brevemente.html (1 of 5) [27/02/2003 16:24:07] . q 1. r r 1. 3. Propiedades comunes más importantes. Propiedades comunes más importantes. Aunque cada componente tiene sus propias propiedades. métodos y eventos q 1. métodos y eventos.TComponent .

TComponent . por lo que no responde al ratón. Enabled Hint y ShowHint Cuando se establecen a verdad. al teclado ni a eventos del temporizador. ShowHint determina si la ayuda de sugerencia breve se debe mostrar o no. emplean el valor que tienen establecido para esa ParentShowHint propiedad. file:///D|/Manuales/appendix/tcomponent. En ParentFont y otro caso. métodos y eventos Caption indica el texto que acompaña a algunos componentes. La segunda se presenta en la barra de estado. Permite especificar las propiedades de la fuente de letra que se usará en el componente. Establece qué icono se muestra cuando el usuario mueve el cursor sobre un componente. separadas por la barra |. Caption y Name Color Cursor Font Se refiere al color de fondo del componente. Name indica el nombre o identificador que se le asigna al componente en el programa y con el que se referirá al componente en la aplicación (en el código).Propiedades. Tiene dos partes. heredan el valor para la ParentColor.html (2 of 5) [27/02/2003 16:24:07] . Visible Indica si el componente es visible o no. C++ Builder usará el valor de la propiedad Name para crear el puntero que referenciará al componente y el programador lo usará para referenciarlo. Hint especifica el texto que debe aparecer en el cuadro de ayuda o texto de sugerencia asociado a un componente. Para activar y desactivar componentes: cuando un componente se desactiva no puede recibir el foco. La primera (sugerencia breve) se visualiza cuando el usuario coloca el puntero sobre el componente. propiedad a la que hacen referencia de su componente padre. Esta información aparece cuando ocurre el evento OnHint.

Las siguientes propiedades. Método Descripción ClientToScreen() Convierte las coordenadas del área de cliente en coordenadas de y pantalla y viceversa.TComponent . respectivamente. No se emplean habitualmente porque las acciones que realizan se efectúan modificando las propiedades del componente. Métodos de los componentes. Altura y anchura (en píxeles) del componente.html (3 of 5) [27/02/2003 16:24:07] . 2. ScreenToClient() file:///D|/Manuales/appendix/tcomponent. métodos y eventos 1. Coordenadas X e Y del componente (su esquina superior izquierda).2.Propiedades. Propiedad BorderStyle Height y Width HelpContext Left y Top TabOrder y TabStop Descripción Para diferenciar al componente del formulario o integrarlo en su fondo. aunque se usan frecuentemente. no están disponibles para todos los componentes. Para asociar un número de índice de un fichero de ayuda a un componente. Para establecer el order de tabulación y determinar si el componente forma o no parte de la secuencia de tabulación. Otras propiedades de uso corriente.

Devuelve verdad si el componente puede recibir el foco (si las propiedades Visible y Enabled están a verdad).Propiedades. Ambos métodos modifican la propiedad Visible. métodos y eventos Hide() y Show() Invalidate().html (4 of 5) [27/02/2003 16:24:07] . Redibujar un componente. Refresh().TComponent . Eventos de los componentes. Eventos asociados a la pulsación de alguna tecla. Left. Establece simultáneamente los valores de las propiedades Top. Width y Height. Evento Descripción file:///D|/Manuales/appendix/tcomponent. Repaint() y Update() SetBounds() SetFocus() CanFocus() Hide() oculta el componente. 3. Puede volver a hacerse visible posteriormente con Show(). Sitúa el foco sobre un componente y lo convierte en el componente activo. Una acción puede desencadenar varios eventos y el orden en ocurren puede ser muy importante: Eventos asociados al movimiento y pulsación con el ratón.

el PaintBox no se verá en tiempo de ejecución. métodos y eventos OnMouseDown. OnMouseMove. cuando se pincha con él sobre el componente. OnClick y OnDblClick OnEnter ocurre cuando se activa un componente (recibe el foco) siempre que el foco se transfiera desde otro componente del mismo formulario. OnEnter y OnExit OnExit ocurre cuando el componente pierde el foco. este gestor se encargará de dibujar sobre el Canvas y si no se proporciona este gestor. OnPaint Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tcomponent. Para responder a los eventos que suceden al mover el ratón o OnMouseUp. siempre que el foco se transfiera a otro componente del mismo formulario.TComponent . Si el objeto es un PaintBox. OnKeyUp y OnKeyPress Para responder a los eventos que suceden al pulsar alguna tecla cuando el foco está en un componente. OnKeyDown.html (5 of 5) [27/02/2003 16:24:07] .Propiedades. Este evento ocurre cuando un objeto tiene que ser redibujado.

hpp> #include <Controls. TLabel *LabelOutput.h.html (1 of 2) [27/02/2003 16:24:07] . private: // User declarations public: // User declarations __fastcall TMainForm(TComponent* Owner). void __fastcall OKButtonClick(TObject *Sender). TCheckBox *CheckBox. observar el contenido del fichero que C++ Builder crea como fichero de declaración del formulario. TRadioButton *RadioButton2.hpp> #include <StdCtrls. //-----------------------------------------------------------------------file:///D|/Manuales/appendix/tip/tip_name. //-------------------------------------------------------------------------extern PACKAGE TMainForm *MainForm. void __fastcall CheckBoxClick(TObject *Sender). void __fastcall FormCreate(TObject *Sender). void __fastcall ExitButtonClick(TObject *Sender).hpp> #include <Forms.h: //-------------------------------------------------------------------------#ifndef mainH #define mainH //-------------------------------------------------------------------------#include <Classes. Recordar que el formulario principal se llamó. TEdit *Edit. TRadioButton *RadioButton1.hpp> //-------------------------------------------------------------------------class TMainForm : public TForm { __published: // IDE-managed Components TLabel *LabelEdit. MainForm. TButton *ExitButton. TButton *OKButton. si retomamos el ejemplo inicial de este curso (proyecto Inicial). En main. main.Propiedad Name Curso de C++ Builder Sobre la propiedad Name A modo de ejemplo. finalmente. }.

. por ejemplo. } //-------------------------------------------------------------------------- Accedemos a la propiedad Checked de RadioButton1 mediante el operador -> porque RadioButton1 es un puntero.cpp nos referimos a este componente usando el valor de la propiedad Name de la siguiente manera: //-------------------------------------------------------------------------void __fastcall TMainForm::OKButtonClick(TObject *Sender) { if (RadioButton1->Checked) { if (Edit->Text == "") LabelOutput->Caption = "Escogió Opción 1. . al primer botón de radio se le asignó el valor RadioButton1 a su propiedad Name. Sr/Sra. Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tip/tip_name.. En el listado anterior..html (2 of 2) [27/02/2003 16:24:07] ..Propiedad Name --#endif Observar que. desconocido/a".. RadioButton1 es un puntero a un objeto de tipo TRadioButton. En main.

file:///D|/Manuales/intro/ejemplos/pizarra/index. Guardar (File | Save As) la unidad asociada al formulario (Unit1.bpr. una nueva aplicación ( File | New Applicaction). 1. 4. Para más información. crear el directorio Pizarra y. Ahora podemos construir el ejecutable y probarlo: seleccionar Project | Build Pizarra y a continuación.bpr. si procede. 2. pinchar el siguiente enlace: En primer lugar. Guardar (File | Save Project As) el proyecto (Project1. Crear y configurar el proyecto. 2. cambiar la propiedad Caption por PIZARRA y la propiedad Name por MainForm. Dar un nombre a la aplicación y fijar un icono (Project | Options | Application). Configurar el formulario principal. por defecto) como Pizarra. Dar como título: PIZARRA y seleccionar un icono.cpp. Run | Run.Ejemplos . por defecto) como FuncsPizarra. Observar que Unit1.html (1 of 4) [27/02/2003 16:24:07] . Cambiar el nombre y título del formulario principal: Con el inspector de objetos.Pizarra Curso de C++ Builder Pizarra 1.cpp.h 3.h ha cambiado automáticamente a FuncsPizarra.

Kind = bkClose y Caption = &Salir. 3. Debajo del Bevel. file:///D|/Manuales/intro/ejemplos/pizarra/index. Escribir el código. Style = bsLowered y Height = 8. Fijar las siguientes propiedades: Name = ExitBtn. 3. centrado horizontalmente un componente BitBtn (solapa Additional). alineado en lo alto. Fijar las propiedades Name = PaintBox. Align = alTop. En la parte superior. 2.Pizarra El formulario principal deberá tener el siguiente aspecto: Fijar manualmente el tamaño a 300 X 400 (Height = 300 y Width = 400). Contiene 3 componentes: 1.Ejemplos . Align = alTop y Height = 225.html (2 of 4) [27/02/2003 16:24:07] . Debajo del PaintBox un componente Bevel (solapa Additional). un componente PaintBox (solapa System). Fijar las siguientes propiedades: Name = Linea.

150). PaintBox->Canvas->Ellipse (100.Ejemplos .Pizarra En primer lugar. y tras seleccionar la pestaña Events haremos doble click en el gestor del evento OnClick. 100. } //----------------------------------------------------------- Finalmente. PaintBox->Canvas->Rectangle (200. // Dibujar un cuadrado PaintBox->Canvas->Pen->Color = clRed. PaintBox->Canvas->Brush->Color = clRed. y tras seleccionar la pestaña Events haremos doble click en el gestor del evento OnPaint. PaintBox->Canvas->Brush->Color = clYellow. 250. 150. escribiremos el código asociado al evento OnClick del componente BitBtn (ExitBtn). 150). escribiremos el código asociado al evento OnPaint del componente PaintBox. file:///D|/Manuales/intro/ejemplos/pizarra/index. 100. Seleccionar en el inspector de objetos dicho componente. Generar el ejecutable. } //----------------------------------------------------------- 4.html (3 of 4) [27/02/2003 16:24:07] . El gestor de este evento quedará como sigue: //----------------------------------------------------------- void __fastcall TMainForm::PaintBoxPaint(TObject *Sender) { // Dibujar un circulo PaintBox->Canvas->Pen->Color = clBlack. El gestor de este evento quedará como sigue: //----------------------------------------------------------- void __fastcall TMainForm::ExitBtnClick(TObject *Sender) { Application->Terminate(). Seleccionar en el inspector de objetos dicho componente.

Run | Run.html (4 of 4) [27/02/2003 16:24:07] . El resultado de la ejecución será el siguiente: Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/pizarra/index.Ejemplos .Pizarra Ahora podemos construir el ejecutable y probarlo: seleccionar Project | Build Pizarra y a continuación.

Ejecutar el programa make para que interprete el fichero makefile y desencadene las órdenes oportunas para la creación del ejecutable.Estructura y configuración de un proyecto de C++ Builder Curso de C++ Builder Estructura y configuración de un proyecto Estructura habitual de un proyecto escrito en C++ Una aplicación escrita en C++ se compone de un módulo (fichero) que contiene la función main() y. Para la creación de un ejecutable se requiere: 1. Un fichero makefile en el que se especifica la dependencia entre los diferentes módulos y la manera en la que se generan los módulos objeto. 2. opcionalmente. file:///D|/Manuales/appendix/project/index. Para este trabajo estructura los ficheros asociados a una aplicación en un proyecto. de una serie de módulos adicionales que pueden contener declaraciones de clases.bpr (Borland Project). Ficheros de proyecto en C++ Builder En C++ Builder la gestión de proyectos software se realiza automáticamente y el usuario no necesita construir el fichero makefile ni ejecutar make para obtener el ejecutable: C++ Builder se encarga de todo ésto. de acuerdo a lo especificado en el fichero makefile. bibliotecas y el ejecutable final. Se puede decir que un fichero de proyecto es un fichero makefile. declaraciones de funciones (prototipos). etc. La extensión de estos ficheros es .html (1 of 4) [27/02/2003 16:24:08] . definiciones de clases.

h. Cómo configurar un proyecto en C++ Builder El primer consejo es que cada aplicación debería estar en un directorio propio donde se guardarán todos los ficheros asociados a la aplicación.Estructura y configuración de un proyecto de C++ Builder Ejemplo. seleccionar Project | View Source). A modo de ejemplo. emplearemos el proyecto Inicial.h que contiene la declaración de los componentes que se incluyen en la ventana. Un módulo con extensión . Consiste en desarrollar una sencilla aplicación que consta de una única ventana. que se desarrolla en los seis ejercicios introductorios. file:///D|/Manuales/appendix/project/index.html (2 of 4) [27/02/2003 16:24:08] . q q Habitualmente no es preciso trabajar sobre este fichero. En aplicaciones que hacen uso de la VCL la función main() se llama WinMain() y se aloja en un fichero cuyo nombre coincide con el del proyecto. Ejemplo. los ficheros asociados a la ventana principal (y única) se llamarán main. para mostrar en el editor de código el fichero que contiene a la función WinMain(). Un módulo cabecera con extensión .bpr En todo proyecto existe un fichero que contiene la función principal. En este ejemplo. Para cada ventana existirán dos módulos adicionales: 1. 2. La función WinMain() se alojará en el fichero Inicial. cualquier aplicación contendrá al menos una ventana.cpp con el código asociado a esa ventana (usualmente contiene los gestores de los eventos que se pueden gestionar en esa ventana).cpp y main.cpp Además. Si fuera preciso. El proyecto se llamará Inicial. Ejemplo.

Unit1. Unit1. los gestores de los eventos que puede gestionar).bpr. A) Si se acaba de arrancar C++ Builder aparece.e.cpp. file:///D|/Manuales/appendix/project/index.bpr.h (especificacion de los componentes del formulario principal). Project1. por defecto: 1. Project1.cpp. Guardar ficheros asociados a ventanas (File | Save As) en el directorio adecuado para dar nombres significativos a los ficheros. Ejemplo. Puede comprobarse usando el gestor de proyectos (View | Project Manager). 2. fichero que contiene las funciones asociadas al formulario principal (constructor de la ventana y que posteriormente contendrá. fichero que contiene la función WinMain(). básicamente en proporcionar nombres significativos al proyecto y a los ficheros asociados al proyecto. Crear un directorio (p. B) Si existe un proyecto vigente. si se desea el proyecto vigente. Cambiar la propiedad Caption por Form de Prueba y la propiedad Name por MainForm. por defecto aparece un formulario vacío llamado Form1 asociado al proyecto Project1. Los pasos a seguir son los siguientes: 1.Estructura y configuración de un proyecto de C++ Builder Ejemplo. Ejercicio) para guardar los ficheros asociados al proyecto. Ahora se procede a configurar la aplicación. 3. 2. Cambiar el nombre y título del formulario principal utilizando el inspector de objetos. además. lo más cómodo es crear una nueva aplicación (File | New Application) salvando.html (3 of 4) [27/02/2003 16:24:08] . y 4. Consiste. fichero de proyecto. En cualquier caso se crean.

Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/project/index. Ejemplo. Selecionar Project | Options | Application.cpp ha cambiado automáticamente a Inicial. Comprobar que Inicial. (Observar que Project1. Ejemplo. Guardar Unit1.cpp. Guardar Project1. Dar como título: Ejemplo inicial y seleccionar cualquier icono.bpr como Inicial. Dar un nombre a la aplicación y fijar un icono. Observar que el proyecto vigente se llama ahora Inicial. Guardar el proyecto: (File | Save Project As) en el directorio adecuado.h). Estos datos aparecerán al minimizar el programa durante su ejecución. (Unit1. 4.bpr tiene la estructura de un fichero makefile.html (4 of 4) [27/02/2003 16:24:08] .bpr.h cambia automáticamente a main. y que éste contiene a la función WinMain). Podemos comprobarlo desplegando el menú Project.cpp como main.cpp.Estructura y configuración de un proyecto de C++ Builder Ejemplo. 3.

6 4.5 4.5 4. Pizarra Controles de edición Editor Programación dirigida a objetos en C++Builder Ejemplo 0 Ejemplo 1 Ejemplo 2 Sección 2.2 file:///D|/Manuales/exercises.2 2.Ejercicios Curso de C++ Builder Índice de ejercicios Ejercicios introductorios Diseño de un formulario.2 3. Ejercicios adicionales Ejemplos de aplicaciones simples y de consola.2 2.2 5.2 5. Modificación y consulta de propiedades en tiempo de ejecución. Uso del inspector de objetos para escribir gestores de eventos con el editor de código.2 3.C++ Builder .5.6. Uso del inspector de objetos para modificar propiedades.2 3. Gestores de eventos.7.html (1 of 2) [27/02/2003 16:24:08] . Métodos asociados a componentes.5 Sección 5.2 Sección 2.

Ejercicios Ejemplo 3 Reproductor de sonidos Programación concurrente Ejemplos de programación con hebras q Creación de una hebra q Ejecución de una hebra q Control de la ejecución de una hebra q Coordinación entre hebras: Synchronize q Coordinación entre hebras: Bloqueo de objetos q Coordinación entre hebras: Secciones críticas q Sincronización entre hebras: TEvent Acceso a bases de datos Un componente 'data-aware' TDBDateTimePicker Un formulario Un diálogo de búsqueda genérico Una aplicación sencilla (Paradox) Gestión de una pequeña base de datos culinaria Una aplicación algo más compleja (InterBase) Diccionario de citas Ejercicio Desarrollo completo de una aplicación 6.html (2 of 2) [27/02/2003 16:24:08] .C++ Builder .5 Sección 7 Sección 8 Atrás file:///D|/Manuales/exercises.3 6.

1. Crear y configurar el proyecto: Para más información.1 Figura E1.html (1 of 2) [27/02/2003 16:24:09] . Colocar componentes en un formulario y redimensionarlo para que quede (aproximadamente) como se indica en la figura E1. pinchar el siguiente enlace: 1. Todos los componentes necesarios para realizar este ejemplo se encuentran en la página de componentes Standard. 2. Diseñar este formulario. file:///D|/Manuales/intro/ejemplos/ej1.Ejercicio 1. Diseño de un formulario Curso de C++ Builder Ejercicio 1. Directorio: Ejercicio. Diseño de un formulario 1.

Diseño de un formulario 2. 3. 4. 3.html (2 of 2) [27/02/2003 16:24:09] .cpp. Generar el ejecutable: Seleccionar Project | Build. Ejecutar el "programa": Seleccionar Run | Run. Unidad asociada al formulario (Unit1. Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/ej1.bpr.cpp.bpr. Proyecto (Project1. por defecto): main. por defecto): Inicial.Ejercicio 1.

El formulario de la figura 6 modificado.Ejercicio 2. al texto que aparece sobre un botón).1. Las modificaciones se realizarán usando el Inspector de Objetos (pestaña Properties). En la lista siguiente se detallan las modificaciones a realizar. Figura E2. básicamente. Al ser un identificador (como un nombre de variable. Uso del inspector de objetos para modificar propiedades Curso de C++ Builder Ejercicio 2. por file:///D|/Manuales/intro/ejemplos/ej2. Name: Se refiere al nombre con el que se va a referenciar al componente desde el programa. Uso del inspector de objetos para modificar propiedades Cambiar el formulario diseñado en el ejercicio 1 para que tenga el aspecto que se indica en la figura E2. se trata de modificar los valores de las propiedades Caption y Name: q q Caption: Se refiere al título o leyenda que acompaña a los componentes (por ejemplo. Observar que.html (1 of 3) [27/02/2003 16:24:09] .1.

Generar el ejecutable y ejecutar el "programa". RadioButton2 : Caption = Opción 2 y Name = RadioButton2. Font Style = Bold. Por defecto. Size = 10 y Color = Marine.Ejercicio 2. Figura E2. file:///D|/Manuales/intro/ejemplos/ej2. Label2 : Dejar vacío el valor de Caption y Name = LabelOutput. Button2 : Caption = Salir y Name = ExitButton. El resultado se muestra en la figura E2. C++ Builder emplea la propiedad Name del componente para denominar al puntero. Cuando se coloca un componente en un formulario.2. CheckBox1 : Caption = Activar opciones. por ejemplo. Name = CheckBox y Checked = true.2. C++ Builder crea un puntero al componente en la declaración del formulario (fichero main. Edit1 : Dejar vacío el valor de Text y Name = Edit. Name = OKButton y Enabled = false.h en este ejemplo) y gracias a ello se puede acceder al componente a través del código. Así.html (2 of 3) [27/02/2003 16:24:09] . C++ Builder asigna nombres como Button1 y Button2 y es conveniente asignarles otros más clarificadores como OKButton o ExitButton. Resultado de la ejecución tras modificar propiedades en tiempo de diseño. Button1 : Caption = OK. RadioButton1 : Caption = Opción 1 y Name = RadioButton1. Uso del inspector de objetos para modificar propiedades ejemplo) debe ser significativo. las modificaciones a realizar son las siguientes: q q q q q q q q q Form1 : Caption = Form de Prueba y Name = MainForm. Label1 : Caption = Nombre y Name = LabelEdit. Activar el cuadro de diálogo asociado a la propiedad Font y establecer los siguientes valores: Font = MS Serif.

Ejercicio 2. Uso del inspector de objetos para modificar propiedades Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/ej2.html (3 of 3) [27/02/2003 16:24:09] .

el programa deja de ejecutarse.Ejercicio 3. file:///D|/Manuales/intro/ejemplos/ej3. Se trata de que al pinchar sobre este botón la aplicación termine su ejecución. hacer doble click en OnClick. generar el ejecutable y ejecutar el programa: al hacer click sobre el botón de salir. Uso del inspector de objetos para escribir gestores de eventos con el editor de código Vamos a construir el gestor del evento que se genera al hacer click sobre el botón de salir. Seleccionar el componente ExitButton y en la pestaña Events del inspector de objetos. } //------------------------------------------------------------ Ahora. Uso del inspector de objetos para escribir gestores de eventos con el editor de código Curso de C++ Builder Ejercicio 3. generado automáticamente: //-----------------------------------------------------------void __fastcall TMainForm::ExitButtonClick(TObject *Sender) { } //------------------------------------------------------------ Escribir el siguiente código: //-----------------------------------------------------------void __fastcall TMainForm::ExitButtonClick(TObject *Sender) { Application->Terminate(). El editor de código muestra el siguiente código.html (1 of 2) [27/02/2003 16:24:09] .

Ejercicio 3.html (2 of 2) [27/02/2003 16:24:09] . Uso del inspector de objetos para escribir gestores de eventos con el editor de código Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/ej3.

html (1 of 6) [27/02/2003 16:24:10] . Aplicaciones de consola.Ejemplos . Veamos cómo. ejecutándose sobre una consola MS-DOS. En cualquier caso. y el aspecto de una aplicación de este tipo es el generado por los compiladores "tradicionales". Una aplicación de consola no utiliza los objetos de la VCL. indicar que se va a crear una aplicación de consola (Console). Seleccionar File | New | Console Wizard y en el asistente. El editor de código aparece de la siguiente manera: Observar que el editor de código no presenta las líneas necesarias para la inclusión de las file:///D|/Manuales/intro/ejemplos/simples/index. Una aplicación de consola se crea usando el asistente Console Wizard.Aplicaciones simples Curso de C++ Builder Ejemplos de aplicaciones simples 1. C++ Builder permite la creación de este tipo de aplicaciones.

bpr como Console.bpr. Seleccionar File | Save Project As y guardar Project1. al contrario que ocurre en las aplicaciones "visuales".h> #include <iostream. char* argv[]) { for (int i=0. El resultado de la ejecución será el siguiente: file:///D|/Manuales/intro/ejemplos/simples/index. Ahora podemos construir el ejecutable y probarlo: seleccionar Project | Build Console y a continuación. Escribir el siguiente código: #pragma hdrstop #include <condefs. return 0. Run | Run.h> //----------------------------------------------------------- #pragma argsused int main(int argc. i<5.Aplicaciones simples definiciones de objetos de la VCL y la función principal es la conocida main().h> #include <conio. getch(). } //----------------------------------------------------------- Finalmente. donde ésta se llama WinMain().Ejemplos .html (2 of 6) [27/02/2003 16:24:10] . guardar el proyecto y ejecutar el programa. i++) cout << "Valor de i = " << i << endl.

h del proyecto vigente.Ejemplos . Activar el formulario y a continuación seleccionar Project | Remove from project. Aplicaciones visuales sencillas. LPSTR.cpp como Unit1. return 0. El primer paso es crear una aplicación de la manera usual: Seleccionar File | New Application.Aplicaciones simples 2. 1. int) { ShowMessage ("Hola"). HINSTANCE.bpr. Seleccionar File | Save Project As y guardar Project1. Run | Run.html (3 of 6) [27/02/2003 16:24:10] . Ahora podemos construir el ejecutable y probarlo: seleccionar Project | Build Saludo y a continuación. seleccionar Project | View Source y escribir el siguiente código: //----------------------------------------------------------- #include <vcl. Como la aplicación no tendrá un formulario y por defecto se asocia uno a la aplicación debemos borrarlo. } //----------------------------------------------------------- Finalmente.cpp tiene asociado el formulario principal Form1. Para escribir el código del programa. Unit1.h> //----------------------------------------------------------- WINAPI WinMain(HINSTANCE. El resultado de la ejecución será el siguiente: file:///D|/Manuales/intro/ejemplos/simples/index. guardar el proyecto y ejecutar el programa. En este ejemplo escribiremos un programa que lanza una ventana de mensaje con un saludo. Ejemplo 1: Saludo. Pueden construirse aplicaciones visuales (hacen uso de la VCL) sin necesidad de usar el diseñador de formularios. Confirmar el borrado y de esta forma se eliminan tanto Unit1.bpr como Saludo.

. Ejemplo 2: Ciclo (múltiples ventanas secuenciales). seleccionar Project | View Source y escribir el siguiente código: //----------------------------------------------------------- #include <vcl. LPSTR. de forma que en cada iteración aparece una sóla ventana. para escribir el código del programa.Ejemplos . Finalmente. Activar el formulario para eliminarlo del proyecto: seleccionar Project | Remove from project. Quinta iteración file:///D|/Manuales/intro/ejemplos/simples/index. .html (4 of 6) [27/02/2003 16:24:10] . Para pasar a la siguiente iteración hay que pulsar el botón OK.i++){ ShowMessage ("Valor de i = " + AnsiString(i)).i<5 . construir el ejecutable (Project | Build Ciclo) y ejecutarlo Run | Run). será el siguiente. Primera iteración Segunda iteración . . } //----------------------------------------------------------- Guardar el proyecto (File | Save Project As) llamándolo Ciclo. HINSTANCE.bpr.h> //----------------------------------------------------------- WINAPI WinMain(HINSTANCE. Este programa presenta los valores guardados en un vector en una ventana de mensajes (recordar el ejemplo anterior). Como antes. en primer lugar se crea una aplicación: Seleccionar File | New Application. . . en cada iteración. presentando cada valor individualmente. } return 0.Aplicaciones simples 2. El resultado de la ejecución. int) { for (int i=0 .

int) { int *vector.. return 0. i++) { vector[i] = i*2. Se procede como en los dos casos anteriores. HINSTANCE. El código que escribiremos es el siguiente: //----------------------------------------------------------- #include <vcl.. LPSTR. Ejemplo 3: Resultado compuesto en una única ventana. y llamaremos al proyecto Vector..bpr.Ejemplos .. delete []vector. AnsiString cadena = "". 3. cadena = cadena + "vector[" + AnsiString (i) + "] = " + AnsiString (vector[i]) + "\n".. En este ejemplo se crea un vector dinámico de 5 enteros y se muestra su contenido en una única ventana. i<5.html (5 of 6) [27/02/2003 16:24:10] . } file:///D|/Manuales/intro/ejemplos/simples/index.Aplicaciones simples . vector = new int[5].h> //----------------------------------------------------------- WINAPI WinMain(HINSTANCE. } ShowMessage (cadena). for (int i=0.

Aplicaciones simples //----------------------------------------------------------- La ejecución de este programa produce el siguiente resultado: Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/simples/index.html (6 of 6) [27/02/2003 16:24:10] .Ejemplos .

por defecto) como Edicion. Observar que Unit1.h ha cambiado automáticamente a FuncsEdicion. Crear y configurar el proyecto.html (1 of 5) [27/02/2003 16:24:10] . Run | Run. Ahora podemos construir el ejecutable y probarlo: seleccionar Project | Build Edicion y a continuación. Para más información. Cambiar el nombre y título del formulario principal: Con el inspector de objetos. 2.h 3. una nueva aplicación ( File | New Applicaction). 2.bpr. si procede. pinchar el siguiente enlace: En primer lugar.cpp. cambiar la propiedad Caption por Controles de edición y la propiedad Name por MainForm. El formulario principal debe tener el siguiente aspecto: file:///D|/Manuales/intro/ejemplos/controles/index. 4. Dar un nombre a la aplicación y fijar un icono (Project | Options | Application). Dar como título: Controles de Edición y seleccionar un icono.bpr.Ejemplos . Configurar el formulario principal. crear el directorio Edicion y. por defecto) como FuncsEdicion.cpp.Una aplicación con componentes de edición Curso de C++ Builder Construcción de una aplicación con componentes de edición 1. 1. Guardar (File | Save As) la unidad asociada al formulario (Unit1. Guardar (File | Save Project As) el proyecto (Project1.

y dos botones BitBtn (solapa Additional). cambiar las propiedades de estas componentes prestando especial cuidado al nombre (Name) de forma que los nombres queden como se indica en la figura: 3.Una aplicación con componentes de edición Contiene 8 componentes: tres Label (solapa Standard). Utilizando el inspector de objetos.html (2 of 5) [27/02/2003 16:24:10] . Configurar el formulario secundario. Este formulario tiene un único componente Label llamada Label. tres Edit (solapa Standard). Añadir un nuevo formulario al proyecto: seleccionar File | New Form y fijar Name =SaludoBox y Caption= Cuadro de salutación. El aspecto del formulario será el siguiente: file:///D|/Manuales/intro/ejemplos/controles/index.Ejemplos .

} } //----------------------------------------------------------- 5. SaludoBox->Show().Ejemplos . EditApellido2->Text = "". Escribir el código. EditApellido1->Text = "". En este caso. 4. EditNombre->SetFocus().h). " + EditNombre->Text + " " + EditApellido1->Text + " " + EditApellido2->Text.cpp(observar que Unit1.ya que file:///D|/Manuales/intro/ejemplos/controles/index. EditNombre->Text = "". Seleccionar en el inspector de objetos dicho componente. todo hay que decirlo . Ahora podemos construir el ejecutable y probarlo: seleccionar Project | Build Edicion y a continuación. Seleccionar File | Save ally guardar Unit1.muy habitual.html (3 of 5) [27/02/2003 16:24:10] . la pestaña Events y hacer doble click el gestor del evento OnClick. "Error en la entrada de datos". El gestor de este evento quedará como sigue: //----------------------------------------------------------- void __fastcall TMainForm::BotonOKClick(TObject *Sender) { if (EditNombre->Text == "" || EditApellido1->Text == "" || EditApellido2->Text == "" ) { Application->MessageBox ( "Debe especificar todos los campos". Observar que se produce un error de compilación .Una aplicación con componentes de edición Guardar el formulario (con los ficheros asociados).hcambia a Saludo. MB_OK). sólo se escribirá código para el evento OnClick del componente BotonOK del formulario principal. Generar el ejecutable. Run | Run. } else { SaludoBox->Label->Caption = "Bienvenido.cppcomo Saludo.

Volver a generar el ejecutable y ejecutar el programa. Resulta poco profesional que la única posibilidad de cerrar un formulario sea pinchar sobre el botón del aspa situado en el marco de una ventana.h".Una aplicación con componentes de edición no se puede encontrar la definición de SaludoBox.h.cpp observaremos que este fichero no incluye a Saludo. se produce el siguiente resultado: 6.cpp. objeto que es usado en FuncsEdicion. Ejercicios adicionales. Como ejemplo de ejecución. 2.html (4 of 5) [27/02/2003 16:24:10] . file:///D|/Manuales/intro/ejemplos/controles/index. si miramos FuncsEdicion. De hecho. si el usuario introduce los siguientes datos en las líneas de edición: Al pulsar el botón de confirmación.cpp.Ejemplos . Añadir al formulario secundario un botón para cerrarlo. Observar que se añade la línea #include "Saludo. seleccionar File | Include Unit Hdr y seleccionar Saludo. 1. Estando activo en el editor de código FuncsEdicion. Modificar el código asociado al método BotonOKClick de manera que la ventana de saludo se ejecute modalmente.

Ejemplos .html (5 of 5) [27/02/2003 16:24:10] .Una aplicación con componentes de edición Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/controles/index.

Añadir un nuevo formulario (Acerca de . y el alumno puede añadirle más funcionalidad. Mostramos diversas técnicas para añadir menús y submenús y cómo incorporar un menú cotextual. Este ejercicio se estructura como sigue: 1. a asociar nombres representativos a los ficheros descartando los que C++ Builder asocia por defecto.) file:///D|/Manuales/intro/ejemplos/editor/index. La aplicación que se va a presentar consiste en un editor de texto con bastante funcionalidad.html (1 of 15) [27/02/2003 16:24:12] .. lo que le permitirá ampliar sus conocimientos sobre programación de aplicaciones visuales con C++ Builder..Editor de texto Curso de C++ Builder Un sencillo editor de texto En este ejemplo se explica cómo crear rápidamente una aplicación para Windows con C++ Builder. Básicamente. Mostramos cómo crear un proyecto (conjunto de ficheros de programa y formularios asociados a una aplicación) y cómo configurarlo. Mostramos con profundidad cómo configurar un formulario. No debe entenderse que la aplicación presentada está cerrada. Añadir menús al formulario. 4. desde añadir una barra rápida hasta cuadros de diálogo. Escribir el código del programa. 3. 2. Configurar el formulario principal. En esta sección se presentan los componentes habituales de una aplicación Windows. Crear y Configurar el proyecto. Una vez diseñado el formulario hay que escribir el código C++ de los manipuladores de eventos asociados a los componentes 5.Ejemplos . más bien al contrario. aunque muy mejorable.

crear el directorio EjemploEditor y. pinchar el siguiente enlace: En primer lugar. Como referencia. una nueva aplicación ( File | New Applicaction). Cambiar el nombre y título del formulario principal: file:///D|/Manuales/intro/ejemplos/editor/index. Sobre la barra de estado y los cuadros de pista (Hints). Mostramos cómo añadir cuadros de pista a los botones rápidos y cómo mostrar información en la barra de estado. 6. Crear y configurar el proyecto. Para más información. tal como debe verse en el gestor de proyectos. 1.Ejemplos . esta es la estructura del proyecto que vamos vamos a crear.Editor de texto Aquí mostramos cómo se pueden añadir nuevos formularios. si procede. 1.html (2 of 15) [27/02/2003 16:24:12] .

r Crear un componente Bevel.bpr.h 3. por defecto) como FuncsEditor. Colocarlo sobre el formulario (no nos preocupamos de su tamaño ni de su alineación respecto al formulario).html (3 of 15) [27/02/2003 16:24:12] . Guardar (File | Save Project As) el proyecto (Project1. por defecto) como MiEditor.1. 2. fijar Name= Bevel.cpp. seleccionar la propiedad Lines y dejar limpio su contenido con el editor de cadenas. Guardar (File | Save As) la unidad asociada al formulario (Unit1. Guardar los ficheros: File | Save All 2. cambiar la propiedad Captionpor Mi editor de textoy la propiedad Namepor MainForm.2.h ha cambiado automáticamente a FuncsEditor. Configurar el formulario principal. Cambiar la propiedad Name por Memo. Run | Run.bpr. Height = 2 y alinearlo en lo alto (Align =alTop). 2. en la solapa Standard de la paleta de componentes. Agregar un componente Memo. 4. r Crear un panel para albergar los botones de la barra rápida. Agregar una barra rápida.Ejemplos . Seleccionar un componente Panel (solapa Standard) y colocarlo en algún file:///D|/Manuales/intro/ejemplos/editor/index. Seleccionar un componente Bevel (solapa Additional). Ahora podemos construir el ejecutable y probarlo: seleccionar Project | Build MiEditor y a continuación. Dar como título: Mi editor de texto 1.Editor de texto Con el inspector de objetos. Seleccionar. Observar que Unit1.cpp. Dar un nombre a la aplicación y fijar un icono (Project | Options | Application). 2.0 y seleccionar un icono. el componente Memo.

Editor de texto lugar del formulario. Para el botón Abrir Fichero: Seleccionar un componente SpeedButton (solapa Additional) y colocarlo en el panel.html (4 of 15) [27/02/2003 16:24:12] .bmp). salvar fichero y salir del programa. Se colocarán los botones para abrir fichero. Glyph: filesave. Glyph: dooropen.bmp. Fijar: s s s s s Name = SpeedBar Height = 32 BevelOuter = bvNone Caption = (Dejar en blanco) Align = alTop r Colocar los botones de acceso rápido de la barra rápida.bmp) y Salir (Name = ExitBtn. Cambiar las propiedades: s s s Name = FileOpenBtn Left = 4 Glyph: Pinchar dos veces en la propiedad Glyph y seleccionar el icono fileopen.Ejemplos . Repetir estos pasos para los botones Salvar Fichero (Name =FileSaveBtn. file:///D|/Manuales/intro/ejemplos/editor/index.

2. Seleccionar el componente Memo y fijar la propiedad Align= alClient. 2.Editor de texto 2.3. Agregar una barra de estado. por lo que el lugar file:///D|/Manuales/intro/ejemplos/editor/index. Seleccionar un componente StatusBar (solapa Win32). Estos son componentes no visuales.4. Reajustar el componente Memo. Añadir una barra de scroll vertical: cambiar la propiedad ScrollBars a ssVertical. Fijar Name = StatusBar.5.html (5 of 15) [27/02/2003 16:24:12] .Ejemplos . Añadir las componentes no visuales OpenDialog y SaveDialog Colocar en cualquier sitio del formulario los componentes OpenDialog y SaveDialog (solapa Dialogs).

añadiremos un menú principal (sección 3. crearemos un menú contextual (sección 3.5). construir el proyecto (Project | Build MiEditor) y ejecutarlo (Run | Run).1) junto con los submenús asociados: Ficheros (sección 3. El menú y los submenús son los típicos de las aplicaciones Windows.2). 3. El aspecto del formulario será el de la figura siguiente. respectivamente. Edición (sección 3.4). Cambiar las propiedades Name a OpenDialog y SaveDialog.html (6 of 15) [27/02/2003 16:24:12] . Finalmente. Los componentes no visuales OpenDialog y SaveDialog no se ven en tiempo de ejecución. Para crear el menú principal y los submenús. Guardar todos los ficheros del proyecto (File | Save All). seleccionar el componente no visual file:///D|/Manuales/intro/ejemplos/editor/index.Ejemplos .3 y Ayuda (sección 3. En primer lugar. Añadir menús al formulario.Editor de texto de ubicación no es importante.

A continuación. Diseño del menú principal. Menú Ficheros. 3. r r r Para el submenú Ficheros: Name=FileMenu y Caption=&Ficheros Para el submenú Edicion: Name=EditMenu y Caption=&Edicion Para el submenú Ayuda: Name=HelpMenu y Caption=&Ayuda 3. Fijar Name=MainMenu.2.html (7 of 15) [27/02/2003 16:24:12] . Edicion y Ayuda. diseñar el menú. Las cabeceras de los submenús serán: Ficheros. Deseamos que se abra un submenú asociado a cada una de estas categorías cuando se pinche con el ratón sobre éstas. file:///D|/Manuales/intro/ejemplos/editor/index.1.Editor de texto MainMenu (solapa Standard) y colocarlo en algún lugar del formulario. Se hará con el diseñador de menús: pinchar dos veces sobre el componente MainMenu.Ejemplos .

Menú Edición. (separador) y Salir. impresora: Name=FilePrintSetUp. Guardar.Editor de texto Añadir las opciones: Nuevo. Guardar: Name=FileSave y Caption= &Guardar. Imprimir. Guardar como: Name=FileSaveAs y Caption= Guardar &como. Guardar como. Abrir.Ejemplos .3. Caption=&Imprimir y Enabled=false. Para cada opción se procede como antes: r r r r r r r r r Nuevo: Name=FileNew y Caption=&Nuevo Abrir: Name=FileOpen y Caption= &Abrir.html (8 of 15) [27/02/2003 16:24:12] . Caption=Config&urar impresora y Enabled= false Incluir un separador: Caption = Salir: Name=FileExit y Caption=&Salir 3. Incluir un separador: Caption = Imprimir: Name=FilePrint. Configurar impresora. Conf. (separador). file:///D|/Manuales/intro/ejemplos/editor/index.

Caption=&Deshacer. Caption=P&egar y ShortCut=Ctrl+V. Caption=&Ajustar. ShortCut=Ctrl+Z Incluir un separador: Caption = Cortar: Name=EditCut. Seleccionar del menú principal la cabecera Edicion. A continuación. (separador). Pulsar el botón derecho del ratón y seleccionar Insert from Template | Edit Menu. Caption=&Reemplazar y Enabled=false Incluir un separador: Caption = Ajustar: Name=EditWordWrap. Reemplazar.Editor de texto Añadir las opciones: Deshacer. Pegar. Caption=&Copiar y ShortCut=Ctrl+C. (separador) y Ajustar.Ejemplos . Caption=C&ortar. Borrar la antigua cabecera Edicion.Cortar. y ShortCut=Ctrl+X. y Checked=true file:///D|/Manuales/intro/ejemplos/editor/index. Buscar. Copiar: Name=EditCopy. Reemplazar: Name=EditReplace. Camiar la nueva cabecera Edit para dejarla Name=EditMenu y Caption=&Edicion.html (9 of 15) [27/02/2003 16:24:12] . (separador). modificar el submenú Edicion para que quede: r r r r r r r r r r r Deshacer:Name=EditUndo. Seleccionat todo: Name=EditSelectAll. Este submenú se creará usando una plantilla de menú. Caption=Seleccionar &todo y ShortCut=Ctrl+A. Seleccionar todo. Copiar. Incluir un separador: Caption = Buscar: Name=EditFind. Caption=&Buscar y Enabled=false. Pegar: Name=EditPaste.

Solamente tendrá una opción: Acerca de .. Para crear el menú contextual. seleccionar el componente no visual PopUpMenu file:///D|/Manuales/intro/ejemplos/editor/index.Ejemplos . cerrar el diseñador de menús.html (10 of 15) [27/02/2003 16:24:12] .. Menú Ayuda.4.. Establecer las propiedades Name=HelpAbout y Caption=Ace&rca de . El aspecto del formulario será el siguiente: 3.Editor de texto 3. .5. Menú Contextual.. Finalmente.

Pegar: Name=PopUpPaste.. seleccionar el componente Memo.Editor de texto (solapa Standard) y colocarlo en algún lugar del formulario. (separador) y Acerca de. Se activa el editor de código.Ejemplos . El menú contextual puede asociarse a cualquier componente que tenga asociada la propiedad PopupMenu. Copiar: Name=PopUpCopy. Detallaremos cómo se hace el de la opción Ficheros | Salir. Caption=P&egar y ShortCut=Ctrl+V. : Name=PopUpAbout y Caption=Ace&rca de . Pegar. Todos los manipuladores de eventos se escriben con una metodología similar. mostrando el gestor que se va a completar: //-----------------------------------------------------------void __fastcall TMainForm::FileExitClick(TObject *Sender) { } //------------------------------------------------------------ file:///D|/Manuales/intro/ejemplos/editor/index. Añadir las opciones: Cortar. Copiar. Cada opción del menú y cada botón de la barra rápida debe tener asociada una acción. En este caso se asociará al componente Memo para que al pulsar el botón derecho del ratón se despliegue el menú que acabamos de crear. .. y los demás se completarán siguiendo las líneas aquí descritas.. de la misma manera que se ha hecho con el menú principal. Para esto. Incluir un separador: Caption = Acerca de .. Escribir el código del programa. La acción se asocia a cada componente mediante el gestor de eventos del inspector de objetos. 4. Fijar Name=PopUpMenu.html (11 of 15) [27/02/2003 16:24:12] . y ShortCut=Ctrl+X. acceder a la propiedad PopupMenu y seleccionar PopUpMenu (el único disponible). Para cada opción: r r r r r Cortar: Name=PopUpCut. Seleccionar Ficheros | Salir del menu principal. Caption=C&ortar. Este menú se diseñará con el diseñador de menús. Caption=&Copiar y ShortCut=Ctrl+C.

seleccionar el componente ExitBtn en el inspector de objetos.Ejemplos . el resultado final debe ser: r Opción: Ficheros | Nuevo Opción: Ficheros | Abrir y botón rápido FileOpenBtn Opción: Ficheros | Guardar y botón rápido FileSaveBtn Opción: Ficheros | Guardar como Opción: Edición | Deshacer Opción: Edición | Cortar y Cortar del menú contextual. desplegar la lista de funciones pulsando sobre la flecha que aparece a la derecha del evento OnClick (ahora sólo está FileExitClick()) y seleccionarla.Editor de texto Completar la función de la siguiente forma: //-----------------------------------------------------------void __fastcall TMainForm::FileExitClick(TObject *Sender) { Application->Terminate(). Opción: Edición | Copiar y Copiar del menú contextual. Para seleccionar una de las funciones ya escritas. Así. Dicho de otra forma. Opción: Edición | Pegar y Pegar del menú contextual. le asignamos las misma función al evento OnClick. pulsar en la pestaña Events y en en evento OnClick. Para ello.html (12 of 15) [27/02/2003 16:24:12] . Para cada opción. } //------------------------------------------------------------ Como el botón rápido para salir ExitBtn debe realizar la misma tarea. Opción: Edición | Seleccionar todo r r r r r r r r file:///D|/Manuales/intro/ejemplos/editor/index. la función FileExitClick() se activa desde Ficheros | Salir y desde el botón rápido ExitBtn. proceder de la misma forma.

Name = AboutBox y BorderStyle = bsDialog y configurarlo: 1. Crear un marco que englobe a los tres componentes Label. Añadir un botón de OK.0. Corresponde al componente BitBtn (solapa Additional).Editor de texto r Opción: Edición | Ajustar 5. Versión 1. diseñar una ventana modal titulada Acerca de Mi editor de texto con el siguiente aspecto: Fijar las propiedades del formulario Caption = Acerca de Mi editor de texto.) Seleccionar File | New Form. 4. Añadir un nuevo formulario (Acerca de. Sobre este formulario. 2.. Para este componente. 3. file:///D|/Manuales/intro/ejemplos/editor/index. Añadir un icono (el mismo que se asoció a la aplicación) seleccionando un componente Image (solapa Additional). fijar Autosize = true.Ejemplos . respectivamente.html (13 of 15) [27/02/2003 16:24:12] .. y © Curso de Programación Visual. Añadir tres componentes Label (solapa Standard) con textos (Caption): Mi editor de texto. Fijar Kind = bkOK. Seleccionar el componente Bevel (solapa Additional) y enmarcar el texto. Fijar Shape = bsFrame.

Seleccionar File | Save y darle el nombre About. éste se especifica también en la misma propiedad separado por la barra |. construir el proyecto y ejecutar. Salvar. 6.. Observar que al poner el cursor sobre el botón se muestra el cuadro de pista pero no en la barra de estado.. Se puede asociar a cada componente un cuadro de pista (Hint) fijando al valor de su propiedad Hint al texto que se quiere mostrar. Por ejemplo. en el menú contextual debe abrirse la ventana que hemos creado.. cuando se seleccione Ayuda | Acerca de .. El código que abre esta ventana se completa como sigue: seleccionar la opción Ayuda | Acerca de . Si se desea que aparezca un texto más amplio en la barra de estado.Ejemplos . Ahora. Seleccionar About. o Acerca de . Sobre la barra de estado y los cuadros de pista (Hints)..cpp Añadir esta unidad al proyecto.cpp y File | Include Unit Hdr.. construir el proyecto y ejecutarlo. y completar el manipulador HelpAboutClick() de la siguiente forma: //----------------------------------------------------------- void __fastcall TMainForm::HelpAboutClick(TObject *Sender) { AboutBox->ShowModal().Editor de texto Almacenar la unidad. seleccionar el botón FileOpenBtn y fijar la propiedad Hint a Abrir fichero | Abrir un fichero existente y fijar ShowHint = true.html (14 of 15) [27/02/2003 16:24:12] . Finalmente. Modificar las propiedades Hint de los botones FileSaveBtn y ExitBtn fijándolas a Guardar fichero | Guardar en un fichero el texto mostrado y file:///D|/Manuales/intro/ejemplos/editor/index. } //----------------------------------------------------------- Asignar la misma función al gestor del evento OnClick de PopUpAbout. Seleccionar FuncsEditor.

Editor de texto Salir | Terminar la ejecución del programa. salvar.html (15 of 15) [27/02/2003 16:24:12] . construir el proyecto y ejecutar. y fijar para ambos ShowHint = true. Finalmente.Ejemplos . respectivamente. Para que aparezca el texto largo en la barra de estado basta con establecer la propiedad AutoHint de la barra de estado a true. Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/index.

guardar el archivo actual. file:///D|/Manuales/intro/ejemplos/editor/fich_nuevo. } // Borrar el contenido de Memo. // Si se pulsa CANCEL. SaveDialog->FileName = "". MB_YESNOCANCEL). // Sustituir el valor de la propiedad FileName del cuadro // de dialogo Save por espacios en blanco. no hacer nada. ¿Salvar los cambios?". int result = Application->MessageBox( "El fichero activo ha cambiado. "!Cuidado!". // Si se pulsa YES. if (result == IDYES) FileSaveClick(Sender).html (1 of 2) [27/02/2003 16:24:12] . if (result == IDCANCEL) return.Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Ficheros | Nuevo //---------------------------------------------------------void __fastcall TMainForm::FileNewClick(TObject *Sender) { // Abre un nuevo fichero. if (Memo->Modified) { // Mostrar un cuadro de mensaje. Asi se sabe // que el fichero no se ha guardado aun. si lo hay. Primero hay que verificar // que el fichero actual tiene que guardarse.Ejemplos . if (Memo->Lines->Count > 0) Memo->Clear().

html (2 of 2) [27/02/2003 16:24:12] .Editor de texto } //----------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/fich_nuevo.Ejemplos .

Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Ficheros | Abrir y botón FileOpenBtn //---------------------------------------------------------void __fastcall TMainForm::FileOpenClick(TObject *Sender) { // Abrir un fichero.Ejemplos . file:///D|/Manuales/intro/ejemplos/editor/fich_abrir. int result = Application->MessageBox( "El fichero activo ha cambiado. ¿Salvar los cambios?". Igual que en FileNewClick() if (Memo->Modified) { // Mostrar un cuadro de mensaje.html (1 of 3) [27/02/2003 16:24:12] . Verificar en primer lugar si hay que // salvar el archivo actual.

si lo hay. if (result == IDYES) FileSaveClick(Sender). file:///D|/Manuales/intro/ejemplos/editor/fich_abrir. // Si se pulsa CANCEL. } // Abrir el cuadro de diálogo File Open. if (result == IDCANCEL) return. if (Memo->Lines->Count > 0) Memo->Clear(). OpenDialog->FileName = "". // Si se pulsa YES. no hacer nada.html (2 of 3) [27/02/2003 16:24:12] .Editor de texto "!Cuidado!". if (OpenDialog->Execute()) { // Borrar el contenido de Memo. MB_YESNOCANCEL).Ejemplos . guardar el archivo actual.

html (3 of 3) [27/02/2003 16:24:12] . Memo->Lines->LoadFromFile(OpenDialog->FileName). } } //---------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/fich_abrir. SaveDialog->FileName = OpenDialog->FileName.Editor de texto // Leer el fichero a Memo.Ejemplos .

if (SaveDialog->FileName != "") { Memo->Lines->SaveToFile(SaveDialog->FileName).Ejemplos . file:///D|/Manuales/intro/ejemplos/editor/fich_guardar.Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Ficheros | Guardar y botón FileSaveBtn //----------------------------------------------------------- void __fastcall TMainForm::FileSaveClick(TObject *Sender) { // Si ya se ha especificado un nombre de fichero no es // necesario abrir el cuadro de diálogo Guardar Fichero.html (1 of 2) [27/02/2003 16:24:13] . // Solo hay que guardarlo con SaveToFile().

} //----------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/fich_guardar. else FileSaveAsClick(Sender).html (2 of 2) [27/02/2003 16:24:13] . } // Si no se ha dado un nombre. ejecutar SaveAs().Ejemplos .Editor de texto // Establecer ahora la propiedad Modified a FALSE. Memo->Modified = false.

Ejemplos . if (SaveDialog->Execute()) { Memo->Lines->SaveToFile(SaveDialog->FileName).Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Ficheros | Guardar como //----------------------------------------------------------- void __fastcall TMainForm::FileSaveAsClick(TObject *Sender) { SaveDialog->Title = "Save As".html (1 of 2) [27/02/2003 16:24:13] . } file:///D|/Manuales/intro/ejemplos/editor/fich_guardar_como. Memo->Modified = false.

html (2 of 2) [27/02/2003 16:24:13] .Editor de texto } //----------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/fich_guardar_como.Ejemplos .

Ejemplos .Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Edición | Deshacer //----------------------------------------------------------- void __fastcall TMainForm::EditUndoClick(TObject *Sender) { Memo->Undo().html (1 of 2) [27/02/2003 16:24:13] . // Llamada a TMemo->Undo() } //----------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/editor/edic_deshacer.

Editor de texto Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/edic_deshacer.Ejemplos .html (2 of 2) [27/02/2003 16:24:13] .

//----------------------------------------------------------- void __fastcall TMainForm::EditCutClick(TObject *Sender) { Memo->CutToClipboard(). // Llamada a TMemo->CutToClipboard() } //----------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/editor/edic_cortar.html (1 of 2) [27/02/2003 16:24:13] .Ejemplos .Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Edición | Cortar y Cortar del menú contextual.

Ejemplos .Editor de texto Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/edic_cortar.html (2 of 2) [27/02/2003 16:24:13] .

//Llamada a TMemo->CopyToClipboard() } //----------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/editor/edic_copiar.Ejemplos .html (1 of 2) [27/02/2003 16:24:14] .Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Edición | Copiar y Copiar del menú contextual. //----------------------------------------------------------- void __fastcall TMainForm::EditCopyClick(TObject *Sender) { Memo->CopyToClipboard().

Editor de texto Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/edic_copiar.Ejemplos .html (2 of 2) [27/02/2003 16:24:14] .

// TMemo->PasteFromClipboard() } //----------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/editor/edic_pegar.Ejemplos .html (1 of 2) [27/02/2003 16:24:14] .Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Edición | Pegar y Pegar del menú contextual. //----------------------------------------------------------- void __fastcall TMainForm::EditPasteClick(TObject *Sender) { Memo->PasteFromClipboard().

Editor de texto Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/edic_pegar.Ejemplos .html (2 of 2) [27/02/2003 16:24:14] .

html (1 of 2) [27/02/2003 16:24:14] .Ejemplos . // TMemo->SelectAll() } //----------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/editor/edic_seleccionar_todo.Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Edición | Seleccionar todo //----------------------------------------------------------- void __fastcall TMainForm::EditSelectAllClick(TObject *Sender) { Memo->SelectAll().

html (2 of 2) [27/02/2003 16:24:14] .Editor de texto Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/edic_seleccionar_todo.Ejemplos .

una barra. EditWordWrap->Checked = Memo->WordWrap.Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Edición | Ajustar //----------------------------------------------------------- void __fastcall TMainForm::EditWordWrapClick(TObject *Sender) { // Modificar la propiedad TMemo::WordWrap. // Si WordWrap está activo. Si no. Memo->WordWrap = !Memo->WordWrap.Ejemplos . dos. file:///D|/Manuales/intro/ejemplos/editor/edic_ajustar.html (1 of 2) [27/02/2003 16:24:14] .

else Memo->ScrollBars = ssBoth.Ejemplos .Editor de texto if (Memo->WordWrap) Memo->ScrollBars = ssVertical.html (2 of 2) [27/02/2003 16:24:14] . } //----------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/editor/edic_ajustar.

2.OOP . LPSTR. } //---------------------------------------------------------------------- PPAL. } return 0.Ejemplo 0 Curso de C++ Builder Ejemplo 0 Corresponde al final de la sección 5.CPP //---------------------------------------------------------------------#include <vcl. PpalFrm).h> #pragma hdrstop USERES("Ejemplo. EJEMPLO. USEFORM("Ppal.4. int) { try { Application->Initialize(). HINSTANCE.cpp".res").cpp"). Application->CreateForm(__classid(TPpalFrm).html (1 of 7) [27/02/2003 16:24:15] .H //---------------------------------------------------------------------file:///D|/Manuales/intro/ejemplos/oop/Ejemplo0. &PpalFrm). } catch (Exception &exception) { Application->ShowException(&exception). //----------------------------------------------------------------------WINAPI WinMain(HINSTANCE. Application->Run(). USEUNIT("ObjGraf. tras la herencia y antes de ABSTRACCIÓN.

hpp> //---------------------------------------------------------------------class TPpalFrm : public TForm { __published: // IDE-managed Components TPaintBox *PaintBox. void __fastcall PaintBoxPaint(TObject *Sender). void __fastcall FormDestroy(TObject *Sender). void __fastcall FormCreate(TObject *Sender).Ejemplo 0 #ifndef PpalH #define PpalH //---------------------------------------------------------------------#include #include #include #include #include <Classes.CPP //---------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "Ppal.h" //---------------------------------------------------------------------file:///D|/Manuales/intro/ejemplos/oop/Ejemplo0. //---------------------------------------------------------------------#endif PPAL.hpp> <StdCtrls.OOP . private: // User declarations public: // User declarations __fastcall TPpalFrm(TComponent* Owner).hpp> #include "ObjGraf. TBitBtn *BotonSalir. //---------------------------------------------------------------------extern PACKAGE TPpalFrm *PpalFrm.h" #include <Buttons.hpp> <ExtCtrls.hpp> <Controls.hpp> <Forms. }. void __fastcall BotonSalirClick(TObject *Sender).html (2 of 7) [27/02/2003 16:24:15] .

OOP . clYellow. 45). Cuad2->Mostrar(). 210.html (3 of 7) [27/02/2003 16:24:15] . Cuad2 = new TCuadrado (PaintBox. // Punteros a objetos de las clases derivadas. 100. 150. //---------------------------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { delete Cir1. 25). 70. 120. 200. delete Cuad1.Ejemplo 0 #pragma package(smart_init) #pragma resource "*. TCirculo *Cir1. 40. *Cuad2. } 30). Cuad1->Mostrar(). } file:///D|/Manuales/intro/ejemplos/oop/Ejemplo0. Cir2->Mostrar().dfm" TPpalFrm *PpalFrm. delete Cuad2. 20). Cir2 = new TCirculo (PaintBox. Cuad1 = new TCuadrado (PaintBox. *Cir2. } //---------------------------------------------------------------------void __fastcall TPpalFrm::BotonSalirClick(TObject *Sender) { Application->Terminate(). 100. clGreen. //---------------------------------------------------------------------- __fastcall TPpalFrm::TPpalFrm(TComponent* Owner) : TForm(Owner) { } //---------------------------------------------------------------------- void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Cir1 = new TCirculo (PaintBox. delete Cir2. } //---------------------------------------------------------------------void __fastcall TPpalFrm::PaintBoxPaint(TObject *Sender) { Cir1->Mostrar(). clRed. TCuadrado *Cuad1. clBlack.

int _X=0.OOP . *PaintBox. // Metodo virtual puro }.H //---------------------------------------------------------------------#ifndef ObjGrafH #define ObjGrafH //*************************************************/ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { public: int X. //*************************************************/ // Definicion de la clase derivada TCirculo. // Constructor de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { public: int Radio. // Otros metodos virtual void Mostrar (void) = 0. TColor TPaintBox // Propiedades Color. int _Y=0).Ejemplo 0 //---------------------------------------------------------------------- OBJGRAF. TColor _Color=clBlack. // Metodo constructor TCirculo (TPaintBox *_PaintBox.html (4 of 7) [27/02/2003 16:24:15] . int Y. file:///D|/Manuales/intro/ejemplos/oop/Ejemplo0. TColor _Color=clBlack.

html (5 of 7) [27/02/2003 16:24:15] .OOP . // Instanciacion del metodo virtual puro de la clase TObjGraf void Mostrar (void). // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { public: int Lado. TColor _Color=clBlack.h" //---------------------------------------------------------------------#pragma package(smart_init) /*****************************************************/ // Metodos asociados a la clase base TObjGraf /*****************************************************/ file:///D|/Manuales/intro/ejemplos/oop/Ejemplo0. int _Radio=1). // Instanciacion del metodo virtual puro de la clase TObjGraf void Mostrar (void). //*************************************************/ // Definicion de la clase derivada TCuadrado. int _Lado=1).h> #pragma hdrstop #include "ObjGraf. int _Y=0. // Metodo constructor TCuadrado (TPaintBox *_PaintBox. int _Y=0. }. }.Ejemplo 0 int _X=0. int _X=0. //---------------------------------------------------------------------#endif OBJGRAF.CPP //---------------------------------------------------------------------#include <vcl.

X+Lado. int _Y) { PaintBox = _PaintBox. // TCuadrado deriva de la clase base TObjGraf. X = _X.OOP . } file:///D|/Manuales/intro/ejemplos/oop/Ejemplo0. int _X.html (6 of 7) [27/02/2003 16:24:15] . } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCirculo :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. PaintBox->Canvas->Brush->Color = Color. Color = _Color. _X. TColor _Color. int _Radio) : TObjGraf (_PaintBox. } /*****************************************************/ // Metodos asociados a la clase derivada TCuadrado. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCuadrado :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. Y. _Color. X+Radio*2. Y+Radio*2). _Y) { Radio = _Radio. /*****************************************************/ TCuadrado :: TCuadrado (TPaintBox *_PaintBox. Y = _Y. _Color. int _Y. /*****************************************************/ TCirculo :: TCirculo (TPaintBox *_PaintBox. PaintBox->Canvas->Ellipse(X. } /*****************************************************/ // Metodos asociados a la clase derivada TCirculo. TColor _Color. Y. int _Lado) : TObjGraf (_PaintBox.Ejemplo 0 TObjGraf :: TObjGraf (TPaintBox *_PaintBox. PaintBox->Canvas->Rectangle(X. _Y) { Lado = _Lado. Y+Lado). _X. // TCirculo deriva de la clase base TObjGraf. TColor _Color. int _X. int _Y. int _X. PaintBox->Canvas->Brush->Color = Color.

html (7 of 7) [27/02/2003 16:24:15] .Ejemplo 0 Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/oop/Ejemplo0.OOP .

O. El Paradigma de la POO en C++.O. 5.2. Propiedades Virtuales.5.5. Los conceptos presentados en esta sección se ilustrarán usando un ejemplo que se irá completando poco a poco a medida que se introduzcan nuevos conceptos. 5.3. r r r 5. Polimorfismo.7. Clase: Especificación de las características de un conjunto de objetos. Clases Abstractas. r r 5. este mismo ejemplo se emplea en las secciones dedicadas al tratamiento de excepciones y a la programación con hebras. 5. 5.Programación Orientada a Objetos en C++ Curso de C++ Builder Programación Orientada a Objetos en C++ q q q q q 5. definamos que entendemos por objeto y clase: Objeto: Una entidad autónoma con una funcionalidad concreta y bien definida.1.1.. preparemos el camino creando un proyecto: file:///D|/Manuales/intro/5.4.1. Sobrecarga de funciones. Constructores y Destructores (Inicialización de Clases I).3.2. La P.7. Creación y Destrucción de Objetos. En primer lugar. Restricciones de acceso en C++.5. r r 5. es un paradigma de programación que se fundamenta en los conceptos de objeto y clase.6.2. 5.6.7. tan sólo se presentarán los conceptos necesarios para una correcta programación en C++ Builder.1. En esta sección no se pretende dar una teoría completa de P. Encapsulamiento. Polimorfismo en las clases y métodos virtuales. Herencia. q 5.5.O. 5. Herencia de Constructores y Destructores (Inicialización de Clases II). Herencia Múltiple. 5. 5.6. Es más. Abstracción.html (1 of 28) [27/02/2003 16:24:17] . Así. q 5..O.2. Un objeto es una instancia de una clase.

con Align=alTop. Guardar el código del formulario como Ppal. y ObjGraf. Colocar un botón bit que permita terminar la ejecución del programa.h: //-------------------------------------------------#ifndef ObjGrafH #define ObjGrafH // Definición de la clase TObjGraf class TObjGraf {}. pero no se crea ningún objeto. Dejar espacio por debajo del PaintBox para colocar un botón.h.Programación Orientada a Objetos en C++ q Crear un proyecto (File | New | Application) Cambiar el nombre del formulario (Name=PpalFrm). y. aunque no es obligatorio.cpp y otro con extensión . 5.bpr. Muy Importante: Con el ejemplo anterior sólo conseguimos definir la clase. Colocar un PaintBox de la página de componentes System que se llame PaintBox.cpp Cuando se crea una unidad de esta manera se crean. #endif //-------------------------------------------------- Nótese que el nombre de la clase va precedido por una T. La idea es que delimite la parte inferior del PaintBox.h. El botón estará centrado horizontalmente en la parte inferior del formulario. Colocar un bevel de ancho 4 y alinearlo en lo alto (Align=alTop). disponemos de dos ficheros: ObjGraf. que contendrá la definición (implementación de los métodos) de éstas.1. dos ficheros. que se file:///D|/Manuales/intro/5. Guardarla con el nombre ObjGraf. Así. El Paradigma de la POO en C++ Existen cuatro principios básicos que cualquier sistema orientado a objetos debe incorporar. uno con extensión . que contendrá las declaraciones de las clases con las que vamos a trabajar.html (2 of 28) [27/02/2003 16:24:17] . Crear una unidad (File | New | Unit). si es muy recomendable ya que es una convención de C++ Builder que casi todos los nombres de clases vayan precedidos por T.cpp. en realidad. q q q q q En ObjGraf.cpp y el proyecto como Ejemplo.

Programación Orientada a Objetos en C++ esquematizan en la figura 5.1.h" En Ppal. TObjGraf ObjGraf2. Un objeto se puede instanciar de una forma simple. } file:///D|/Manuales/intro/5.h: #include "ObjGraf. 5. En Ppal. 1. Creación y Destrucción de Objetos Ya se ha dicho que una clase es únicamente una especificación.1. declarando una variable del tipo de la clase. se deben instanciar las clases.cpp: Pulsando dos veces en OnCreate de la pestaña Events del editor de objetos de PpalFrm: //-------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { TObjGraf ObjGraf1().html (3 of 28) [27/02/2003 16:24:17] .2. Figura 5. Para poder utilizar la funcionalidad contenida en la misma. Pilares de la POO. Creación por Declaración.

se requiere la declaración previa de un puntero a objetos del tipo del que se va a crear. Esto es así por dos razones. 3. La duración de los objetos suele ir más allá de una simple función o bloque. Destrucción de objetos file:///D|/Manuales/intro/5. nosotros no la utilizaremos. Creación Dinámica Es la forma habitual de crear objetos en C++ Builder. // ObjGraf es un puntero a objetos de tipo TObjGraf //-------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { ObjGraf = new TObjGraf.4). Por lo tanto.cpp: TObjGraf * ObjGraf. En Ppal. Debido al enfoque de la programación dirigida por eventos. se usa una variable que referencie o apunte al nuevo objeto creado (de otra manera éste quedaría totalmente inaccesible). 2. No se puede usar esta modalidad de creación con la VCL.Programación Orientada a Objetos en C++ //-------------------------------------------------- Aunque esta forma es posible. suele ser habitual que un objeto se cree en un gestor de eventos y se destruya en otro. // Variable Global. Cuando usamos new para instanciar un objeto. y bastante utilizada en la programación de C++ clásica.html (4 of 28) [27/02/2003 16:24:17] . y se realiza mediante el operador new . En definitiva. 2. ¡Cuidado! Cuando se utiliza esta forma de instanciación de clases es responsabilidad únicamente del programador la correcta destrucción de los mismos. en C++ Builder se utiliza en muy contadas ocasiones. } //-------------------------------------------------- La forma de establecer el estado inicial o destruir las componentes de un objeto se estudiarán en el apartado dedicado a Constructores y Destructores (sección 5. fundamentalmente: 1.

La destrucción de objetos creados en tiempo de ejecución con new se realiza mediante el operador delete.3.) existen datos y procedimientos que actúan sobre esos datos.Programación Orientada a Objetos en C++ Cuando un objeto deja de ser útil hay que eliminarlo.2.O. En la figura 5. No hay una relación aparente entre datos y procedimientos (funciones) y esta relación se establece de manera más o menos pecisa de acuerdo a la profesionalidad del programador. p. En un objeto podemos distinguir dos aspectos bien diferenciados: q q Estado -----------> Propiedades Comportamiento ---> Métodos En P. La especificación de las propiedades de un objeto y los métodos de acceso se realiza en la declaración de la clase de la que se instancia el objeto. En Ppal. De esta manera la aplicación recupera los recursos (memoria) que ese objeto había acaparado cuando se creó. La declaración de propiedades y métodos de los objetos de la clase TObjGraf se realiza de la siguiente manera: file:///D|/Manuales/intro/5. Propiedades y métodos de los objetos de la clase TObjGraf.e. } //-------------------------------------------------- 5.html (5 of 28) [27/02/2003 16:24:17] .O.cpp: Pulsando dos veces en OnDestroy de la pestaña Events del editor de objetos de PpalFrm: //-------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { delete ObjGraf. los datos y los procedimientos que los gestionan están relacionados explícitamente y se "encapsulan" en un objeto.2 esquematizamos las propiedades y métodos que se van a asociar a los objetos de la clase TObjGraf: Figura 5. Encapsulamiento En la programación clásica (lenguaje C.

ObjGraf->Mostrar(). TColor Color. .html (6 of 28) [27/02/2003 16:24:17] . } //-------------------------------------------------- Nota: Los puntos suspensivos no son una palabra reservada de C++.. ValorY = ObjGraf->Y... //-------------------------------------------------- Acceso a Miembros de un Objeto Para acceder a los miembros de un objeto se usan los operadores típicos de acceso a miembros: el operador . simplemente significan que se omite una parte del código. y los referenciamos mediante un puntero. // Métodos }.Programación Orientada a Objetos en C++ En ObjGraf..cpp: //-------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { . Constructores y Destructores (Inicialización de Clases I) Son métodos que permiten establecer el estado inicial y final de un objeto.h: //-------------------------------------------------class TObjGraf { public: int X.Mostrar(). ya sea porque es irrelevante o porque ya se ha expuesto anteriormente. int ValorY. int Y.4. //Equivalente a (*Obj). para referencia directa al objeto y el operador -> para acceso a través de un puntero. Los constructores se pueden file:///D|/Manuales/intro/5. ObjGraf->X = 5. TPaintBox *PaintBox. el operador de acceso que utilizaremos es el operador -> En Ppal. Como nosotros siempre creamos los objetos con new. 5. // Propiedades void Mostrar (void).

} Importante: No es necesario escribir un destructor salvo si el objeto requiere memoria dinámica adicional.5. TColor _Color. Y los destructores no pueden recibir ni devolver ningún valor. clRed. 10). Un destructor se ejecuta cuando el objeto deja de existir: 1) porque su ámbito acaba. la clase derivada incorpora todos los miembros de la clase base además file:///D|/Manuales/intro/5. ó 2) cuando se crea dinámicamente con el operador new. X = _X. } En Ppal.html (7 of 28) [27/02/2003 16:24:17] . }. 5. // Constructor de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox.. El constructor debe llamarse igual que la clase.cpp: void __fastcall TPpalFrm::FormCreate(TObject *Sender) { ObjGraf = new TObjGraf (PaintBox. Herencia Cuando una clase hereda de otra. De ser así. int _Y) { PaintBox = _PaintBox. Color = _Color. En ObjGraf. y el destructor el nombre de la clase precedido del carácter ~ Un constructor se ejecuta cuando se crea un nuevo objeto: 1) por declaración. básicamente. liberar la memoria dinámica que ocupa el objeto que se va a destruir. int _X. ó 2) cuando se libera explícitamente con el operador delete. 10. pero no pueden devolver nada.h: class TObjGraf { . En ObjGraf. // El destructor sería: ~TObjGraf (void). la tarea del destructor será.. Y = _Y.Programación Orientada a Objetos en C++ definir con un conjunto de argumentos arbitrario. int _Y=0). TColor _Color=clBlack. int _X=0.cpp: TObjGraf :: TObjGraf (TPaintBox * _PaintBox.

TCirculo y TCuadrado. Tomando como base la clase TObjGraf se van a construir dos nuevas clases. Las clases TCirculo y TCuadrado heredan las propiedades y métodos de la clase TObjGraf. // Propiedad exclusiva de TCirculo }.4 En ObjGraf. Esto significa que los objetos de estas clases tienen asociados las propiedades y métodos de la clase base. Figura 5. TObjGraf. La herencia es una herramienta muy importante en muchos aspectos del desarrollo de aplicaciones: q q q Organización del diseño. que derivan de TObjGraf. // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { public: int Lado.h: //*************************************************/ // Definicion de la clase derivada TCirculo // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { public: int Radio.Programación Orientada a Objetos en C++ de los suyos propios.3.html (8 of 28) [27/02/2003 16:24:17] . además de los suyos propios. //*************************************************/ // Definicion de la clase derivada TCuadrado. En la figura 5. Reusabilidad de clases (propias o no). Mejora del mantenimiento.3 esquematizamos el mecanismo de herencia para las nuevas clases y las nuevas propiedades que se asocian a los objetos de las clases derivadas. // Propiedad exclusiva de TCuadrado file:///D|/Manuales/intro/5.

que los destructores de las clases derivadas se invocan antes que los de las clases base.Programación Orientada a Objetos en C++ }. se utiliza la lista de inicialización. //*************************************************/ // Definicion de la clase derivada TCuadrado. // Propiedad exclusiva de TCirculo // Metodo constructor TCirculo (TPaintBox *_PaintBox. no obstante. 5. y 2. Para determinar con qué parámetros se llaman a los constructores de las clases base. Es posible. por lo que nosotros supondremos que sólo existe la public. En ObjGraf. Pero ésta no se suele usar. esto es así porque C++ permite también la herencia private. emplear los constructores de la clase base pero hay que indicarlo explícitamente.1. Herencia de Constructores y Destructores (Inicialización de Clases II) Los constructores y destructores de una clase no son heredadas automáticamente por sus descendientes. TColor _Color=clBlack. es necesario saber: 1.h: //*************************************************/ // Definicion de la clase derivada TCirculo // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { public: int Radio.5. int _Radio=1). // Propiedad exclusiva de TCuadrado file:///D|/Manuales/intro/5. que los constructores y destructores de las clases base son invocados automáticamente antes que los constructores de las clases derivadas. // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { public: int Lado. int _Y=0. Antes del nombre de la clase base hay que poner public. Deberemos crear en las clases hijas sus propios constructores y destructores. De ser así.html (9 of 28) [27/02/2003 16:24:17] . int _X=0. }.

int _X. }. _X. int _X=0. int _Lado) : TObjGraf (_PaintBox. // Otros metodos virtual void Mostrar (void) = 0. Clases Abstractas Clase abstracta: es una clase que no está completamente especificada (posee métodos sin implementar).Programación Orientada a Objetos en C++ // Metodo constructor TCuadrado (TPaintBox * _PaintBox. class TCirculo : public TObjGraf { file:///D|/Manuales/intro/5. int _Lado=1). int _Y=0. int _Radio) : TObjGraf (_PaintBox. TColor _Color=clBlack. q q Virtual: obliga a las clases derivadas a implementar ese método.html (10 of 28) [27/02/2003 16:24:17] . En ObjGraf. } 5. _Color. por lo tanto no se pueden crear instancias de la misma.5. Puro: no pueden crearse instancias de esa clase.. En ObjGraf. int _Y. } TCuadrado :: TCuadrado (TPaintBox * _PaintBox.2. _Color. int _X. Una clase abstracta se usa para servir de clase base a otras clases.h: class TObjGraf { public: .cpp: TCirculo :: TCirculo (TPaintBox * _PaintBox. int _Y. TColor _Color. En terminología C++ se dice que una clase abstracta es aquella que posee al menos un método virtual puro. _Y) { Lado = _Lado.. // Metodo virtual puro }. _X. _Y) { Radio = _Radio. TColor _Color.

2. }.Programación Orientada a Objetos en C++ public: . X+Lado. Y+Radio*2). PaintBox->Canvas->Brush->Color = Color.html (11 of 28) [27/02/2003 16:24:17] . } . class TCuadrado : public TObjGraf { public: . Y. }. En ObjGraf. } ¿Por qué se especifica el método Mostrar en TObjGraf. X+Radio*2.. PaintBox->Canvas->Ellipse(X. ¿Porqué?: Recordar que en Ppal. // Instanciacion del metodo virtual puro de la clase TObjGraf void Mostrar (void).. PaintBox->Canvas->Rectangle(X. como virtual puro. en lugar de omitirlo? Fundamentalmente podemos considerar dos razones para usar métodos virtuales puros: 1. // Instanciacion del metodo virtual puro de la clase TObjGraf void Mostrar (void). En este estado. Y+Lado).. nos aparecerá un error: no se puede crear una instancia de una clase abstracta.... si probamos a ejecutar el programa. void TCuadrado :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. Y. Para obligar a que las clases descendientes los implementen. PaintBox->Canvas->Brush->Color = Color. y se podrá invocar con seguridad.cpp el gestor asociado al evento OnCreate del formulario está escrito como sigue: //-------------------------------------------------- file:///D|/Manuales/intro/5.cpp: void TCirculo :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. Para evitar que se puedan crear instancias de la clase abstracta. De esta forma estamos seguros de que todas las clases descendientes no abstractas de TObjGraf poseen el método.

creemos entonces objetos de las clases hijas: 1. 150. *Cir2. 2. 3. modificaremos la función FormCreate para que cree dos objetos de cada clase referenciados por los punteros declarados anteriormente: //-------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Cir1 = new TCirculo (PaintBox. 20). delete Cuad2. dos para referenciar a objetos de tipo TCirculo y otros dos para referenciar a objetos de tipo TCuadrado: // Punteros a objetos de las clases derivadas. // Variable Global. En segundo lugar. Cir2 = new TCirculo (PaintBox. TCuadrado *Cuad1. }. 25). file:///D|/Manuales/intro/5. delete Cuad1. //-------------------------------------------------- Así. *Cuad2. 100. 10. 45).html (12 of 28) [27/02/2003 16:24:17] . y en su lugar se declararán cuatro punteros. clGreen. }. TCirculo *Cir1. clBlack. Finalmente. 100. 200. clRed. 210. En primer lugar. 120. modificaremos la función FormDestroy para que elimine los objetos creados: //-------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { delete Cir1. en Ppal. 40.cpp hay que borrar la declaración de la variable global: TObjGraf *ObjGraf. Cuad1 = new TCuadrado (PaintBox. 10). 70. Cuad2 = new TCuadrado (PaintBox. clYellow. clRed. //-------------------------------------------------- 30).Programación Orientada a Objetos en C++ void __fastcall TPpalFrm::FormCreate(TObject *Sender) { ObjGraf = new TObjGraf (PaintBox. delete Cir2.

Resultado del proyecto Ejemplo. El resultado es el mostrado en la figura 5. el proyecto debe estar como se indica en el proyecto Ejemplo0. Cir2->Mostrar().5. Cuad2->Mostrar(). aunque no se visualizan en la ventana. ¿Porqué? En ningún momento se ha llamado al método Mostrar() asociado a cada objeto. Ejercicio: Construir la clase TTriangulo y modificar el proyecto para que proporcione un resultado similar al de la figura 5.html (13 of 28) [27/02/2003 16:24:17] . } //-------------------------------------------------- En este punto. al ejecutar el programa se crean y se destruyen objetos de las clases derivadas.Programación Orientada a Objetos en C++ } //-------------------------------------------------- Ahora. Cuad1->Mostrar().4: 4 Figura 5. Para mostrar los objetos. basta con indicarlo en el gestor asociado al evento OnPaint del componente PaintBox: //-------------------------------------------------void __fastcall TPpalFrm::PaintBoxPaint(TObject *Sender) { Cir1->Mostrar(). file:///D|/Manuales/intro/5.bpr.4.

5.... public TVehiculo { ... . class TCocheEnVenta : public TProducto.3. Resultado del proyecto Ejemplo.. 5. }. }.bpr mostrando objetos de la clase TTriangulo. file:///D|/Manuales/intro/5. Observar que los objetos de la clase TCocheEnVenta derivan de las clases TProducto y TVehiculo. class TVehiculo { int NumRuedas. Herencia Múltiple La herencia múltiple es el hecho de que una clase derivada se genere a partir de varias clases base. Ejemplo: En un concesionario de coches podríamos considerar la siguiente jerarquía de clases: class TProducto { long Precio.5.html (14 of 28) [27/02/2003 16:24:17] . }. .Programación Orientada a Objetos en C++ Figura 5.

5.1. En ObjGraf. Podemos distinguir en una clase dos aspectos desde el punto de vista de la abstracción: q q Interfaz: lo que se puede ver/usar externamente de un objeto. Que herede de TCuadrado y contenga un objeto de la clase TCirculo. si quisieramos diseñar una clase (TMarco) que represente un marco (representado por un cuadrado y un círculo). Ninguna de las dos posibilidades es mejor que la otra. private: Implementación de la clase. Implementación: cómo lleva a cabo su cometido. Que herede de TObjGraf y contenga un objeto de la clase TCirculo y otro de TCuadrado.h: //*************************************************/ file:///D|/Manuales/intro/5. Que herede de TCirculo y contenga un objeto de la clase TCuadrado. protected: desde los métodos de la clase y desde los métodos de las clases derivadas. pero no cómo lo lleva a cabo. Estos especificadores no modifican ni la forma de acceso ni el comportamiento. protected: Implementación de la familia. únicamente controlan desde dónde se pueden usar los miembros de la clase: q q q public: desde cualquier sitio. private: desde los métodos de la clase. una es la herencia. Abstracción Es la ocultación de detalles irrelevantes o que no se desean mostrar.Programación Orientada a Objetos en C++ Existen dos formas para que una clase saque partido de las ventajas de otra. en cada caso particular habrá que estudiar cual es la mejor opción. Por ejemplo.html (15 of 28) [27/02/2003 16:24:17] . y la otra es que una clase contenga un objeto de la otra clase. 5. Resumiendo: nos interesa saber qué nos ofrece un objeto. Restricciones de acceso en C++ En C++ se puede especificar el acceso a los miembros de una clase utilizando los siguientes especificadores de acceso: q q q public: Interfaz de la clase.6. podemos decidir distintas estrategias a la hora de llevarlo a cabo: q q q q Que herede de TCirculo y TCuadrado.6.

TColor Color. TColor _Color=clBlack. // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { protected: // Pueden acceder los objetos de esta clase y sus descendientes. // Instanciacion del metodo virtual puro // de la clase TObjGraf }. int Radio. int _Y=0. TPaintBox * PaintBox.Programación Orientada a Objetos en C++ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int X. // Otros metodos virtual void Mostrar (void) = 0. Modificar de la misma manera las clases TCirculo y TCuadrado para que sus propiedades Radio y Lado queden protegidas y los métodos públicos: //*************************************************/ // Definicion de la clase derivada TCirculo. protected: // Pueden acceder los objetos de esta clase y sus descendientes. public: // Metodo constructor TCirculo (TPaintBox *_PaintBox. int _X=0. // Puede acceder SOLO los objetos de esta clase. int Y. // Constructor de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. TColor _Color=clBlack. int _X=0. int _Radio=1). int _Y=0). public: // Pueden usarlas todas. // Metodo virtual puro }. file:///D|/Manuales/intro/5.html (16 of 28) [27/02/2003 16:24:17] . void Mostrar (void).

¿Entonces cómo se puede cambiar el estado de un objeto desde el exterior? 1. porque su uso está restringido al IDE.cpp escribiéramos: //-------------------------------------------------void __fastcall TPpalFrm::FormCreate (TObject *Sender) { . int _X=0.Programación Orientada a Objetos en C++ //*************************************************/ // Definicion de la clase derivada TCuadrado.. Esta técnica es exclusiva de C++ Builder y la describimos en la siguiente sección. TColor _Color=clBlack.. Es una buena técnica de programación no permitir el acceso público a las propiedades de un objeto. file:///D|/Manuales/intro/5. si en Ppal. Esta es la técnica clásica que se emplea en C++ 2. Así. public: // Metodo constructor TCuadrado (TPaintBox * _PaintBox. // No se puede porque X es private. que es el __published. De esta manera son los métodos los que acceden a las propiedades y el usuario de la clase sólo accede a través de ellos. Cir1->Mostrar(). // Instanciacion del metodo virtual puro // de la clase TObjGraf }. int Lado. // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { protected: // Pueden acceder los objetos de esta clase y sus descendientes. Cir1->X = 10. int _Y=0. ya que si esto ocurriera podría peligrar la integridad del objeto. } //-------------------------------------------------- En realidad estos tres especificadores de acceso son los propios de C++. pero en C++ Builder existe otro adicional. No vamos a dar mucha importancia a este modificador. Ofreciendo métodos (públicos) que se encarguen de modificar las propiedades (privadas) que se desee. Cuando en una clase veamos una sección __published quiere decir que los miembros contenidos en la misma son mantenidos automáticamente por el IDE y no deberemos modificar nada en dicha sección. // Se puede. A través de los métodos y de las propiedades "virtuales". void Mostrar (void).html (17 of 28) [27/02/2003 16:24:17] . ya que de lo contrario los resultados pueden ser imprevisibles. int _Lado=1).

// Puede acceder SOLO los objetos de esta clase. {read=FY. __property int X = __property int Y = __property TColor Color = {read=FX. // Constructor de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. mediante la palabra reservada read mientras que si se usa para escritura se especifica con write. Es más. El usuario de la clase usa estas propiedades como si fueran propiedades reales y en última instancia se traducen en la llamada a un método o en el acceso a una propiedad real. realmente. virtual int GetAncho (void) = 0. // OJO: Se ha cambiado Color por FColor // Pueden usarlas todas. en la parte derecha de una asignación) se traduce en una acción diferente que si esa popiedad virtual se usa para escritura. *PaintBox. write=SetX }.6. file:///D|/Manuales/intro/5. // Metodo virtual puro protected: TColor TPaintBox public: // Pueden acceder los objetos de esta clase y descendientes. void SetY (int _Y). write=FColor}. {read=FColor. no existen. sintácticamente.Programación Orientada a Objetos en C++ 5.html (18 of 28) [27/02/2003 16:24:17] . // OJO: Se ha cambiado el nombre a // los miembros X e Y por FX y FY.h: //*************************************************/ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int FX. // Metodo virtual puro virtual int GetAlto (void) = 0. void SetX (int _X). // Metodo virtual puro // NUEVAS FORMAS DE ACCESO CON PROPIEDADES VIRTUALES. Se llaman virtuales porque. // Otros metodos virtual void Mostrar (void) = 0.2. write=SetY }. La acción que se produce cuando la propiedad virtual es de lectura se especifica. Veamos un ejemplo. int _Y=0). si una propiedad virtual se usa para lectura (p. Propiedades Virtuales Son propiedades definidas mediante métodos de lectura (read) y/o escritura (write). TColor _Color=clBlack. int _X=0. FColor. int FY.e. En ObjGraf.

Programación Orientada a Objetos en C++ __property int __property int }. no obstante.html (19 of 28) [27/02/2003 16:24:17] . directamente. La última instrucción. Si en Ppal. observar que las propiedades virtuales Ancho y Alto no tienen asociados métodos de acceso para escritura. povocaría un error porque SetX() es un método privado. FY). Observaciones: q Observar que la "antigua" propiedad X (resp. Además. hay una propiedad virtual (pública) llamada X (resp. ya que cuando se accede para lectura a la propiedad (virtual) X en realidad se accede a la propiedad (real) FX. q Como hemos incorporado dos nuevos métodos a la clase base TObjGraf (GetAncho() y GetAlto()) y éstos se han declarado virtuales puros necesitamos instanciarlos en las clases derivadas: file:///D|/Manuales/intro/5. En realidad es como si se hiciera int CX = Cir1->FX. En realidad es como si se hiciera Cir1->SetX(100). Y). Y) se llama ahora FX (resp. povocaría un error porque FX es una propiedad privada. Al "redirigir" la escritura al método SetX() podemos controlar la validez del parámetro y corregir. La última instrucción. }.cpp se usara esta propiedad para lectura: int CX = Cir1->X. Si se usara esta propiedad para escritura: Cir1->X = 100. q La propiedad virtual Color tiene asociado el mismo método de acceso para lectura y escritura: devuelve o escribe. ya que cuando se accede para escritura a la propiedad (virtual) X en realidad se llama al método SetX(). en la propiedad real FColor. Finalmente. no obstante. el valor: una ventaja adicional. en su caso. Ancho = Alto = {read=GetAncho {read=GetAlto }. Estas propiedades están declaradas en la clase TObjGraf lo que significa que sus descendientes también las heredan.

int Radio. // Instanciacion del metodo virtual puro de // la clase TObjGraf }. // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { protected: // Pueden acceder los objetos de esta clase y descendientes. // Instanciacion del metodo virtual puro de // la clase TObjGraf }. inline int GetAncho inline int GetAlto public: // Metodo constructor TCuadrado (TPaintBox * _PaintBox. inline int GetAncho inline int GetAlto public: // Metodo constructor TCirculo (TPaintBox *_PaintBox. int _Lado=1). int _Y=0. // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { protected: // Pueden acceder los objetos de esta clase y descendientes.} (void) {return(Lado). int _X=0.cpp) las funciones write de las propiedades virtuales X e Y: file:///D|/Manuales/intro/5. TColor _Color=clBlack.} (void) {return(Radio*2). (void) {return(Radio*2). (void) {return(Lado).} Ahora. void Mostrar (void). TColor _Color=clBlack.Programación Orientada a Objetos en C++ //*************************************************/ // Definicion de la clase derivada TCirculo.} int Lado. int _X=0. int _Y=0. int _Radio=1). añadimos (en ObjGraf. void Mostrar (void). //*************************************************/ // Definicion de la clase derivada TCuadrado.html (20 of 28) [27/02/2003 16:24:17] .

el proyecto debe estar como se indica en el proyecto Ejemplo1. // Ajustar al margen derecho else FX = _X.Alto)) // Demasiado alta FY = PaintBox->Height . En este caso. GetAlto) para fijar el valor de una // propiedad virtual (Alto. En ObjGraf.cpp: TObjGraf :: TObjGraf (TPaintBox *_PaintBox. } En este punto. El resultado el el mismo que el mostrado en la figura 5. FColor = _Color. // No se puede llamar a los metodos virtuales puros FY = _Y. // Ajustar al margen inferior else FY = _Y. no se puede llamar a los métodos virtuales puros (GetAncho() y GetAlto()) de las propiedades virtuales (Ancho y Alto) desde el constructor de la clase base TObjGraf. int _X.4. TColor _Color.html (21 of 28) [27/02/2003 16:24:17] .Alto. file:///D|/Manuales/intro/5.Programación Orientada a Objetos en C++ // Funciones de escritura de las propiedades virtuales X e Y void TObjGraf :: SetX (int _X) { if (_X < 0) // Coordenada negativa FX = 0. // (GetAncho. // Correcto: escribir sin modificar } void TObjGraf :: SetY (int _Y) { if (_Y < 0) // Coordenada negativa FY = 0. // Ajustar al margen izquierdo else if (_X > (PaintBox->Width . Ancho) desde un // constructor de la clase base. // Ajustar al margen superior else if (_Y > (PaintBox->Height .Ancho. // Correcto: escribir sin modificar } Muy importante: Cambiamos el constructor de la clase TObjGraf porque no se puede llamar a los métodos virtuales puros de una propiedad virtual desde un constructor de una clase base. // MUY IMPORTANTE: Estas tres lineas han cambiado: FX = _X.Ancho)) // Demasiado alta FX = PaintBox->Width . int _Y) { PaintBox = _PaintBox.

Observar que la propiedad virtual X se usa para lectura y escritura. 100. Cir2. 100.html (22 of 28) [27/02/2003 16:24:17] . Cuad1 y Cuad2) se crean con sus correspondientes constructores. 5. que en última instancia llaman al constructor de la clase base para establecer los valores de las propiedades reales FX. 100. La línea anterior fija la coordenada X al valor 100. -100.Programación Orientada a Objetos en C++ Experimentación con las propiedades virtuales. Los objetos gráficos (Cir1. FColor y PaintBox. en la función FormCreate()de Ppal. con coordenadas incorrectas no se corrigen ya que como el constructor de la clase base no puede utilizar la propiedad virtual X para escritura no se emplea el método SetX(). 1.7. por ejemplo. Lectura/escritura a través de propiedades virtuales. Observar que el círculo negro tiene el valor 0 en la coordenada X: este valor se ha fijado a través del método de escritura SetX(). La consecuencia es que si se crea un círculo. 2.cppcambiar la línea: Cir1 = new TCirculo (PaintBox. FY.cpp añadiendo esta línea al principio: if (Cir1->X < 0) Cir1->X = 100. clBlack. Polimorfismo file:///D|/Manuales/intro/5. Los constructores no verifican coordenadas. por: Cir1 = new TCirculo (PaintBox. Modificar la función PaintBoxPaint() de Ppal. 30). Un ejemplo más clarificador es cambiar la línea anterior por: if (Cir1->X < 0) Cir1->X = -200. clBlack. Observar que el círculo negro no se muestra. Como demostración. 30).

Polimorfismo en las clases y métodos virtuales. Como tenemos variables (punteros) que pueden contener objetos de distintas clases. Una pelota (un objeto de tipo TPelota. FX = ObjGraf->FX. } 5. Puede darse de tres formas diferentes: q Funciones: sobrecarga. Una clase se puede comportar como cualquiera de sus antecesoras (en la asignación por ejemplo). para ser más precisos) es un círculo que tiene la capacidad de file:///D|/Manuales/intro/5. Ocurre cuando en una clase existen dos métodos con idéntico nombre pero con distinta lista de parámetros. Enlace dinámico: métodos virtuales.Programación Orientada a Objetos en C++ Es demostrar comportamientos distintos según la situación. Para ilustrar el polimorfismo.7. podría sobrecargarse el constructor de la clase TObjGraf añadiendo un nuevo constructor de copia: En ObjGraf. FColor = ObjGraf->Color. Clases: es al que se refiere normalmente el concepto de polimorfismo.cpp: TObjGraf::TObjGraf (TObjGraf *ObjGraf) { PaintBox = ObjGraf->PaintBox.1.Sobrecarga de funciones. que derive de la clase TCirculo. el compilador no sabe qué tipo de objeto es al que realmente apunta la variable (en tiempo de compilación) por lo tanto hay retrasar el enlace a tiempo de ejecución.7.2. El enlace dinámico es retrasar el enlace de una llamada a un método (función) al tiempo de ejecución.h: TObjGraf (TObjGraf *ObjGraf). FY = ObjGraf->FY. Por ejemplo. El compilador los considera como dos métodos distintos y aplicará cada uno de ellos en la situación apropiada. En ObjGraf. q q 5. TPelota. crearemos una nueva clase.html (23 of 28) [27/02/2003 16:24:17] .

el metodo Mostrar() se declara virtual. lo que conseguimos a través del método Mostrar() asociado a la clase TPelota. // Ahora. O=8. SO=9. Codificacion: /* NO 10 \ O 8 --/ 9 SO */ enum TDireccion {S=1. Antes. En ObjGraf.h: // Tipo definido por enumeracion para la direccion de TPelota. public: .. N 2 | * | 1 S NE 6 / --.4 E \ 5 SE file:///D|/Manuales/intro/5. SE=5. por comodidad y claridad.h: //*************************************************/ // Definicion de la clase derivada TCirculo. aunque no es puro: // 1) Por ser virtual: cualquier clase que derive de TCirculo debe // tener su propio metodo Mostrar(). Ahora nos centramos en la nueva clase TPelota. Sin embargo. }.. en este momento nos interesa poner de manifiesto el polimorfismo. E=4. definimos un tipo por enumeración para la dirección del movimiento: En ObjGraf.html (24 of 28) [27/02/2003 16:24:17] . virtual void Mostrar (void). // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { private: .Programación Orientada a Objetos en C++ movimiento. Antes. Para implementar el movimiento de una pelota necesitamos incorporar nuevas propiedades y métodos propios a la clase TPelota. modificamos la declaración del método Mostrar() de la clase TCirculo para obligar a sus descendientes a implementar su propio método Mostrar(): basta con indicar que en el método Mostrar() de la clase TCirculo es virtual. N=2.... NO=10}. NE=6. . // 2) Por no ser puro: puede llamarse a este metodo con objetos TCirculo..

// TPelota deriva de la clase TCirculo. que a su // vez deriva de la clase base TObjGraf /*****************************************************/ TPelota :: TPelota (TPaintBox *_PaintBox. int _Velocidad) : TCirculo (_PaintBox. TColor _Color=clBlack. file:///D|/Manuales/intro/5.cpp: /*****************************************************/ // Metodos asociados a la clase derivada TPelota. int _Velocidad=5). FVelocidad}. La implementación de los métodos propios de la clase TPelota se hará en ObjGraf. int _Y=0. TDireccion _Direccion=SE.html (25 of 28) [27/02/2003 16:24:17] . Velocidad = _Velocidad. que a su // vez deriva de la clase base TObjGraf //*************************************************/ class TPelota: public TCirculo { private: int FDirX. int _Radio=1. // Otros metodos void Mostrar (void). GetDireccion.h: //*************************************************/ // Definicion de la clase derivada TPelota. FVelocidad. SetDireccion (TDireccion _Direccion). GetDireccion (void).Programación Orientada a Objetos en C++ La declaración de la clase TPelota se hará en ObjGraf. void Borrar (void). // TPelota deriva de la clase TCirculo. int _X=0. SetDireccion}. int _X. // Velocidad del movimiento void TDireccion public: // Constructores TPelota (TPaintBox *_PaintBox. _X. TDireccion _Direccion. en el eje Y int FVelocidad. _Y. _Radio) { Direccion = _Direccion. // Dir. _Color. en el eje X int FDirY. __property int Velocidad = {read = write= __property TDireccion Direccion = {read = write= }. // Dir. TColor _Color. int _Y. void Mover (void). int _Radio.

Y. El polimorfismo se va a manifestar invocando a la función Mostrar() para cada uno de esos objetos. que provocan diferentes acciones dependiendo del tipo de objetos al que se aplican.html (26 of 28) [27/02/2003 16:24:17] . } TDireccion TPelota :: GetDireccion (void) { TDireccion _Dir. Y. Vamos a crear dinámicamente cuatro objetos de diferentes clases. FDirX = (_Dir & 4) ? +1 : ((_Dir & 8) ? -1 : 0). file:///D|/Manuales/intro/5. _Dir = (TDireccion) (_Dir + (FDirX == +1) ? 4 : ((FDirX == -1 ) ? 8 :0)). PaintBox->Canvas->Brush->Color = PaintBox->Color. } void TPelota :: Mover (void) { Borrar (). } // Otras funciones propias de TPelota void TPelota :: Borrar (void) { PaintBox->Canvas->Pen->Color = PaintBox->Color. void TPelota :: Mostrar (void) { PaintBox->Canvas->Pen->Color = clBlack. X+Radio*2. X += FDirX * Velocidad. // Observar la diferencia PaintBox->Canvas->Brush->Color = Color. PaintBox->Canvas->Ellipse(X. _Dir = (TDireccion) ((FDirY == +1) ? 1 : ((FDirY == -1 ) ? 2 : 0)). } void TPelota :: SetDireccion (TDireccion _Dir) { FDirY = (_Dir & 1) ? +1 : ((_Dir & 2) ? -1 : 0).Programación Orientada a Objetos en C++ } // Instanciacion del metodo virtual puro de la clase TObjGraf // y virtual en TCirculo. para ilustrar el polimorfismo nos basaremos en la existencia de diferentes métodos con el mismo nombre: Mostrar(). return (_Dir). PaintBox->Canvas->Ellipse(X. } Finalmente. Y+Radio*2). Estos objetos van a ser referenciados (mediante punteros) desde un vector de objetos de tipo TObjGraf *. X+Radio*2. Mostrar (). Y+Radio*2). Y += FDirY * Velocidad.

cpp declararemos la variable global: TObjGraf **Objs. } //---------------------------------------------------------------------= = = = new new new new TCirculo TCuadrado TCirculo TPelota (PaintBox. 30). Objs[0] Objs[1] Objs[2] Objs[3] } //---------------------------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { for (int i=0.html (27 of 28) [27/02/2003 16:24:17] .cpp: //---------------------------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Objs = new TObjGraf * [4]. clBlack. delete []Objs. 70. (PaintBox. 100. clRed. (PaintBox.6: Figura 5. clGreen.6. i<4. 20). El resultado es el mostrado en la figura 5. que se interpreta como: Objs es un puntero a una zona de memoria que contendrá punteros a objetos de tipo TObjGraf. 120. (PaintBox. 150. 200. i++) delete Objs[i]. } //---------------------------------------------------------------------void __fastcall TPpalFrm::PaintBoxPaint(TObject *Sender) { for (int i=0. Así. i++) Objs[i]->Mostrar(). el proyecto debe estar como se indica en el proyecto Ejemplo2. 210. i<4. // POLIMORFISMO En este punto. clYellow. file:///D|/Manuales/intro/5.bpr. 25). 100. en Ppal. Resultado del proyecto Ejemplo. 40.Programación Orientada a Objetos en C++ En Ppal. 45).

html (28 of 28) [27/02/2003 16:24:17] .Programación Orientada a Objetos en C++ Página principal © Francisco Cortijo Bon file:///D|/Manuales/intro/5.

Lanzamiento de excepciones. *p2. lo habitual es que exista suficiente memoria disponible y no haya ningún problema.5. ¡¡No tienen por qué ser errores!! Si se consigue dominar su programación. El funcionamiento general del mecanismo de lanzamiento y tratamiento de excepciones es el siguiente: q q q q Existe un método que invoca la ejecución de otro.4. Especificación de excepciones. Pero si queremos realizar una aplicación robusta deberemos de tener en cuenta la eventualidad de que dicha memoria no se conceda. Excepciones no tratadas. En este momento termina la ejecución del método más interno y se retorna inmediatamente al método llamador. legible. lo cual complica enormemente un sencillo algoritmo.html (1 of 16) [27/02/2003 16:24:19] .2. Este método más interno se encuentra en una situación que puede considerarse como excepcional. file:///D|/Manuales/intro/6.Tratamiento de excepciones Curso de C++ Builder Tratamiento de excepciones q q q q q 6. *p3. De esta manera se consigue un diseño mucho más estructurado.1. Las excepciones son situaciones anómalas que requieren un tratamiento especial. 6. Cuando solicitamos memoria al sistema. la calidad de las aplicaciones que se desarrollen aumentará considerablemente. 6. 6.3. Excepciones de la VCL. Ejemplo. robusto y fácil de mantener. manejando las situaciones extraordinarias a parte. Parte del tratamiento de la excepción puede ser volver a lanzarla al método que invocó a este. 6. El método llamador debe capturar la excepción y la trata. Captura de excepciones. Por lo tanto lanza una excepción. Veamos una función escrita en C que simplemente intenta asignar memoria dinámica para tres enteros: void SinExcepciones (void) { int *p1. La correcta programación de excepciones significa diseñar los algoritmos pensando únicamente en la forma habitual en la que deben ejecutarse.

} } Si programamos en C++ y hacemos uso de las excepciones: void ConExcepciones (void) { int *p1. p2 = new int. El tratamiento que se efectúa es. } p2 = (int*) malloc(sizeof(int)). // Comportamiento normal. } catch(. Las instrucciones que pueden provocar el lanzamiento de una excepción (la "zona crítica") se encierran en un bloque try. printf("No hay suficiente memoria"). abort(). file:///D|/Manuales/intro/6... try { p1 = new int. Si alguna de las instrucciones del bloque try provocara una excepción el flujo del programa se dirige al final de ese bloque.. if (p2 == NULL) { printf("No hay suficiente memoria"). } } El ANSI C++ especifica que si una instrucción new falla (no hay memoria disponible) debe lanzar la excepción bad_alloc (definida en el fichero de cabecera new). en este caso. la excepción bad_alloc. p3 = new int. el programa terminaría -ver sección 6. *p3.html (2 of 16) [27/02/2003 16:24:19] ..) captura cualquier excepción. la instrucción catch(. y en particular. } p3 = (int*) malloc(sizeof(int)). if (p3 == NULL) { printf("No hay suficiente memoria"). if (p1 == NULL) { printf("No hay suficiente memoria"). abort().Tratamiento de excepciones p1 = (int*) malloc(sizeof(int)).){ // Comportamiento excepcional.4-). mostrar un mensaje de error y terminar la ejecución del programa. En este caso. abort(). abort(). buscando un bloque catch que capture la excepción (si no lo encontrara. *p2.

// Calcular cociente. el entorno se hace cargo de ella y muestra la siguiente ventana: Figura 6.html (3 of 16) [27/02/2003 16:24:19] . Zona critica: peligro si Divisor == 0 Cociente = Dividendo / Divisor. //---------------------------------------------------------------#include <vcl. HINSTANCE. introducir la siguiente modificación: file:///D|/Manuales/intro/6. se intenta realizar una división por cero y el programa lanza una excepción de división por cero (EZeroDivide). al no estar tratada por el programa. Ventana de error que surge debido a una excepción EDivByZero no tratada. } //---------------------------------------------------------------- Cuando se produce la excepción. Cociente. // Leer datos de entrada: dividendo y divisor Valor = InputBox ("División".h> #pragma hdrstop //---------------------------------------------------------------WINAPI WinMain(HINSTANCE. Si el divisor es cero. Leer divisor y convertirlo. El siguiente programa (proyecto Division) lee dos valores y calcula el cociente entre ambos.Tratamiento de excepciones Ejemplo. int) { AnsiString Valor. Divisor = StrToFloat (Valor). return (0). // Mostrar el resultado ShowMessage ("Cociente = " + AnsiString(Cociente)). "Divisor". Divisor. Valor = InputBox ("División". Para proteger la instrucción crítica. LPSTR. ""). // // // // Leer dividendo y convertirlo. "Dividendo". Dividendo = StrToFloat (Valor). float Dividendo. "").1. recoger y tratar la excepción.

.) { ShowMessage ("El divisor no puede ser cero.. ShowMessage ("Cociente = " + AnsiString(Cociente)).2. Ahora. al ejecutar el programa e intoducir el valor 0 como divisor se muestra la ventana mostrada en la figura 6.2."). } catch (.3 Figura 6. file:///D|/Manuales/intro/6.Tratamiento de excepciones try { Cociente = Dividendo / Divisor.3. Figura 6. Ventana resultante de la gestión de la excepción. } Para ceder el control de la gestión de excepciones a nuestro programa debemos desabilitar la opción por la que el entorno integrado gestiona las interrupciones e indicar que se van a gestionar por el programa: seleccionaremos Tools | Debuggber Options y abriremos la carpeta OS Exceptions para dejarla como se indica en la figura 6.html (4 of 16) [27/02/2003 16:24:19] . Ventana Debugger Options Con esto indicamos al depurador de C++ Builder que nuestro programa se encargará de manejar las excepciones C++ que ocurran.

Nota: Aunque las excepciones sean clases. y precisamente será dicho objeto la excepción en sí. 6.html (5 of 16) [27/02/2003 16:24:19] . y no por T como el resto de las clases. //*************************************************/ class EFueraRango {}. si tuvieramos un método que lanzara una excepción por falta de memoria.h: //*************************************************/ // Definicion de la clase EFueraRango // Clase de excepcion por entrar en "fuera de rango": // salirse de los limites del PaintBox al calcular // las nuevas coordenadas de dibujo de la pelota. Cuando se lanza una excepción. que sirve para enumerar. Con lo que podríamos lanzar una excepción de la siguiente manera: throw EfueraRango(). Por ejemplo. en C++ Builder existe la convención de que su nombre empiece por la letra E. acerca de la situación en la que se produjo la excepción. Suele ser muy útil crear clases de excepciones propias para controlar las situaciones anómalas de nuestra aplicación. En ObjGraf. podría ser interesante que incorporara una propiedad que indicara cual era el máximo de memoria disponible cuando se lanzó la excepción.Tratamiento de excepciones 6. en file:///D|/Manuales/intro/6. no tiene ningún miembro (propiedades o métodos). se le pueden añadir. en realidad lo que se hace es crear un objeto de la clase que se le indique a throw(). que podrá ser utilizada por la sección de código que lo trate.2. Aunque en el ejemplo anterior la clase creada para la excepción. Por ejemplo. Éstos servirán para poder incorporar información en el objeto excepción.1. Lanzamiento de excepciones El lanzamiento de una excepción se realiza llamando a la función throw(). Especificación de excepciones C++ cuenta con una característica denominada especificación de excepciones.

// Ajustar al margen derecho throw EFueraRango(). Si queremos que un método pueda lanzar un determinado tipo de excepción deberemos especificarlo de esta manera. En ObjGraf.Ancho.Alto. // Ajustar al margen superior throw EFueraRango(). en la clase TObjGraf: //*************************************************/ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int FX.Alto)) { // Demasiado alta FY = PaintBox->Height . // Correcto: escribir sin modificar } void TObjGraf :: SetY (int _Y) throw (EFueraRango) { if (_Y < 0) { // Coordenada negativa FY = 0. las excepciones que puede lanzar un método.crean un (int _Y) throw (EFueraRango). // Ajustar al margen inferior throw EFueraRango(). void SetX void SetY EFueraRango (int _X) throw (EFueraRango). // Lanzar excepcion } else if (_X > (PaintBox->Width . En ObjGraf.. int FY. // Lanzar excepcion file:///D|/Manuales/intro/6.Tratamiento de excepciones una declaración.cpp: // Funciones de escritura de las propiedades virtuales X e Y void TObjGraf :: SetX (int _X) throw (EFueraRango) { if (_X < 0) { // Coordenada negativa FX = 0. // Ajustar al margen izquierdo throw EFueraRango(). // Lanzar excepcion } else if (_Y > (PaintBox->Height .Ancho)) { // Demasiado alta FX = PaintBox->Width . // Si hay problemas. // Metodo virtual puro virtual int GetAlto (void) = 0.h.html (6 of 16) [27/02/2003 16:24:19] .. // Lanzar excepcion } else FX = _X. // objeto de clase virtual int GetAncho (void) = 0. // Metodo virtual puro .

Mostrar (). } file:///D|/Manuales/intro/6. en el bloque catch. try { <bloque de instrucciones críticas> } catch (<tipo excepción1> <variable1>) { <manejador 1> } catch (<tipo excepción2> <variable2>) { . try { X += FDirX * Velocidad. } Podemos especificar tantos bloques catch para un bloque try como deseemos..html (7 of 16) [27/02/2003 16:24:19] . Si se especifica catch (.cpp: void TPelota :: Mover (void) { Borrar (). } catch (EFueraRango) { FDirX = -FDirX. en el momento que ocurra una excepción se ejecutará el bloque catch cuya clase concuerde con la de la excepción.. la captura (discriminación de la excepción que se ha producido) se efectúa en una instrucción catch y su procesamiento se realiza a continuación. }. }. try { Y += FDirY * Velocidad.3. La excepción no tiene porqué lanzarse explícitamente en el bloque try sino que puede ser consecuencia de la ejecución de una función que se ha llamado dentro de ese bloque..) se capturará cualquier excepción. Captura de excepciones El bloque susceptible de producir alguna excepción ("zona crítica") se encierra en un bloque try. } catch (EFueraRango) { FDirY = -FDirY. // Correcto: escribir sin modificar } 6.. En ObjGraf.Tratamiento de excepciones } else FY = _Y.

Modificar las funciones FormCreate() y FormDestroy() para que queden: //---------------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Pelota = new TPelota (PaintBox. Añadir a PpalFrm un TTimer (Carpeta System) y fijar Interval=100. Si no fuera sí. 25). la instrucción "crítica": X += FDirX * Velocidad. se traduce a: X = X + FDirX * Velocidad.html (8 of 16) [27/02/2003 16:24:19] . } //---------------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { delete Pelota. y como X es una propiedad virtual. en realidad se trata de hacer: SetX (FX + FDirX * Velocidad). no el entorno. Dejar únicamente la siguiente declaración global: TPelota *Pelota. 70. seleccionar Tools | Debuggber Options. donde se observa que es el método SetX() el que puede provocar el lanzamiento de la excepción. 120. Eliminar el manejador del evento OnPaint del componente PaintBox (borrando su cuerpo solamente).cpp: 1.Tratamiento de excepciones En este ejemplo. clYellow. En el evento OnTimer poner: //---------------------------------------------------------void __fastcall TPpalFrm::Timer1Timer(TObject *Sender) { Pelota->Mover(). 4. } //---------------------------------------------------------- NOTA: El entorno debe estar configurado para que el programa gestione las excepciones. 2. abrir la carpeta OS Exceptions y dejarla como se indica en file:///D|/Manuales/intro/6. En Ppal. } 3.

4: Figura 6. Excepciones no tratadas Si una excepción que ha sido lanzada no encuentra un manejador apropiado. El resultado es el mostrado en la figura 6. se llamará a la función terminate(). Dos instantes del movimiento de la pelota. aparece un mensaje que describe el tipo de error que se ha producido. la cual por defecto realiza un abort(). El motivo es que las excepciones están integradas en numerosas clases y se lanzan automáticamente cuando se presenta un situación no esperada. Clases de Excepciones.html (9 of 16) [27/02/2003 16:24:19] .Tratamiento de excepciones la figura 6. Algo muy parecido ocurre si un método lanza una excepción de un tipo que no tiene listado en su especificación de excepciones. 6. Excepciones de la VCL Si se utilizan componentes de la VCL en las aplicaciones.4. entonces se llama a la función unexpected() la cual por defecto llama a terminate(). C++ Builder incorpora un extenso conjunto de clases de excepción integradas que permiten tratar automáticamente errores de división por cero. 1. En este punto. el proyecto debe estar como se indica en el proyecto Ejemplo3. Si no se realiza un tratamiento de la excepción. la VCL llevará a cabo un tratamiento por defecto. Pero de igual manera que con terminate() podemos definir nuestra propia función unexpected() con set_unexpected(). de conversiones de tipos y otras file:///D|/Manuales/intro/6.2. Normalmente. 6.5.4. de E/S de archivos. es necesario comprender el mecanismo de tratamiento de excepciones de la VCL. Pero se puede definir nuestra propia función terminate() con la orden set_terminate().

//-------------------------------------------------------#include <vcl. HINSTANCE.5 Figura 6. Ejemplo de lanzamiento y captura de excepción VCL. int) { try { throw Exception("Mi excepción VCL"). El resultado de la ejecución del programa anterior es el mostrado en la figura 6. por lo que se deberá tener en cuenta lo siguiente: r r Las clases de excepción de tipo VCL solamente pueden capturarse por puntero o por referencia (preferible). como todas las clases de la VCL deben de localizarse en el heap (creación dinámica).h> #pragma hdrstop //-------------------------------------------------------WINAPI WinMain(HINSTANCE. Por ejemplo.ClassName()) + "\nMensaje: " + E. file:///D|/Manuales/intro/6. } return (0). LPSTR. } catch (const Exception & E) { ShowMessage("Clase de la excepción capturada: " + AnsiString(E. Las excepciones de tipo VCL deben lanzarse con sintaxis "por valor".Tratamiento de excepciones muchas situaciones anómalas. pasarse a los constructores y recuperarse mediante la propiedad Message. Todas las excepciones que descienden de Exception cuentan con un mensaje que puede presentarse en pantalla. Todas las clases excepción de VCL se derivan de un objeto raíz denominado Exception.html (10 of 16) [27/02/2003 16:24:19] . Tratamiento de Excepciones de la VCL Las excepciones de tipo VCL. } //-------------------------------------------------------- La sentencia throw del ejemplo anterior crea una instancia de la clase Exception y llama a su constructor. que encapsula las propiedades y métodos fundamentales de todas las excepciones por parte de las aplicaciones. Emplear la siguiente sintaxis para capturar las excepciones de la VCL: catch (const exception_class & exception_variable) Se especifica la clase de excepción que se desea capturar y se proporciona una variable por medio de la cual hacer referencia a la excepción. Las excepciones pueden pasarse a un bloque catch que toma un parámetro de tipo Exception.Message).5. 2.

las excepciones de la VCL si suelen ser errores. //--------------------------------------------------------------------#include <vcl. HINSTANCE. Operaciones no válidas con punteros. Captura errores de división por cero (para división entera y real. LPSTR. Clases de excepción típicas Aunque las excepciones no tienen porque indicar un error en la ejecución de una aplicación. El siguiente programa (proyecto Division2) es una ampliación del proyecto Division.h> #pragma hdrstop //--------------------------------------------------------------------WINAPI WinMain(HINSTANCE. Aunque todas estas clases funcionen de la misma manera.html (11 of 16) [27/02/2003 16:24:19] .Tratamiento de excepciones 3. Ejemplo. Veamos una selección de las clases de excepción más utilizadas en C++ Builder. respectivamente). En éste se van a discriminar distintas excepciones. Representa un error de E/S de archivo. Datos incompatibles con una máscara especificada. Indica un error de impresión. Especifica un error de acceso a base de datos. más que capturar cualquier excepción. int) { file:///D|/Manuales/intro/6. cada una de ellas tiene particularidades derivadas de la excepción concreta que indican. Clase EAccessViolation EDatabaseError EDBEditError EDivByZero EZeroDivide EInOutError EInvalidPointer EPrinterError Descripción Error de acceso a memoria.

else { // Leer divisor y convertirlo Valor =InputBox ("Division". catch (Exception & e) { ShowMessage ("Se produjo una excepción: "+AnsiString(e. Divisor.6.6: Figura 6. ""). "Dividendo".ClassName())+ "\n " + e.Message). ShowMessage ("Cociente = " + AnsiString(Cociente)). Ejemplo de división por cero. file:///D|/Manuales/intro/6. "").").html (12 of 16) [27/02/2003 16:24:19] . Cociente = (Dividendo / Divisor). Divisor = StrToFloat (Valor). float sigo = true. float Dividendo. "Divisor". Cociente. } } // try // Se captura si se ha realizado una división por cero.Tratamiento de excepciones AnsiString Valor. Dividendo = StrToFloat (Valor). while (sigo) { try { // Leer dividendo y convertirlo Valor =InputBox ("Division". if (Dividendo == 0) sigo = false. catch (EZeroDivide & ) { ShowMessage ("El divisor no puede ser cero. } //--------------------------------------------------------------------- Si se intenta realizar una division por cero el resultado es el que se indica en la figura 6. } } // while sigo return (0). } // Más general: se alcanza si no se captura la anterior.

7. la función StrToFloat() lanzaría una excepción EConvertError que se captura con el último bloque catch (ver figura 6. Es más.8). si se produjera algún tipo de desbordamiento también podría controlarse con el último bloque catch (ver figura 6. file:///D|/Manuales/intro/6. Figura 6. Ejemplos de desbordamiento: A) En la entrada de datos y B) En el cálculo del cociente.Tratamiento de excepciones Si se introdujera un dato incorrecto.html (13 of 16) [27/02/2003 16:24:19] . Ejemplo de entrada incorrecta. Figura 6.7).8.

Otra manera de capturar la división por cero. } file:///D|/Manuales/intro/6.Message).9. Para finalizar. Figura 6.html (14 of 16) [27/02/2003 16:24:19] .9). si añadimos el siguiente bloque catch entre los dos anteriores: catch (EMathError & e) { ShowMessage ("Operación no válida: " + e.Tratamiento de excepciones Si quitáramos el primer bloque catch podría capturarse la interrupción EZeroDivide (ver figura 6.

html (15 of 16) [27/02/2003 16:24:19] .Tratamiento de excepciones y consideramos (una parte de) la jerarquía de clases de excepciones: TObject-->Exception-->EExternal-->EMathError-->(EZeroDivide. Otra manera de capturar desbordamientos: A) En la entrada de datos y B) En el cálculo del cociente. .. file:///D|/Manuales/intro/6.) el alumno deberá interpretar el resultado de la figura 6.10: Figura 6..10. EOverflow. EJERCICIO: Reproductor de sonidos.

html (16 of 16) [27/02/2003 16:24:19] .Tratamiento de excepciones Página principal © Francisco Cortijo Bon file:///D|/Manuales/intro/6.

En este ejemplo se muestra el tratamiento de excepciones para el movimiento de la pelota.OOP .res").CPP //---------------------------------------------------------------------- #include <vcl. } return 0. &PpalFrm). int) { try { Application->Initialize().Ejemplo 3 Curso de C++ Builder Ejemplo 3 Corresponde al final de la sección 7. //---------------------------------------------------------------------WINAPI WinMain(HINSTANCE.H file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. LPSTR. } //---------------------------------------------------------------------- PPAL. HINSTANCE. USEFORM("Ppal. } catch (Exception &exception) { Application->ShowException(&exception). PpalFrm).cpp"). USEUNIT("ObjGraf. Application->CreateForm(__classid(TPpalFrm). EJEMPLO.h> #pragma hdrstop USERES("Ejemplo3. Application->Run().html (1 of 10) [27/02/2003 16:24:20] .cpp".

html (2 of 10) [27/02/2003 16:24:20] . public: // User declarations __fastcall TPpalFrm(TComponent* Owner). TBitBtn *BotonSalir. TTimer *Timer1.h> #pragma hdrstop file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3.OOP .CPP //---------------------------------------------------------------------#include <vcl. void __fastcall BotonSalirClick(TObject *Sender).hpp> <Forms.hpp> <StdCtrls.hpp> <Controls. //---------------------------------------------------------------------#endif PPAL. private: // User declarations TPelota *Pelota. }. //---------------------------------------------------------------------extern PACKAGE TPpalFrm *PpalFrm. void __fastcall FormDestroy(TObject *Sender). void __fastcall Timer1Timer(TObject *Sender).hpp> <ExtCtrls.hpp> #include "ObjGraf. void __fastcall FormCreate(TObject *Sender).Ejemplo 3 //---------------------------------------------------------------------#ifndef PpalH #define PpalH //---------------------------------------------------------------------#include #include #include #include #include <Classes.hpp> //---------------------------------------------------------------------class TPpalFrm : public TForm { __published: // IDE-managed Components TPaintBox *PaintBox.h" #include <Buttons.

dfm" TPpalFrm *PpalFrm. } //---------------------------------------------------------------------void __fastcall TPpalFrm::BotonSalirClick(TObject *Sender) { Application->Terminate(). 120.OOP .H //---------------------------------------------------------------------#ifndef ObjGrafH #define ObjGrafH file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3.Ejemplo 3 #include "Ppal. 25). //---------------------------------------------------------------------__fastcall TPpalFrm::TPpalFrm(TComponent* Owner) : TForm(Owner) { } //---------------------------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Pelota = new TPelota (PaintBox. 70. } //---------------------------------------------------------------------- OBJGRAF.h" //---------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*. } //---------------------------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { delete Pelota.html (3 of 10) [27/02/2003 16:24:20] . } //---------------------------------------------------------------------void __fastcall TPpalFrm::Timer1Timer(TObject *Sender) { Pelota->Mover(). clYellow.

file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. // Metodo virtual puro __property __property __property __property __property }. {read=FY. write=SetY }.html (4 of 10) [27/02/2003 16:24:20] . write=FColor}. // objeto de clase virtual int GetAncho (void) = 0. //*************************************************/ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int FX. TObjGraf (TObjGraf *ObjGraf). //*************************************************/ class EFueraRango {}. {read=GetAncho }. *PaintBox. // Si hay problemas. int FY. int _Y=0). FColor.Ejemplo 3 //*************************************************/ // Definicion de la clase EFueraRango // Clase de excepcion por entrar en "fuera de rango": // salirse de los limites del PaintBox al calcular // las nuevas coordenadas de dibujo de la pelota. TColor _Color=clBlack.crean un (int _Y) throw (EFueraRango). // Metodo virtual puro protected: TColor TPaintBox public: // Constructores de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. {read=FColor. int _X=0. {read=GetAlto }. void SetX void SetY EFueraRango (int _X) throw (EFueraRango). // Metodo virtual puro virtual int GetAlto (void) = 0. // Otros metodos virtual void Mostrar (void) = 0. write=SetX }.OOP . int int TColor int int X Y Color Ancho Alto = = = = = {read=FX.

TColor _Color=clBlack. int _Y=0.html (5 of 10) [27/02/2003 16:24:20] . NO=10}. SE=5. // TPelota deriva de la clase TCirculo. // Instanciacion del metodo virtual puro de // la clase TObjGraf __property int Radio = }. inline int GetAncho inline int GetAlto public: // Constructores TCirculo (TPaintBox *_PaintBox. int _X=0. int _Radio=1). // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { private: int FRadio. (void) {return(FRadio*2).OOP . {read=FRadio. write=FRadio}. // Otros metodos void Mostrar (void). SO=9. O=8. que a su // vez deriva de la clase base TObjGraf //*************************************************/ enum TDireccion {S=1. /* Tipo definido por enumeracion para la direccion de TPelota La codificacion es: NO 10 \ \ O 8 ---/ / 9 SO */ N 2 | | | | 1 S NE 6 / / ---.Ejemplo 3 //*************************************************/ // Definicion de la clase derivada TCirculo.} (void) {return(FRadio*2). NE=6.4 E \ \ 5 SE file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. N=2. E=4.} //*************************************************/ // Definicion de la clase derivada TPelota.

} file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. int _Velocidad=5). int FDirY. TDireccion _Direccion=SE. TColor _Color=clBlack. void Borrar (void). int FVelocidad. int _X=0. inline int GetAncho inline int GetAlto public: // Constructores TCuadrado (TPaintBox *_PaintBox. //*************************************************/ // Definicion de la clase derivada TCuadrado. __property int Velocidad = {read = FVelocidad. write=SetDireccion}. int _Lado=1). SetDireccion (TDireccion _Direccion). // Otros metodos (void) {return(FLado). TColor _Color=clBlack.} (void) {return(FLado). }.html (6 of 10) [27/02/2003 16:24:20] . int _Y=0. int _Radio=1. int _X=0. void Mover (void). void TDireccion public : // Constructores TPelota (TPaintBox *_PaintBox. int _Y=0. GetDireccion (void).Ejemplo 3 class TPelota: public TCirculo { private: int FDirX. __property TDireccion Direccion = {read = GetDireccion. // Otros metodos void Mostrar (void). // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { private: int FLado.OOP . write=FVelocidad}.

TColor _Color.html (7 of 10) [27/02/2003 16:24:20] . FX = ObjGraf->FX. int _Y) { PaintBox = _PaintBox. FX = _X. OBJGRAF. FY = ObjGraf->FY.OOP . int _X. // Instanciacion del metodo virtual puro de // la clase TObjGraf __property int Lado = }. FY = _Y. FColor = _Color.CPP //---------------------------------------------------------------------#include <vcl.h" //---------------------------------------------------------------------#pragma package(smart_init) /*****************************************************/ // Metodos asociados a la clase base TObjGraf /*****************************************************/ // Constructores TObjGraf :: TObjGraf (TPaintBox *_PaintBox.Ejemplo 3 void Mostrar (void). } // Funciones de escritura de las propiedades virtuales X e Y void TObjGraf :: SetX (int _X) throw (EFueraRango) file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. //---------------------------------------------------------------------#endif {read=FLado. FColor = ObjGraf->Color. } TObjGraf :: TObjGraf (TObjGraf *ObjGraf) { PaintBox = ObjGraf->PaintBox. write=FLado}.h> #pragma hdrstop #include "ObjGraf.

} /*****************************************************/ // Metodos asociados a la clase derivada TCirculo. } /*****************************************************/ file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. X+Radio*2.Ancho. _Y) { Radio = _Radio. // TCirculo deriva de la clase base TObjGraf.Ancho)) { FX = PaintBox->Width . } else FX = _X. throw EFueraRango(). Y+Radio*2).Alto)) { FY = PaintBox->Height . int _Radio) : TObjGraf (_PaintBox.Ejemplo 3 { if (_X < 0) { FX = 0. throw EFueraRango(). /*****************************************************/ TCirculo :: TCirculo (TPaintBox *_PaintBox. _Color.OOP . } else if (_Y > (PaintBox->Height . Y. throw EFueraRango(). throw EFueraRango(). _X. PaintBox->Canvas->Brush->Color = Color. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCirculo :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. int _X.Alto. } void TObjGraf :: SetY (int _Y) throw (EFueraRango) { if (_Y < 0) { FY = 0. } else FY = _Y. TColor _Color. } else if (_X > (PaintBox->Width .html (8 of 10) [27/02/2003 16:24:20] . int _Y. PaintBox->Canvas->Ellipse(X.

PaintBox->Canvas->Brush->Color = Color. que a su // vez deriva de la clase base TObjGraf /*****************************************************/ TPelota :: TPelota (TPaintBox *_PaintBox. }. Mostrar (). }.OOP . PaintBox->Canvas->Ellipse(X. } // Otras funcione propias de TPelota void TPelota :: Borrar (void) { PaintBox->Canvas->Pen->Color = clBtnFace.html (9 of 10) [27/02/2003 16:24:20] . // TPelota deriva de la clase TCirculo. int _Y. X+Radio*2. try { X += FDirX * Velocidad. } void TPelota :: Mover (void) { Borrar (). } catch (EFueraRango) { FDirY = -FDirY. _Color. PaintBox->Canvas->Brush->Color = clBtnFace. _Radio) { Direccion = _Direccion. int _X. } file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TPelota :: Mostrar (void) { PaintBox->Canvas->Pen->Color = clBlack. _X. int _Radio. Y+Radio*2). Y. //PaintBox->Color.Ejemplo 3 // Metodos asociados a la clase derivada TPelota. int _Velocidad) : TCirculo (_PaintBox. TColor _Color. } catch (EFueraRango) { FDirX = -FDirX. // PaintBox->Color. PaintBox->Canvas->Ellipse(X. Velocidad = _Velocidad. X+Radio*2. Y. Y+Radio*2). try { Y += FDirY * Velocidad. _Y. TDireccion _Direccion.

_Color. int _Lado) : TObjGraf (_PaintBox.Ejemplo 3 void TPelota :: SetDireccion (TDireccion _Dir) { FDirY = (_Dir & 1) ? +1 : ((_Dir & 2) ? -1 : 0).html (10 of 10) [27/02/2003 16:24:20] . Y+Lado).OOP . int _X. _X. } Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. PaintBox->Canvas->Brush->Color = Color. _Dir = (TDireccion) ((FDirY == +1) ? 1 : ((FDirY == -1 ) ? 2 : 0)). _Y) { Lado = _Lado. TColor _Color. return (_Dir). Y. // TCuadrado deriva de la clase base TObjGraf. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCuadrado :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. X+Lado. } TDireccion TPelota :: GetDireccion (void) { TDireccion _Dir. int _Y. _Dir = (TDireccion) (_Dir + (FDirX == +1) ? 4 :((FDirX == -1 )? 8:0)). PaintBox->Canvas->Rectangle(X. /*****************************************************/ TCuadrado :: TCuadrado (TPaintBox *_PaintBox. } /*****************************************************/ // Metodos asociados a la clase derivada TCuadrado. FDirX = (_Dir & 4) ? +1 : ((_Dir & 8) ? -1 : 0).

file:///D|/Manuales/intro/ejemplos/Sonidos/index.cpp como Ppal. Utilizaremos la gestión de excepciones para controlar la correcta ejecución del programa.cpp y Project1. 2.Sonidos Curso de C++ Builder Sonidos En este ejemplo se crará un formulario que contendrá un componente MediaPlayer que servirá para reproducir ficheros . MSSoundBtn. Un control MediaPlayer (pestaña System) no visible (Visible=false). Configurar el formulario. 3. Crear y configurar el proyecto.bpr como Sonidos. Cuatro botones normales (Button) llamados (Name): LogoffBtn. y. una nueva aplicación ( File | New Application). Configurar el formulario para que tenga el aspecto mostrado en la figura siguiente: Cambiar el título (Caption por Sonidos) y añadir los siguientes componentes: 1.WAV. ErrorBtn y OtrosBtn con el texto (Caption) indicado en la figura anterior. pinchar el siguiente enlace: En primer lugar.bpr 2. Para más información. 1. crear el directorio Sonidos.html (1 of 4) [27/02/2003 16:24:20] . Un botón BitBtn para terminar.Ejemplos . Guardar proyecto: Salvar Unit1. si procede.

MediaPlayer1->Wait = true. que se escribirá por encima de todas las funciones de Ppal. MediaPlayer1->Play(). try { MediaPlayer1->Open(). MediaPlayer1->Play().html (2 of 4) [27/02/2003 16:24:20] . e). } catch (Exception & e) { Error (MediaPlayer1->FileName. 3.Sonidos 4. try { MediaPlayer1->Open(). } } //-------------------------------------------------------------void __fastcall TForm1::ErrorBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\NoEsta. Así. La gestión de las interrupciones capturadas se realiza con una función común cuyo prototipo es: void Error (AnsiString & name. MediaPlayer1->Wait = true. MediaPlayer1->Close().cpp.Ejemplos . MediaPlayer1->Close(). } catch (Exception & e) { Error (MediaPlayer1->FileName. MediaPlayer1->Play(). try { MediaPlayer1->Open().wav". } } //-------------------------------------------------------------void __fastcall TForm1::MSSoundBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\The Microsoft Sound.wav". Un cuadro de diálogo OpenDialog (pestaña Dialogs). MediaPlayer1->Wait = true. e). Exception & e). Escribir los gestores de eventos asociados a la pulsación de los botones. file:///D|/Manuales/intro/ejemplos/Sonidos/index. los gestores de los eventos OnClick asociados a los botones serán los siguientes: //-------------------------------------------------------------void __fastcall TForm1::LogoffBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\Logoff.wav".

ClassName()) + "\nDetalles: " + AnsiString(e. try { MediaPlayer1->Open().Sonidos MediaPlayer1->Close().wav aparece la siguiente ventana: file:///D|/Manuales/intro/ejemplos/Sonidos/index.Ejemplos . } } // if (OpenDialog1->Execute()) } //-------------------------------------------------------------void Error (AnsiString & name. si se quiere reproducir un fichero cuyo formato no sea .html (3 of 4) [27/02/2003 16:24:20] . e). si se pulsa en el botón Error (se supone que el fichero de sonido que se quiere reproducir no existe) aparece la siguiente ventana: En cambio. } catch (Exception & e) { Error (MediaPlayer1->FileName.Message)). Exception & e) { ShowMessage ("Fallo en la reproducción del fichero de sonido: " + name + "\nExcepción: " + AnsiString(e. OpenDialog1->InitialDir = "C:\\WINDOWS". MediaPlayer1->Close(). } } //-------------------------------------------------------------void __fastcall TForm1::OtrosBtnClick(TObject *Sender) { OpenDialog1->Title = "Abrir un fichero de sonido".wav) | *. e). OpenDialog1->Filter = "Ficheros de sonido (*. } //-------------------------------------------------------------- Cuando se ejecuta este programa. if (OpenDialog1->Execute()) { MediaPlayer1->FileName = OpenDialog1->FileName. MediaPlayer1->Play(). } catch (Exception & e) { Error (MediaPlayer1->FileName.WAV". MediaPlayer1->Wait = true.

Ejemplos .html (4 of 4) [27/02/2003 16:24:20] .Sonidos Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/Sonidos/index.

html (1 of 2) [27/02/2003 16:24:20] .C++ Builder Curso de C++ Builder Programación con Hebras Introducción q ¿Por qué usar hebras? La clase TThread q q q Creación de hebras Liberación de hebras Prioridad de una hebra Ejecución de hebras q q q El método Execute() Variables locales a las hebras Control de la ejecución de una hebra: Suspend. Resume & Terminate Coordinación entre hebras q Uso de recursos compartidos r r r La hebra principal de la VCL Bloqueo de objetos Secciones críticas q Sincronización entre hebras r Esperar la finalización de una hebra file:///D|/Manuales/threads/index.

C++ Builder r Esperar a que se complete una tarea Ejemplos Página principal © Fernando Berzal Galiano file:///D|/Manuales/threads/index.html (2 of 2) [27/02/2003 16:24:20] .

html (1 of 2) [27/02/2003 16:24:21] . en general) proporciona una serie de ventajas frente a las limitaciones de los sistemas monotarea. ¿Por qué usar Hebras? El uso de hebras (de paralelismo. La depuración de las aplicaciones es difícil. podemos aprovechar los períodos de inactividad del sistema.C++ Builder Curso de C++ Builder Programación con Hebras Introducción Una aplicación multihebra es una aplicación que contiene varías vías simultáneas de ejecución. Ejemplo: Supongamos que nuestra aplicación tiene que ocuparse de la realización de copias de seguridad de los datos con los que trabaja. El diseño de aplicaciones multihebra es complejo. Las hebras han de coordinarse de algún modo. el programa debe detener completamente la ejecución mientras espera a que se realice cada tarea. Con varias hebras. Con una única hebra tendríamos que programar las copias de seguridad fuera del horario habitual de trabajo (¿y si tiene que funcionar las 24 horas del día?). Consideraciones: q q q q Cada hebra supone una carga adicional al sistema. La CPU permanece ocupada file:///D|/Manuales/threads/introduction. Aprovechamiento de los recursos del sistema Cuando se utiliza una sola hebra.

IMPORTANTE: El objetivo principal del uso de hebras es mejorar el rendimiento del sistema. Establecimiento de prioridades Como es lógico. el sistema operativo podrá asignar cada una a una de las CPUs del sistema. Si se utilizan varias hebras. un programa puede diseñarse como varios procesos paralelos que funcionen de forma independiente. Multiprocesamiento real En un sistema multiprocesador. © Fernando Berzal Galiano file:///D|/Manuales/threads/introduction. La descomposición de una aplicación en varias hebras puede resultar muy beneficiosa en términos de desacoplamiento de código (tareas independientes se implementan por separado) y de calidad del diseño (frente a futuras ampliaciones. si la aplicación se descompone en varias hebras. se le asigna mayor prioridad a las tareas más importantes (vg: las que requieran una respuesta más rápida).C++ Builder completamente (o inactiva) hasta que el proceso actual termine. por ejemplo). Estructuración: Paralelismo implícito En muchas ocasiones. el sistema puede usarse para realizar varias tareas simultáneamente (vg: reproducción de MP3s en background).html (2 of 2) [27/02/2003 16:24:21] . El diseñador/programador deberá decidir hasta qué punto deben utilizarse.

Ejemplo: Crear una hebra Abrimos el repositorio en su página New (al que se accede desde la opción del menú File->New. C++Builder incluye un asistente que lo hace por nosotros. que será el que rellenemos con el código asociado a la hebra.cpp y HPelota. Seleccionamos el elemento Thread Object. Para facilitar el trabajo. en una clase derivada de TThread se pueden añadir todos los miembros (propiedades y métodos) que se necesiten. q file:///D|/Manuales/threads/TThread.). para lo cual se ha de crear una clase derivada de TThread.. Denominamos THebraPelota a la clase derivada de TThread. Para definir una hebra se debe crear un descendiente de TThread. que contendrá el código asociado a la tarea que tenga que realizar la hebra).html (1 of 4) [27/02/2003 16:24:21] .C++ Builder Curso de C++ Builder Programación con Hebras La clase TThread C++ Builder proporciona la clase abstracta TThread para la creación de hebras. Como sucede con cualquier otra clase. Ya hemos creado nuestra primera hebra en una unidad independiente (que almacenaremos en los ficheros HPelota. Obligatoriamente sólo hay que implementar: q El constructor de la clase (que nos permitirá definir la inicialización de la hebra) El método Execute (“la función main() de la hebra”.h). La clase TThread es abstracta porque posee un método virtual puro denominado Execute()..

Dos características de las hebras conviene establecerlas en el constructor: su prioridad y cuándo debe liberarse la hebra. Si se aumenta mucho la prioridad de una hebra que requiera muchos recursos (vg: CPU) puede ocurrir que las demás hebras de la aplicación (y del sistema) no lleguen a procesarse a la velocidad adecuada.html (2 of 4) [27/02/2003 16:24:21] . Asignación de una Prioridad por Defecto La prioridad de una hebra indica qué grado de preferencia tiene la hebra cuando el sistema operativo reparte el tiempo de CPU entre las distintas hebras que se estén ejecutando en el sistema. tpTimeCritical La hebra tiene la prioridad más alta.C++ Builder Inicialización de las hebras La inicialización de una hebra se realiza en su constructor. Para indicar la prioridad del objeto de hebra hay que fijar el valor de la propiedad Priority: Valor Prioridad tpIdle Se ejecuta cuando el sistema está inactivo. tpLowest Dos puntos por debajo del valor normal. donde se establecen los valores iniciales de cuantas propiedades sean necesarias. tpLower Un punto por debajo del valor normal. tpHigher Un punto por encima del valor normal. Ejemplo: file:///D|/Manuales/threads/TThread. Éste recibe como parámetro false si deseamos que la hebra se ejecute inmediatamente después de ser creada o true si queremos que quede suspendida inicialmente. tpNormal La hebra tiene la prioridad normal. se invoca al constructor de su clase base (TThread): __fastcall TThread(bool CreateSuspended). Antes de invocar al constructor de una clase derivada de TThread. tpHighest Dos puntos por encima del valor normal.

basta con fijar el valor de la propiedad FreeOnTerminate a false. file:///D|/Manuales/threads/TThread. en el caso de que el usuario pulse el botón..h" En la clase THebraPelota: . Si este es el caso. en lugar de destruirlas y crearlas de nuevo cada vez. será responsabilidad del programador la liberación de la hebra. puede ser interesante dar la posibilidad al usuario de cancelar el proceso durante su ejecución. En este caso. MUY IMPORTANTE: Antes de liberar una hebra hay que asegurarse de que no se esté ejecutando (ya veremos cómo). __fastcall THebraPelota(TPaintBox *PaintBox). Ejemplo: q En HPelota.h: #include "ObjGraf.C++ Builder Si tenemos un proceso que consume una cantidad considerable de tiempo de CPU. La hebra de alta prioridad no consumirá tiempo de CPU porque estará bloqueada pero. responderá rápidamente. lo más sencillo es dejar que el objeto hebra se libere a sí mismo. Si la aplicación requiere varias instancias del mismo objeto hebra (para ejecutar la hebra varias veces). estableciendo la propiedad FreeOnTerminate a true. Liberación de las hebras A menudo las hebras de una aplicación se ejecutan una sola vez.. public: TPelota *Pelota. se puede aumentar el rendimiento de la aplicación almacenando las hebras en una caché para utilizarlas más adelante. hay casos en que el objeto hebra representa una tarea que debe realizarse varias veces. Para ello. Esto se puede conseguir creando una hebra con prioridad normal para ese proceso y otra hebra de alta prioridad que únicamente esté a la espera de que el usuario pulse un botón de cancelación.html (3 of 4) [27/02/2003 16:24:21] . Sin embargo.

PaintBox. random(PaintBox->Width). q En HPelota. __fastcall THebraPelota::THebraPelota (TPaintBox *PaintBox) : TThread(false) { Priority = tpNormal.cpp: #include <stdlib. random(20)+1....C++ Builder __fastcall ~THebraPelota(void). random(PaintBox->Height).... .html (4 of 4) [27/02/2003 16:24:21] .. Pelota = new TPelota ( // Objeto pelota. } © Fernando Berzal Galiano file:///D|/Manuales/threads/TThread. TDireccion((random(2)+1) | (random(2)+1)*4)). // . } __fastcall THebraPelota::~THebraPelota(void) { delete Pelota. (TColor)(random(0xFF) | (random(0xFF)*0x100) | (random(0xFF)*0x10000)).h> . FreeOnTerminate = true..aletorio.

Una hebra puede concebirse como un programa que se ejecuta dentro de la aplicación.C++ Builder Curso de C++ Builder Programación con Hebras Ejecución de las hebras El método Execute es la función principal de una hebra. Sleep(100). Ejemplo: q En HPelota.cpp: void __fastcall THebraPelota::Execute() { while (true) { // Código de la Hebra. Habrá una copia de la variable para cada una de las hebras que se creen: la variable es global para las funciones de una hebra pero no se comparte con otras hebras.html (1 of 4) [27/02/2003 16:24:21] . Por tanto. es necesario asegurarse de no escribir en la memoria que utilizan las otras hebras. } } Variables locales a las hebras Con la palabra clave __thread podemos definir variables globales que son locales a una hebra. Ejemplo: file:///D|/Manuales/threads/execution. puede utilizarse la memoria compartida entre las hebras para establecer una comunicación entre ellas. Una hebra no es un programa independiente porque comparte el mismo espacio con las demás hebras de la aplicación. Por otro lado. Pelota->Mover().

html (2 of 4) [27/02/2003 16:24:21] . Control de la ejecución de una hebra Una hebra puede encontrarse en dos estados: q q Ejecutándose. Las variables __thread han de ser estáticas (no pueden ser punteros) y no pueden inicializarse en tiempo de ejecución).C++ Builder int __thread x. Ejemplo: file:///D|/Manuales/threads/execution. Por tanto. Las hebras pueden iniciarse y suspenderse tantas veces como sea necesario antes de que finalice su ejecución. La ejecución de una hebra termina normalmente cuando termina la ejecución del método Execute(). el método Execute() ha de comprobar periódicamente el valor de la propiedad Terminated y detener la ejecución de la hebra cuando esté a true. Cuando resulte conveniente reanudar la ejecución de la hebra se debe realizar una llamada al método Resume(). Suspendida. Terminate() cambia el valor de la propiedad Terminated a true. indicando así que la hebra ha de finalizar su ejecución en cuanto sea posible. ya que se puede conseguir lo mismo añadiendo una variable de instancia a la clase de la hebra. Para detener una hebra temporalmente hay que realizar una llamada al método Suspend(). No es aconsejable utilizar este tipo de variables. Para hacer que la ejecución de una hebra finalice de forma prematura hay realizar una llamada al método Terminate(). Suspend() y Resume() utilizan un contador interno. de forma que es posible anidar las llamadas a Suspend() y Resume(). La hebra no reanuda su ejecución hasta que todas las suspensiones hayan tenido su correspondiente llamada a Resume().

} } Cuando se crea una hebra. for (int i=0. .cpp: #include <stdlib. file:///D|/Manuales/threads/execution..html (3 of 4) [27/02/2003 16:24:21] .. void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Objs = new THebraPelota*[4].h" . i<4. randomize(). Si se crea una hebra inicialmente suspendida se ha de invocar al método Resume() para comenzar su ejecución... private: // User declarations THebraPelota **Objs. ++i) Objs[i] = new THebraPelota (PaintBox). Pelota->Mover().h: Para usar la unidad HPelota desde un formulario: #include "HPelota. el estado inicial de ésta dependerá del parámetro que se le pase a su constructor: ejecutándose (false) o suspendida (true). q En Ppal. Ejemplo: q En Ppal..cpp: void __fastcall THebraPelota::Execute() { while (!Terminated) { // Código de la Hebra.h> . Sleep(100).C++ Builder q En HPelota..

. i<4. es una chapuza para evitar que se “cuelgue” la aplicación al liberar las hebras (más adelante veremos como solucionar este problema correctamente)...html (4 of 4) [27/02/2003 16:24:21] . // .C++ Builder } void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { for (int i=0. } Nota: La sentencia Sleep(3000). // Esperar tres segundos. ++i) Objs[i]->Terminate().a que se liberen todas las hebras delete[] Objs. Sleep(3000).. © Fernando Berzal Galiano file:///D|/Manuales/threads/execution.

Hay que tener cuidado para evitar que dos hebras accedan a un recurso compartido (vg: objeto o variable global) al mismo tiempo. Ejemplo: Si ejecutamos el ejemplo anterior. La hebra principal de la VCL No existe garantía alguna (en general) de que los métodos de los componentes de C++ Builder funcionen correctamente cuando son compartidos por varias hebras. Por tanto. aunque el funcionamiento de la aplicación es correcto. Esto se debe a que los métodos Mostrar() y Borrar() de las distintas hebras se entrelazan en el acceso al Canvas del PaintBox. Uso de recursos compartidos Cuando varias hebras comparten el uso de un recurso. pueden ocurrir situaciones no deseadas si dos o más hebras acceden (o intentan acceder) al mismo recurso simultáneamente.C++ Builder Curso de C++ Builder Programación con Hebras Coordinación entre hebras El código ejecutado por una hebra debe tener en cuenta la posible existencia de otras hebras que se ejecuten concurrentemente. Para evitar conflictos con otras hebras. la ejecución de una hebra puede depender del resultado de las tareas que realicen en otras hebras.html (1 of 6) [27/02/2003 16:24:22] . file:///D|/Manuales/threads/coordination. Es decir. la visualización en el PaintBox sufre algunos errores de forma aleatoria. Además. puede que se necesite bloquear la ejecución de otras hebras al acceder a objetos o variables compartidas. al acceder a propiedades o ejecutar métodos pueden efectuarse algunas operaciones que utilicen memoria no protegida de las acciones de otras hebras. Hay que tener cuidado de no bloquear innecesariamente la ejecución de otras hebras (para no disminuir el rendimiento de la aplicación). ¡Se ha de evitar el acceso simultáneo de las hebras al componente Canvas del PaintBox!. las distintas hebras de una aplicación han de coordinar su ejecución.

Para usar la hebra VCL principal hay que crear un método que realice las acciones necesarias y llamarlo utilizando el método Synchronize(). la “hebra principal de la VCL”. Si todos los objetos acceden a sus propiedades e invocan a sus métodos dentro de una única hebra. Ésta es la hebra que gestiona todos los mensajes de Windows que reciben los componentes de la aplicación. } } No siempre es necesario utilizar la hebra VCL principal (de hecho. que utilizan la biblioteca ADO).h y en ObjGraf.C++ Builder Por este motivo se reserva una hebra.cpp: void __fastcall THebraPelota::Execute() { while (!Terminated) { Synchronize(Pelota->Mover). no hay por qué preocuparse. por lo que hay que cambiar la definición del método Mover() de TPelota: void __fastcall Mover (void). además. Los componentes de acceso a datos funcionan correctamente con hebras si pertenecen a distintas sesiones (con la excepción de los controladores de Access.html (2 of 6) [27/02/2003 16:24:22] .cpp: El método Synchronize() recibe cómo parámetro un método del tipo void __fastcall <método> (void). no bloqueamos esta hebra). Ejemplo: q En ObjGraf. Esto permite aumentar el rendimiento de la aplicación porque no es necesario esperar a que la hebra VCL principal entre en su bucle de mensajes (y. Algunos componentes están preparados para funcionar con hebras (son thread-safe) y no hay necesidad de usar el método Synchronize(). file:///D|/Manuales/threads/coordination. q En HPelota. Sleep(100). en algunos casos no se puede usar y tendremos que emplear otros mecanismos como las secciones críticas). para el acceso a los objetos de la VCL.

los objetos de tipo lienzo (TCanvas y sus descendientes) cuentan con un método Lock() que impide a las otras hebras acceder al objeto hasta que se realiza una llamada al método Unlock().html (3 of 6) [27/02/2003 16:24:22] . Las secciones críticas funcionan como puertas que permiten el paso de una sola hebra cada vez. q En ObjGraf. q Bloqueo de objetos Algunos componentes cuentan con mecanismos de bloqueo para que puedan compartirse por varias hebras. PaintBox->Canvas->Unlock(). una llamada a TThreadList::LockList() devuelve el objeto de tipo TList asociado e impide que otras hebras accedan a la lista hasta que se realice una llamada a UnlockList(). Por ejemplo.. Las llamadas a los métodos TCanvas::Lock o TThreadList::LockList pueden anidarse con seguridad. TPen. El desbloqueo no se produce hasta que se haya realizado una llamada de desbloqueo por cada llamada de bloqueo. No se necesita utilizar la hebra VCL principal acceder a TFont. TMetafile ni TIcon. Algunos componentes (por ejemplo. Secciones críticas Si un objeto no cuenta con mecanismos de bloqueo incorporados. Ejemplo: q En HPelota.C++ Builder q Los objetos gráficos funcionan correctamente con hebras. siempre se puede utilizar una sección crítica. Para compartir el uso de objetos lienzo (TCanvas y descendientes) hay que bloquearlos antes. En el caso de TThreadList. .cpp: Eliminar la llamada al método Synchronize() realizada desde el método THebraPelota::Execute().cpp: Tanto en TPelota::Mostrar() como en TPelota::Borrar(): PaintBox->Canvas->Lock(). TBitmap.. Para utilizar una sección crítica hay que crear una instancia global de file:///D|/Manuales/threads/coordination. TBrush. TList) tienen una versión adecuada para funcionar con varias hebras (TThreadList).

Cada sección crítica se asocia a un recurso que se desea compartir por varias hebras. Al finalizar sus operaciones..cpp: #include <syncobjs. TCriticalSection cuenta con dos métodos: Acquire() (que impide a otras hebras acceder a la sección crítica) y Release() (que elimina el bloqueo). eliminar el bloqueo del objeto de tipo TCanvas y emplear en su lugar la sección crítica: { SC->Acquire(). En TPelota::Mostrar() y en TPelota::Borrar().. // ¡¡¡Habría que destruirla!!! .hpp> TCriticalSection *SC = new TCriticalSection(). las hebras tienen que realizar una llamada al método Release() para que las demás hebras puedan acceder al recurso invocando al método Acquire(). file:///D|/Manuales/threads/coordination. SC->Release(). por lo cual será necesario que en ciertas ocasiones una hebra espere a que otra termine la ejecución de una acción determinada.html (4 of 6) [27/02/2003 16:24:22] ..C++ Builder TCriticalSection. .. Ejemplo: q En ObjGraf. Todas las hebras que accedan a un mismo recurso deberán utilizar el método Acquire() de la correspondiente sección crítica para asegurarse de que el recurso no está siendo utilizado por ninguna otra hebra. Si se omite la llamada a Release() el recurso quedaría bloqueado para siempre. } Sincronización entre hebras Puede que las distintas hebras de una aplicación realicen tareas que no sean completamente independientes.

C++ Builder

Ejemplo: Tenemos que dos hebras que calculan el total de ingresos y el total de gastos de una compañía respectivamente. Una tercera hebra ha de obtener el balance final, por lo que deberá esperar a que las dos hebras anteriores terminen su trabajo.

Esperar la finalización de una hebra
Para esperar a que finalice la ejecución de otra hebra, se puede utilizar el método WaitFor() de la otra hebra. WaitFor() bloquea la ejecución de la hebra actual hasta que la otra hebra se haya cerrado, ya sea por haber finalizando la ejecución de su método Execute() o por haberse producido una excepción. WaitFor() devuelve un valor entero que es el valor de la propiedad ReturnValue de la hebra. La propiedad ReturnValue puede cambiarse en el método Execute() y su significado se lo daremos nosotros. Ejemplo:
q

En Ppal.cpp:

void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { int i; for (i=0; i<4; i++) Objs[i]->Terminate(); for (i=0; i<4; i++) Objs[i]->WaitFor(); delete[] Objs; }

Esperar a que se complete una tarea: Sucesos
En algunas ocasiones es necesario esperar a que otra hebra haya realizado una tarea determinada sin que ello implique que haya finalizado su ejecución. En estos casos hay que utilizar un objeto de tipo suceso (TEvent).

file:///D|/Manuales/threads/coordination.html (5 of 6) [27/02/2003 16:24:22]

C++ Builder

Cuando una hebra completa una operación de la que dependen otras hebras, realiza una llamada a TEvent::SetEvent(). SetEvent() activa una señal que cualquier otra hebra puede detectar invocando al método TEvent::WaitFor(). Para desactivar esa señal existe el método TEvent::ResetEvent(). El método WaitFor() espera un tiempo determinado (establecido en milisegundos al llamar al método) hasta que se active la señal. WaitFor() puede devolver uno de los siguientes valores: Valor Significado wrSignaled La señal asociada al suceso se ha activado. wrTimeout Ha transcurrido el tiempo especificado sin que la señal se activase. wrAbandoned El objeto de tipo TEvent se destruyó antes de que se llegase al time-out. Se ha producido un error durante la espera. El código del error concreto se wrError puede obtener de la propiedad TEvent::LastError. Si se desea seguir a la espera de un suceso indefinidamente puede pasar el valor INFINITE como parámetro del método WaitFor(). Pero tenga cuidado, la hebra se quedará bloqueada para siempre si nunca llegara a producirse el evento que espera. NOTA: El componente TEvent no es más que un wrapper de un evento de Windows.

© Fernando Berzal Galiano

file:///D|/Manuales/threads/coordination.html (6 of 6) [27/02/2003 16:24:22]

Acceso a bases de datos

Curso de C++ Builder Acceso a bases de datos
Introducción
q q q

Bases de datos locales Bases de datos cliente/servidor Arquitecturas multicapa

El motor de bases de datos de Borland (BDE)
q

Configuración del driver para InterBase

Componentes de acceso a bases de datos
q q

El asistente para formularios de bases de datos Bases de datos de demostración

Controles de acceso a datos
q q q

Bases de datos con fechas Rejillas Pistas y trucos

El componente TDataSource
file:///D|/Manuales/databases/index.html (1 of 3) [27/02/2003 16:24:22]

Acceso a bases de datos

q

TDataLink: Componentes "data-aware"

Conjuntos de datos
q q q q q q q

TDataSet y sus derivados Cursores Actualizaciones en caché El componente TTable: Tablas El componente TQuery: Consultas SQL El componente TStoredProc: Procedimientos almacenados El componente TField: Acceso a los campos

Sesiones y conexiones
q q

El componente TSession El componente TDatabase

Herramientas y utilidades
q q q q q

BDE Administrator Database Desktop SQL Explorer SQL Monitor Datapump

Ejemplos y ejercicios
q q q

q

q

Un componente 'data-aware': TDBDateTimePicker Un formulario: Un diálogo de búsqueda genérico Una aplicación sencilla (Paradox): Gestión de una pequeña base de datos culinaria Una aplicación algo más compleja (InterBase): Diccionario de citas Ejercicio: Desarrollo completo de una aplicación

Apéndice: SQL
file:///D|/Manuales/databases/index.html (2 of 3) [27/02/2003 16:24:22]

Acceso a bases de datos

Página principal © Fernando Berzal Galiano

file:///D|/Manuales/databases/index.html (3 of 3) [27/02/2003 16:24:22]

C++ Builder

Curso de C++ Builder Acceso a Bases de Datos
Acceso a bases de datos relacionales

La mayoría de las aplicaciones de gestión requieren el acceso a bases de datos. C++ Builder incluye componentes que facilitan enormemente el desarrollo de aplicaciones que interactúan con bases de datos. Usualmente trabajaremos con bases de datos relacionales (bases de datos constituidas por tablas). Antes de seguir, definamos dos conceptos básicos:
q

Cursor: Un indicador del registro que se está insertando, modificando o consultando en una tabla relacional, entendiendo ésta en su sentido más amplio (una tabla de la base de datos o la tabla resultado de una consulta). Conjunto de Datos [Dataset]: Una colección de datos obtenido de una base de datos. Un dataset puede ser algo más que los datos incluidos en una tabla; podría ser el resultado de una consulta que contenga datos provenientes de más de una tabla.

q

Bases de Datos Locales
El modelo más sencillo de aplicación que accede a bases de datos es aquél en el cual se accede a bases de datos locales, también denominadas bases de datos de escritorio La base de datos reside en una sola máquina (generalmente la misma en la que se ejecuta la aplicación), y sólo puede tener acceso a la misma un único usuario. Ejemplos de este modelo son dBase, Paradox, Approach o Access.

Bases de Datos Cliente/Servidor
En este caso, un gestor de bases de datos (DBMS) mantiene la base de datos. El
file:///D|/Manuales/databases/introduction.html (1 of 2) [27/02/2003 16:24:23]

C++ Builder

almacenamiento y gestión del acceso a los datos los realiza el gestor (el servidor). Los gestores de bases de datos relacionales también se conocen como servidores SQL, por ser éste el lenguaje que se utiliza para acceder a los datos. Oracle, IBM DB2, InterBase y SQL Server entran dentro de esta categoría. Las aplicaciones de los usuarios (los clientes) hacen peticiones al servidor utilizando algún protocolo predefinido, CLI [Call-Level-Interface] en inglés, que puede ser un estándar (ODBC, JDBC o BDE) o específico de la base de datos que utilicemos. Como es lógico, varios usuarios situados en distintos puestos de trabajo de una red pueden compartir el mismo servidor SQL, que será el responsable de mantener la "acidez" de las transacciones [Atomicity-Consistency-Isolation-Durability].

Arquitecturas multicapa
q

Las aplicaciones que acceden a bases de datos locales corresponden a una arquitectura de una sola capa: las aplicaciones conectan directamente con la base de datos. El modelo cliente/servidor corresponde a una arquitectura con dos capas: el servidor SQL por un lado y las aplicaciones que se conectan como clientes del servidor por otro. También existen arquitecturas multicapa con más de dos capas: las aplicaciones se conectan a servidores de aplicaciones, que son los que acceden a los servidores de bases de datos. En este caso se suele hacer uso de middleware: CORBA, DCOM, DataSnap (=MIDAS)...

q

q

© Fernando Berzal Galiano

file:///D|/Manuales/databases/introduction.html (2 of 2) [27/02/2003 16:24:23]

C++ Builder proporciona el Borland Database Engine (BDE). Ejemplo file:///D|/Manuales/databases/bde. El BDE necesita un "alias" para acceder a una base de datos particular. Un alias de BDE establece el conjunto de parámetros que se requieren para establecer una conexión con una base de datos. El BDE es un CLI [Call-Level Interface] que hace de intermediario entre las aplicaciones y las bases de datos a las que se accede.C++ Builder Curso de C++ Builder Acceso a bases de datos BDE El Motor de Bases de Datos de Borland Para permitir el acceso a bases de datos locales y servidores SQL. que no es más que una colección de DLLs. de forma que éstas sean independientes de la base de datos que se utilice. Los alias se definen con ayuda del BDE Administrator (que se encuentra en el Panel de Control de Windows). tales como el controlador [driver] empleado y la localización de la base de datos.html (1 of 3) [27/02/2003 16:24:23] .

html (2 of 3) [27/02/2003 16:24:23] . ENABLE SCHEMA CACHE ahorra tiempo y ancho de banda: r r r r q ENABLE SCHEMA CACHE = TRUE SCHEMA CACHE DIR = ..ini & *. y el formulario con el nombre Ppal. q Configuración del driver para InterBase q ENABLE BCD para poder trabajar con números decimales con una precisión especificada (si no hay que utilizar datos de tipo entero o real!!).scf) SCHEMA CACHE SIZE = 32 SCHEMA CACHE TIME = -1 q DRIVER FLAGS = 4608 r r 4092: isc_commit_retaining (para confirmar las transacciones implícitas) + COMMIT RETAIN = TRUE para transacciones explícitas. 512: Nivel de aislamiento superior para las transacciones implícitas (lecturas repetibles). q Ver qué valores se pueden seleccionar para la propiedad DataBaseName. Guardar el proyecto con el nombre BDEje.. q WAIT ON LOCKS: ¿Esperar a que un registro esté disponible? Uso de TCP/IP como protocolo de comunicación con el servidor (de forma que no hace falta instalar el cliente y las utilidades de administración de InterBase en todos los puestos): r q Añadir la entrada "gds_db 3050/tcp" al fichero services de Windows (subdirectorio system32\drivers\etc) q Alias (parámetro SERVER NAME): file:///D|/Manuales/databases/bde. NOTA: El nivel de lecturas repetibles no es adecuado para las aplicaciones que tienen que estar pendientes de las actualizaciones realizadas en otros puestos. los alias BDE disponibles en la máquina. (destino de scache.cpp.C++ Builder Crear una aplicación nueva. q Añadir un componente TTable (en la página Data Access) al formulario.

html (3 of 3) [27/02/2003 16:24:23] .C++ Builder r r NetBEUI: //host/db TCP/IP: host:/db © Fernando Berzal Galiano file:///D|/Manuales/databases/bde.

Para utilizar el asistente hay que seguir los siguientes pasos: 1.. Llamar al asistente como si fuésemos a añadir a nuestro proyecto un formulario más (con "File/New. El componente TDataSource (enlace entre los anteriores) q q El asistente Aunque podemos crear nuestras aplicaciones de bases de datos directamente a partir de los componentes de bases de datos.C++ Builder Curso de C++ Builder Acceso a Bases de Datos Componentes de acceso a Bases de Datos Los componentes de la VCL para el acceso a bases de datos se dividen en categorías siguiendo el modelo MVC (Model-View-Controller): q Controles de acceso a datos (visuales). Conjuntos de datos (no visuales).."). C++ Builder nos ofrece un "potente" asistente para generar formularios sencillos que accedan a bases de datos.html (1 of 16) [27/02/2003 16:24:25] . seleccionando "Database Form Wizard" de la pestaña "Business": file:///D|/Manuales/databases/components.

2. Seleccionamos la tabla a la cual deseamos acceder. Seleccionar el tipo de formulario que deseemos (simple o maestro/detalle) y cómo queremos generarlo (mediante tablas o consultas). En este caso. Para comenzar.html (2 of 16) [27/02/2003 16:24:25] . seleccionamos la base de datos de file:///D|/Manuales/databases/components.C++ Builder También se puede llamar al asistente directamente desde la opción Form Wizard del menú Database. optaremos por un formulario simple construido con una tabla (TTable): 3.

hemos de indicar qué campos incluiremos en nuestro formulario. file:///D|/Manuales/databases/components. Ahora podemos escoger la disposición de los controles en el formulario: horizontal. LENGTH_IN (<): 5. Probaremos inicialmente con la disposición horizontal de los controles en el formulario. vertical o en una rejilla. la tabla BIOLIFE.html (3 of 16) [27/02/2003 16:24:25] .DB: 4. Una vez seleccionada la tabla. dentro de ella.C++ Builder demostración que aparece bajo el alias de BCDEMOS y. Seleccionamos todos (>>) menos la longitud en pulgadas.

html (4 of 16) [27/02/2003 16:24:25] . El resultado obtenido es el siguiente: file:///D|/Manuales/databases/components.C++ Builder 6. Finalmente. le indicamos al asistente que cree un formulario acompañado por un módulo de datos independiente (para separar los objetos que modelizan los conjuntos de datos de los controles que constituyen la vista de esos conjuntos de datos): 7.

Por desgracia.html (5 of 16) [27/02/2003 16:24:25] . además. ha puesto todos los campos de la tabla como si se pudiesen editar con un simple TDBEdit. si queremos que las etiquetas que indican los nombres de los campos aparezcan a la izquierda o encima de los controles que nos permiten editarlos.C++ Builder El formulario de la imagen está bien aunque aún necesita algunos retoques. Por ejemplo. al indicarle al asistente que pusiese los campos horizontalmente. los campos de tipo MEMO (textos) o BLOB (imagen en el ejemplo) no deben mostrarse en una simple caja de edición. Para evitar el error que se producía anteriormente (el uso indiscriminado de cajas de edición incluso para las imágenes). Disposición vertical de los controles 5. podemos optar por disponer los campos verticalmente (tal como se hace desde tiempos del dBase): 6. Seleccionamos la primera de las opciones: file:///D|/Manuales/databases/components. Hemos de indicar.

y el resultado que obtenemos es el siguiente: file:///D|/Manuales/databases/components.. le indicamos al asistente que cree un formulario acompañado por un módulo de datos independiente: 8.C++ Builder 7.html (6 of 16) [27/02/2003 16:24:25] . . Como en el ejemplo anterior..

para que se vea correctamente la imagen.C++ Builder Este formulario está algo mejor que el inicial y. sólo hemos de poner a true la propiedad Stretch del control que nos la muestra (el único TDBImage del formulario) y ajustar un poco el tamaño de los distintos controles. Formularios maestro/detalle Utilicemos ahora el asistente para algo un poco más complejo: 1. Creamos ahora un formulario maestro/detalle (master/detail) con objetos de tipo TTable para modelizar los conjuntos de datos: file:///D|/Manuales/databases/components.html (7 of 16) [27/02/2003 16:24:25] .

una tabla que contiene información acerca de los clientes de una empresa: 3.html (8 of 16) [27/02/2003 16:24:25] . Escogemos los campos que nos interese mostrar y los ordenamos utilizando los botones que aparecen debajo de la lista de campos seleccionados: file:///D|/Manuales/databases/components.C++ Builder 2.DBF de la base de datos BCDEMOS como tabla maestra del formulario. Seleccionamos la tabla CLIENTS.

C++ Builder 4.html (9 of 16) [27/02/2003 16:24:25] . Indicamos que los campo de la tabla maestro los dispondremos verticalmente (para evitar que nos pase lo de antes con las imágenes y los textos): file:///D|/Manuales/databases/components.

DBF de la base de datos BCDEMOS (tabla que contiene las inversiones en bolsa de nuestros clientes): 6. que será la tabla HOLDINGS.html (10 of 16) [27/02/2003 16:24:25] .C++ Builder 5. Seleccionamos la tabla detalle. Escogemos todos sus campos: file:///D|/Manuales/databases/components.

C++ Builder 7.DBF y HOLDINGS. a través del índice existente sobre la columna ACCT_NBR: file:///D|/Manuales/databases/components.DBF. las tablas detalle siempre se muestran en rejillas: 8. Y seleccionamos una rejilla para visualizarlos ya que. usualmente. Para completar nuestro formulario maestro/detalle hemos de especificar cómo se reliza la reunión entre las tablas CLIENTS.html (11 of 16) [27/02/2003 16:24:25] .

le indicamos al asistente que cree un formulario acompañado por un módulo de datos independiente: file:///D|/Manuales/databases/components.html (12 of 16) [27/02/2003 16:24:25] . Como siempre.C++ Builder 9.

C++ Builder 10. la presentación será la adecuada para incluirlo en alguna de nuestras aplicaciones: file:///D|/Manuales/databases/components. con unos cuantos retoques.html (13 of 16) [27/02/2003 16:24:25] . Voilà! Ya tenemos listo un formulario maestro/detalle y.

cualquier aplicación real requerirá formularios más complejos que los vistos hasta ahora y tendremos que olvidarnos del asistente y crearlos nosotros mismos. Tabla maestra: Alias BCDEMOS. tabla customer. tabla reservat.C++ Builder Ejercicios prácticos q Tipo del Formulario: maestro/detalle con objetos TTable.db. q q q Tipo del Formulario: maestro/detalle con objetos TTable. Tabla maestra: Alias BCDEMOS.db.db. tabla orders. Addr1. SaleDate. Tipo del Formulario: maestro/detalle con objetos TTable. q Campos de la tabla maestra: CustNo.db. Tabla maestra: Alias BCDEMOS. tabla master. TaxRate. q Disposición de los campos de la tabla maestra: Horizontally. tabla parts.db. tabla employee. Tipo del Formulario: maestro/detalle con objetos TTable. el asistente nos permite crear rápidamente formularios que nos permiten gestionar conjuntos de datos. tabla master.db. Company. Tipo del Formulario: maestro/detalle con objetos TTable. Tabla detalle: Alias BCDEMOS. Ejercicios para los cuales el asistente se queda corto file:///D|/Manuales/databases/components. Tabla maestra: Alias BCDEMOS. q Definir la reunión (join) seleccionando el índice CustNo: join CustNo -> CustNo. Country.db. Tabla maestra: Alias BCDEMOS. Tabla detalle: Alias BCDEMOS.db. q Tabla detalle: Alias BCDEMOS. OrderNo.db. Tabla detalle: Alias BCDEMOS. Tipo del Formulario: maestro/detalle con objetos TTable. tabla event. Tipo del Formulario: maestro/detalle con objetos TTable.db. Tabla detalle: Alias BCDEMOS. q Campos de la tabla detalle: CustNo. tabla holdings. Tabla maestra: Alias BCDEMOS.db.db. City. tabla industry.html (14 of 16) [27/02/2003 16:24:25] .db. Tabla detalle: Alias BCDEMOS. q Tabla maestra: Alias BCDEMOS. State.db. q Disposición de los campos de la tabla detalle: In a Grid. q q q q q q q q q q q q q q q Limitaciones del asistente Como hemos visto. tabla items. ItemsTotal (en ese orden). Phone (en ese orden). tabla orders. tabla orders. tabla vendors. No obstante. Tabla detalle: Alias BCDEMOS.

db).html (15 of 16) [27/02/2003 16:24:25] .db) y los clientes que acuden a cada recinto (custoly.dbf) de cada cliente (clients. no sólo su símbolo.db) con los pedidos realizados hasta el momento (orders. Mostrar los pedidos de cada cliente (orders.dbf).dbf) o el importe total de lo que ha ganado cada proveedor (vendors.db y parts. que además está relacionada con vendors.C++ Builder Mostrar la relación entre los lugares en que se celebran actividades (venues.db) realizadas por clientes (custoly.db).db) y una serie de reservas (reservat.db).db) tiene un lugar de celebración (venues. Bases de datos de demostración Base de datos de inversiones en bolsa Base de datos de reserva de entradas Base de datos de pedidos file:///D|/Manuales/databases/components.db) y el proveedor de cada pìeza (relación entre items. Mostrar el total de inversiones (holdings.dbf y clients.db como detalle de customer.db.db). Mostrar las inversiones de los clientes (relación entre holdings.dbf) indicando el nombre de las empresas en las que se invierte (almacenado en master. Cada evento (event.db) indicando los detalles de los pedidos (items.

DB completan el conjunto de bases de datos incluidas como ejemplo en la distribución del C++Builder.html (16 of 16) [27/02/2003 16:24:25] .C++ Builder NOTA: Las tablas ANIMALS.DBF. BIOLIFE.DB y COUNTRY. © Fernando Berzal Galiano file:///D|/Manuales/databases/components.

presentaremos los distintos controles de datos del C++ Builder Controles orientados a conjuntos de datos Control Descripción Rejilla de datos: Muestra un DataSource con aspecto de tabla. Se diferencian de los controles estándar en que están enlazados a datos (son componentes data-aware). La propiedad VisibleButtons se utiliza para TDBNavigator seleccionar qué botones podrá pulsar el usuario. aunque cada fila es en TDBCtrlGrid realidad un panel en el que se pueden colocar controles de datos "replicables". Permite construir gráficos a partir de un conjunto de datos. La propiedad TDBChart SeriesList se emplea para seleccionar qué datos deseamos representar y cómo Controles orientados a campos Control Descripción Como el componente estándar TLabel. Igual que las etiquetas normales. Dicho enlace se establece mediante un DataSource. así como la inserción. Es el campo o columna del datasource al que accede cada control. DataField: Propiedad DataSource DataField Descripción Indica el datasource del que se obtienen y al que se envían los datos.html (1 of 6) [27/02/2003 16:24:25] . Mediante la TDBGrid propiedad Columns se pueden especificar qué campos del conjunto de datos se pueden ver en la rejilla y cuáles son sus propiedades. pero enlazado a datos. Por su parte. no consume recursos en Windows. Rejilla que permite incluir controles: Como un TDBGrid. Control de navegación: Sirve para controlar el cursor. Estos componentes trabajan con los datos seleccionados por las propiedades DataSource y. Análogo a TEdit. TDBEdit Presenta un cuadro de edición para un campo concreto. la propiedad Hints permite especificar mensajes de ayuda para cada botón (que habrá que traducir). edición y borrado de datos. en su caso. Muestra el valor de TDBText un campo. el cual no se puede editar.C++ Builder Curso de C++ Builder Acceso a bases de datos Controles de acceso a datos Todos ellos tienen un control homólogo estándar en la paleta de componentes. file:///D|/Manuales/databases/controls. A continuación.

. Se utiliza para campos que sólo permiten varios valores. En la propiedad Items se TDBListBox fijan los valores permitidos. Igual que en el control TDBListBox. El campo que se muestra en la lista de valores viene dado por la propiedad ListField. El comportamiento de todos los controles anteriores ante modificaciones se puede alterar con las propiedades AutoEdit y ReadOnly. Para mostrar imágenes contenidas en una base de datos (en formato BMP o TDBImage WMF). Dichas listas se especifican mediante una serie de valores separados por punto y coma.. Ideal para textos sin formato. OnDataChange y OnUpdateData. void __fastcall TFormDate::DataSourceDataChange(TObject *Sender. En la propiedad Values se indican los valores que en realidad se almacenan en la base de datos. Ideal para claves externas: Como TDBListBox. que son fijos. . El DataSource que se TDBLookupListBox consulta se establece con la propiedad ListSource. }. private: bool FCambiando. Con las propiedades ValueChecked y ValueUnchecked se establecen listas de valores para TDBCheckBox que el TDBCheckBox esté activado o desactivado. aunque la lista aparece como un TComboBox. aunque la lista de valores permitidos no la establece el programador. Igual que TDBMemo. Establece una lista de posibles valores para un campo.html (2 of 6) [27/02/2003 16:24:25] . TField *Field) { if (! FCambiando) try { FCambiando = True. TDBLookupComboBox Igual que TDBLookupListBox. Los valores de la lista se obtienen a partir de los valores de un campo de otro conjunto de datos. Bases de datos con fechas Se puede adaptar TDateTimePicker (página Win32 de la paleta de componentes) para que funcione con un TDataSource especificando sus eventos OnStateChange. Ejemplo class TFormDate : public TForm { . En la propiedad Items se TDBRadioGroup fijan los identificadores que el usuario ve en el grupo de botones. TComboBox enlazado a datos.. las distintas TDBComboBox posibilidades se colocan en la propiedad Items. con la capacidad adicional de dar formato al texto del TDBRichEdit campo (en formato RTF). También es necesario personalizar el evento OnExit del componente TDateTimePicker.C++ Builder TDBMemo Caja de edición con múltiples líneas.. Se emplea en campos que sólo permiten dos valores diferentes. file:///D|/Manuales/databases/controls. La propiedad KeyField indica el campo cuyos valores se almacenan en la base de datos.

TMsgDlgButtons()<<mbYes<<mbNo.html (3 of 6) [27/02/2003 16:24:25] . el tipo de letra e incluso mostrar imágenes o checkboxes sin tener que recurrir al componente TDBCtrlGrid.::TableBeforeDelete(TDataSet *DataSet) { if ( MessageDlg ( "¿Desea eliminar la tupla actual?". } Interceptando el evento OnDrawColumnCell se puede personalizar la presentación de las celdas: cambiar el color. aparece un mensaje en inglés que se puede personalizar interceptando el evento BeforeDelete del conjunto de datos asociado: Ejemplo de personalización de los mensajes mostrados al usuario void __fastcall . } } void __fastcall TFormDate::DataSourceUpdateData(TObject *Sender) { Table->FieldValues["HireDate"] = DateTimePicker->DateTime. } void __fastcall TFormDate::DateTimePickerChange(TObject *Sender) { if (! FCambiando) try { FCambiando = True. mtConfirmation. mientras que la combinación 'Control+Supr' se utiliza para eliminarlas. } __finally { FCambiando = False. Personalización del color de un campo determinado (según el cumplimiento de alguna condición) file:///D|/Manuales/databases/controls. Por defectro. DataSource->Edit(). } } void __fastcall TFormDate::DateTimePickerExit(TObject *Sender) { Table->UpdateRecord(). 0) != mrYes ) Abort(). } Uso de rejillas La tecla 'Insert' permite añadir tuplas.. } __finally { FCambiando = False..C++ Builder DateTimePicker->DateTime = Table->FieldValues["HireDate"].

break. TFontStyles FS. const TRect Rect. else grid->Canvas->StretchDraw(Rect. TColumn *Column. if (tbParts->FieldValues["OnOrder"] >= tbParts->FieldValues["OnHand"]) grid->Canvas->Font->Color = clRed. State). grid->DefaultDrawColumnCell(Rect. State). TGridDrawState State) { TDBGrid *grid = static_cast<TDBGrid*>(Sender). TGridDrawState State) { TDBGrid *grid = static_cast<TDBGrid*>(Sender). DataCol. break. const TRect Rect. grid->DefaultDrawColumnCell(Rect. DataCol. int DataCol.C++ Builder void __fastcall TFormXXX::DBGridDrawColumnCell (TObject *Sender. } Imágenes en vez de texto void __fastcall TFormXXX::DBGridDrawColumnCell (TObject *Sender. TColumn *TColumn. else if (tbEmpleados->FieldValues["Salary"] >= 150000) grid->Canvas->StretchDraw(Rect. State). usDeleted: FS << fsStrikeOut. CaraAlegre->Picture->Graphic). CaraTriste->Picture->Graphic). Column. TColumn *TColumn. TGridDrawState State) { TDBGrid *grid = static_cast<TDBGrid*>(Sender). int DataCol. DataCol. } CheckBoxes (aunque es más cómodo y flexible utilizar TDBCtrlGrid) file:///D|/Manuales/databases/controls. Column. Column. if (Column->FieldName != "") grid->DefaultDrawColumnCell(Rect. const TRect& Rect. switch case case case } (grid->DataSource->DataSet->UpdateStatus()) { usModified: FS << fsBold. grid->Canvas->Font->Style = FS.html (4 of 6) [27/02/2003 16:24:25] . } Propiedades del tipo de letra void __fastcall TFormXXX::DBGridDrawColumnCell (TObject *Sender. usInserted: FS << fsItalic. break. int DataCol.

(RECT*) &Rect. Ordenación dinámica de un conjunto de datos void __fastcall TFormXXX::DBGridTitleClick(TColumn *Column) { try { if (Column->Field->FieldKind == fkLookup) Table->IndexFieldNames = Column->Field->KeyFields. else Table->IndexFieldNames = Column->FieldName. DFC_BUTTON. Esta propiedad la podemos establecer dinámicamente como respuesta al evento OnTitleClick. DrawFrameControl(DBGrid1->Canvas->Handle. const TRect Rect. TColumn *TColumn. "ACTIVO") == 0) { UINT check = 0. int DataCol. DataCol.C++ Builder void __fastcall TFormXXX::DBGridDrawColumnCell (TObject *Sender. } catch(Exception&) { } } Pistas y trucos q BARRAS DE NAVEGACIÓN: Para que siempre se realice un "Append" (al final) en lugar de "Insert" (antes de la fila activa) cuando añadimos nuevos datos (pulsando la tecla Insert). Column.html (5 of 6) [27/02/2003 16:24:25] . TGridDrawState State) { if (CompareText(Column->FieldName. se puede responder al evento OnBeforeAction del TDBNavigator de la siguiente forma: Append en vez de Insert file:///D|/Manuales/databases/controls. } else DBGrid->DefaultDrawColumnCell(Rect. State). } Podemos seleccionar la columna por la que se ordenan los datos usando la propiedad IndexFieldNames del conjunto de datos. if (Table1->FieldValues["ACTIVO"]) check = DFCS_CHECKED. DBGrid->Canvas->FillRect(Rect). DFCS_BUTTONCHECK | check).

C++ Builder void __fastcall TFormXXX::DBNavigatorBeforeAction(TObject *Sender. © Fernando Berzal Galiano file:///D|/Manuales/databases/controls.TNavigateBtn Button) { if (Button==nbInsert) { static_cast<TDBNavigator*>(Sender)->DataSource->DataSet->Append().html (6 of 6) [27/02/2003 16:24:25] . } } q Durante el diseño de formularios podemos arrastrar campos desde el editor de campos del conjunto de datos sobre el que estemos trabajando. De esta forma se añade automáticamente un TDBEdit acompañado por una etiqueta TLabel (con su propiedad FocusControl apuntando al TDBEdit). SysUtils::Abort().

C++ Builder Curso de C++ Builder Acceso a bases de datos TDataSet Conjuntos de datos TDataSet es la clase superior de la jerarquía de clases definida en C++Builder para definir conjuntos de datos. Devuelve true si el cursor está en el primer registro del conjunto de datos. TTable. en TBDEDataSet o en TDBDataSet: Propiedades Propiedad Active Bof CachedUpdates CanModify DataSource DatabaseName Eof Descripción Abre el conjunto de datos cuando se establece a true y lo cierra cuando se fija a false. métodos y eventos que se utilizan en estas clases están definidas realmente en TDataSet. las actualizaciones se mantienen en la caché de la máquina del cliente hasta que el programador los envíe al servidor. file:///D|/Manuales/databases/tdataset. El componente TDataSource asociado. El nombre de la base de datos con la que se está trabajando. De hecho. TQuery y TStoredProc son casos particulares de conjuntos de datos. Determina si el usuario puede editar el conjunto de datos o no. Cuando está a false. la mayoría de las propiedades. Devuelve true cuando el cursor está llega al final del conjunto de datos. todos los cambios realizador en los conjuntos de datos se pasan automáticamente a la base de datos.html (1 of 8) [27/02/2003 16:24:26] . Cuando está a true.

Cancela cualquier modificación en el registro actual si no ha sido enviada con Post(). Devuelve el estado actual del conjunto de datos. Devuelve el número de registros en el dataset. file:///D|/Manuales/databases/tdataset. Indica si una operación de búsqueda ha tenido éxito o no. el buffer del conjunto de datos contiene modificaciones de los datos que aún no han sido enviadas a la base de datos. La escritura no se realiza realmente hasta que se invoca al método CommitUpdates(). Devuelve el valor de un campo especificado en el registro actual. Vacía el contenido de todos los campos del registro actual.C++ Builder FieldCount Fields FieldValues Found Modified RecNo RecordCount State UpdatesPending Es el número de columnas o campos del conjunto de datos. El número de registro actual en el dataset. Indica si el registro actual ha sido modificado. Envía a la base de datos cualquier actualización en caché que estuviese pendiente. Cuando está a true. actualiza la actual si es dsEdit Métodos Método Append() AppendRecord() ApplyUpdates() Cancel() CancelUpdates() ClearFields() Descripción Crea un registro vacío y lo añade al final del conjunto de datos.html (2 of 8) [27/02/2003 16:24:26] . Columnas del conjunto de datos: array de objetos de tipo TField. Estados vg: Post graba una nueva fila si el estado es dsInsert. Añade un registro especificado al final del conjunto de datos. Cancela cualquier actualización en caché que estuviese pendiente.

Mueve el cursor al siguiente registro. Después de que se ha modificado un registro. Actualiza el contenido del registro actual leyéndolo de la base de datos. Localiza un registro por el medio más rápido posible y devuelve el dato contenido en el mismo (se usan índices si es posible). Mueve el cursor al registro anterior. Devuelve un campo TField dado su nombre. Abre el conjunto de datos.html (3 of 8) [27/02/2003 16:24:26] Descripción (¿cuándo se genera?) Después de cancelar las modificaciones. Obtiene todos los registros desde la posición actual del cursor hasta el final del conjunto de datos y los almacena localmente. Desactiva los controles de datos asociados al conjunto de datos (muy útil para evitar el parpadeo de los controles visuales). Escribe los datos modificados de un registro en el conjunto de datos (los envía a la base de datos o al buffer de actualizaciones en caché). este método ignora los cambios hechos previamente que todavía no han sido enviados a la base de datos. Después de abrir un conjunto de datos. Elimina el registro actual. Mueve el cursor un número determinado de filas. Cuando se cierra un conjunto de datos Después de que un registro se haya eliminado. Activa los controles de datos asociados al conjunto de datos. Cuando se utiliza la caché. Permite la edición del registro actual. Establece los valores para todos los campos de un registro. Después de insertar un registro. Inserta un registro en el conjunto de datos con los datos que se le indiquen y los envía con Post(). Sitúa el cursor en el último registro. Eventos Evento AfterCancel AfterClose AfterDelete AfterEdit AfterInsert AfterOpen file:///D|/Manuales/databases/tdataset. Inserta un registro en blanco y pone el conjunto de datos en modo de edición. Mueve el cursor al primer registro. Cierra el conjunto de datos. .C++ Builder CommitUpdates() Close() Delete() DisableControls() Edit() EnableControls() FetchAll() FieldByName() First() GetFieldNames() Insert() InsertRecord() Last() Locate() Lookup() MoveBy() Next() Open() Post() Prior() Refresh() RevertRecord() SetFields() UpdateStatus() Se indica a la base de datos que realice las actualizaciones que estaban en caché y se vacía el buffer de actualizaciones en caché. Recupera la lista con los nombres de los campos del conjunto de datos. Búsqueda de un registro en particular. Devuelve el estado actual cuando las actualizaciones en caché se activan.

Antes de entrar en modo edición. Antes de abrir el conjunto de datos. Antes de que se cancelen los cambios. Cuando ocurre algún error al eliminar una tupla. Cuando ocurre un error al actualizar los datos. Cuando se actualiza el registro en la BD. Siempre que se añade un nuevo registro. Cuando ocurre algún error al editar una tupla.C++ Builder AfterPost BeforeCancel BeforeClose BeforeDelete BeforeEdit BeforeInsert BeforeOpen BeforePost OnDeleteError OnEditError OnNewRecord OnPostError OnUpdateError OnUpdateRecord EJEMPLOS DE USO DE EVENTOS Después de enviar los cambios de un registro. Antes de enviar las modificaciones. Antes de eliminar un registro. Cuando ocurre un error al enviar los cambios.html (4 of 8) [27/02/2003 16:24:26] . con la posibilidad de generar una excepción (DatabaseError) file:///D|/Manuales/databases/tdataset. Introducción de datos Asignación de valores por omisión en el evento OnNewRecord utilizando FieldValues void __fastcall TDataModuleXXX::TableNewRecord(TDataSet *DataSet) { DataSet->FieldValues["Date"] = Date(). Antes de que se cierre un conjunto de datos. } Validaciones a nivel de registros Comprobaciones como respuesta al evento BeforePost. Antes de que se inserte un registro.

tbEmpleadosHireDate->Value < 365 && tbEmpleadosSalary->Value > TopeSalarial) DatabaseError("¡Este es un enchufado!". TMsgDlgButtons()<<mbYes<<mbNo. } Eliminación en cascada Eliminar las líneas detalle de una relación master/detail interceptando el evento BeforeDelete void __fastcall TDataModulePedidos::tbPedidosBeforeDelete(TDataSet *DataSet) { tbLineas->First(). OnPostError. } } Gestión de errores Eventos de detección de errores: OnEditError.html (5 of 8) [27/02/2003 16:24:26] . 0). if (! tbLineas->Eof) if (MessageDlg("¿Eliminar detalles?". 0)==mrYes) { do { tbLineas->Delete().C++ Builder void __fastcall TDataModulePersonal::tbEmpleadosBeforePost(TDataSet *DataSet) { if (Date() . } while (! tbLineas->Eof). OnDeleteError Posible solución ante un error de bloqueo no concedido file:///D|/Manuales/databases/tdataset. } else { Abort().mtConfirmation.

if (Err) { for (int i = 0. mtWarning. ARRAYOFCONST((E->ErrorCode. 0) == mrRetry ) { // Esperar entre 1 y 2 segundos antes de reintentar Sleep(1000 + random(1000)). EDatabaseError *E. TDataAction &Action) { AnsiString S. EDatabaseError *E. } } Mensajes de error personalizados file:///D|/Manuales/databases/tdataset. } } Códigos de error BDE void __fastcall TDataModuleXXX::TablePostError (TDataSet *TDataSet. TDBError *E = Err->Errors[i]. '\n'). Action = daRetry. EDBEngineError *Err = dynamic_cast<EDBEngineError*>(E). } DatabaseError(S.html (6 of 8) [27/02/2003 16:24:26] . Format( "%. i++) { if (i > 0) AppendStr(S. TMsgDlgButton() << mbRetry << mbAbort. i < Err->ErrorCount. TDataAction &Action) { // Consultar al usuario if ( MessageDlg ( E->Message. E>NativeError.C++ Builder void __fastcall TDataModuleXXX::TableEditError (TDataSet *DataSet. 0).4x (%d): %s". AppendStr(S. } else { // Abortar Action = daAbort.E->Message)))).

file:///D|/Manuales/databases/tdataset. switch (GetBDEError(E)) { case DBIERR_KEYVIOL: DatabaseErrorFmt("Clave repetida en la tabla %s". mtConfirmation.html (7 of 8) [27/02/2003 16:24:26] . // Reintentar el borrado en la tabla de pedidos Action = daRetry. while (! tbLineas->Eof) tbLineas->Delete(). } else // Fallar sin mostrar otro mensaje Action = daAbort. } return -1. if (Err) for (int I = 0. TMsgDlgButtons() << mbYes << mbNo. I++) { TDBError *dbe = Err->Errors[I]. EDatabaseError *E. } // Evento OnPostError para cualquier tabla void __fastcall TDataModuleXXX::PostError (TDataSet *DataSet. TDataAction &Action) { TTable *T = static_cast<TTable*>(DataSet).C++ Builder int GetBDEError(EDatabaseError *E) { EDBEngineError *Err = dynamic_cast<EDBEngineError*>(E). ARRAYOFCONST((T->TableName)). Tabla: %s". TDataAction &Action) { if (GetBDEError(E) == DBIERR_DETAILRECORDSEXIST) if ( MessageDlg( "¿Eliminar también las líneas de detalles?". } // Relaciones maestro/detalle void __fastcall TDataModulePedidos::tbPedidosDeleteError (TDataSet *TDataSet. case DBIERR_FOREIGNKEYERR: DatabaseErrorFmt("Error en clave externa. I < Err->ErrorCount. 0). if (dbe->NativeError == 0) return dbe->ErrorCode. 0) == mrYes) { tbLineas->First(). break. EDatabaseError *E.

C++ Builder ARRAYOFCONST((T->TableName)). 0). } } © Fernando Berzal Galiano file:///D|/Manuales/databases/tdataset. break.html (8 of 8) [27/02/2003 16:24:26] .

etc. por ejemplo) con los controles visuales que muestran los datos (TDBGrid. Para cambiar el conjunto de datos enlazado a un componente de tipo TDataSource (ya sea éste una tabla o una consulta).). Implementación de componentes "data-aware" Para crear nuestros propios componentes de forma que se puedan enlazar a un conjunto de datos hemos de automatizar el intercambio de mensajes con los componentes TDataSource. TQuery y TStoredProc. solamente hay que modificar su propiedad DataSet. El código común a todos los controles de datos está recogido en TDataLink (y en su descendiente TFieldDataLink).C++ Builder Curso de C++ Builder Acceso a bases de datos El componente TDataSource TDataSource El componente TDataSource ofrece un mecanismo para enganchar los conjuntos de datos (Table. TDBListBox.html (1 of 2) [27/02/2003 16:24:27] . La propiedad AutoEdit del componente TDataSource determina si se invoca automáticamente al método Edit del conjunto de datos asociado cuando un control (un TDBEdit. TDataSource se encarga de toda la comunicación necesaria entre ellos. file:///D|/Manuales/databases/tdatasource. de forma que podemos utilizarlo para hacer nuestros componentes "data-aware". por ejemplo) recibe el foco. TDBEdit.

C++ Builder © Fernando Berzal Galiano file:///D|/Manuales/databases/tdatasource.html (2 of 2) [27/02/2003 16:24:27] .

Marcadores (TBookmarkStr) TBookmarkStr BM = Table->Bookmark.C++ Builder Curso de C++ Builder Acceso a bases de datos Cursores Cursores Ejercicios q Navegar por un conjunto de datos utilizando First. MoveBy.html (1 of 2) [27/02/2003 16:24:27] . BOF. Last. Next. q Comprobar el efecto de DisableControls y EnableControls. try { // Mover la fila activa } __finally { // Regresar a la posición inicial Table->Bookmark = BM. } Iteradores Clase auxiliar para el recorrido secuencial de un conjunto de datos file:///D|/Manuales/databases/cursor. Prior. IsEmpty y RecordCount. EOF.

. TDataSetIterator dsi(Table).. } © Fernando Berzal Galiano file:///D|/Manuales/databases/cursor.html (2 of 2) [27/02/2003 16:24:27] . Table->Next(). public: TDataSetIterator(TDataSet* ds) : dataset(ds) { Screen->Cursor = crHourGlass. ds->First(). . } }. } ~TDataSetIterator() { dataset->Bookmark = BM. while (! Table->Eof) { // Hacer algo con la fila activa. BM = ds->Bookmark.. Screen->Cursor = crDefault.. dataset->EnableControls().C++ Builder class TDataSetIterator { private: TBookmarkStr BM. ds->DisableControls(). TDataSet* dataset.

CachedUpdates. file:///D|/Manuales/databases/cache.html (1 of 2) [27/02/2003 16:24:27] . También se pueden anular las modificaciones hechas en un registro con el método RevertRecord(). Para confirmar los cambios se ha de llamar a CommitUpdates(). se escriben en un buffer de la máquina local. Cuando la propiedad CachedUpdates está a true. que decide si los cambios efectuados en el conjunto de datos son grabados inmediatamente en la base de datos o si se almacenan en la memoria del ordenador cliente y se envían en bloque al servidor a petición del programa cliente. En su lugar. los cambios en los registros no se escriben en la base de datos. Para anular los cambios almacenados en caché se puede usar el método CancelUpdates(). Los registros se mantienen en la caché hasta que se llama al método ApplyUpdates(). Los conjuntos de datos de C++ Builder vienen equipados con una propiedad.C++ Builder Curso de C++ Builder Acceso a bases de datos Actualizaciones en caché Actualizaciones en caché Las actualizaciones en caché son un recurso del BDE para mejorar el rendimiento de las transacciones en entornos cliente/servidor.

Más fácil mantener la atomicidad de las transacciones (se permite hacer commit o rollback de varios cambios a la vez).html (2 of 2) [27/02/2003 16:24:27] . } Ventajas q Disminuye el número de paquetes enviados por la red (se reduce el tráfico de red). i <= DataSets_size. // Nunca fallan Una alternativa es forzar el vaciado de los buffers escribiendo: void __fastcall TDataModuleXXX::TableAfterPost(TObject *Sender) { static_cast<TDBDataSet*>(Sender)->FlushBuffers(). i++) DataSets[i]->ApplyUpdates(). // Propagar la excepción } for (int i = 0. © Fernando Berzal Galiano file:///D|/Manuales/databases/cache. // this = la base de datos sobre la que estemos trabajando try { for (int i = 0. Los registros de la base de datos sólo se bloquean cuando se hace el volcado de la caché (transacciones más cortas). i <= DataSets_size. i++) DataSets[i]->CommitUpdates(). } catch(Exception&) { Rollback().C++ Builder StartTransaction(). throw. q q Desventajas q Varios usuarios pueden trabajar con el mismo registro simultáneamente (al no existir bloqueos). // Pueden fallar Commit().

por ejemplo) y sus correspondientes DataSources. TableName. Filtros Para realizar búsquedas se pueden utilizar tablas con filtros.html (1 of 6) [27/02/2003 16:24:28] . ReadOnly Métodos: Open&Close. Además. Un filtro se puede construir usando la file:///D|/Manuales/databases/ttable. Búsquedas Una necesidad bastante común en cualquier aplicación de bases de datos es la de seleccionar un conjunto de registros que cumplan una condición. Fijar las propiedades necesarias para especificar correctamente la relación maestro/detalle (vg: reunión CustNoÞCustNo usando como índice CustNo). Entre sus múltiples propiedades y métodos destacan: q Propiedades: DatabaseName. q Crear un formulario que contenga dos componentes TDBGrid enlazados a las tablas del módulo de datos (a sus DataSources para ser más precisos). Para ello es necesario realizar el #include correspondiente.C++ Builder Curso de C++ Builder Acceso a bases de datos TTable El componente TTable facilita el acceso más simple y rápido a una tabla. GotoCurrent q Relaciones maestro/detalle Para construir una relación maestro/detalle en C++ Builder basta con indicar el DataSource de la tabla maestro en la propiedad MasterSource de la tabla detalle y establecer la condición de la reunión (join) mediante la propiedad MasterFields. hay que especificar IndexName o IndexFieldNames para establecer un orden en la tabla detalle (y ¡para que C++Builder lo haga eficientemente!). q Establecer la propiedad MasterSource en la tabla detalle para que apunte al DataSource de la tabla maestra. Ejercicio q Crear un módulo de datos (DataModule) que contenga dos tablas (clientes y pedidos.

// Activar directamente el filtro miActivarFiltro->Checked = True. Table->Refresh(). } void __fastcall TFormX::miActivarFiltroClick(TObject *Sender) { miActivarFiltro->Checked = ! miActivarFiltro->Checked. else { Valor = DBGrid->SelectedField->AsString. Un conjunto de datos filtrado puede recorrerse usando los métodos FindFirst(). i++) if (Valor[i] == DecimalSeparator) Valor[i] = '. FindPrior() y FindLast(). Medite antes de decidirse a utilizar OnFilterRecord.Contains(DBGrid->SelectedField->DataType)) Valor = QuotedStr(DBGrid->SelectedField->AsString). Table->Filtered = True. FindNext(). file:///D|/Manuales/databases/ttable. i <= Valor. Operador. Valor. ftUnknown. void __fastcall TFormX::Filtrar(TObject *Sender) { Set<TFieldType.Length(). } // Combinar la nueva condición con las anteriores if (Table->Filter == "") Table->Filter = Format("[%s] %s %s". Valor))). ARRAYOFCONST((Table1->Filter. Operador = Sender == miIgual ? "=" : Sender == miMayorIgual ? ">=" : Sender == miMenorIgual ? "<=" : "<>". Table->Filtered = miActivarFiltro->Checked.html (2 of 6) [27/02/2003 16:24:28] . Este tipo de filtro se aplica en el cliente. lo cual implica que la aplicación debe bajarse a través de la red incluso los registros que no satisfacen el filtro. else Table->Filter = Format("%s AND [%s] %s %s".'. for (int i = 1. Operador. Valor))). La propiedad Filtered indica si el filtro está activo.C++ Builder propiedad Filter (con FilterOptions) o el evento OnFilterRecord. TiposConComillas < ftString < ftDate < ftTime < ftDateTime. // Activar o desactivar en dependencia del estado de la opción del menú. ftDataSet> TiposConComillas. ARRAYOFCONST((Campo. AnsiString Operador. Campo. // Extraer y dar formato al valor seleccionado if (TiposConComillas. // Extraer el nombre del campo AnsiString Campo = DBGrid->SelectedField->FieldName.

C++ Builder Table->Refresh(). Alternativamente se pueden utilizan las combinaciones SetKey+GotoKey (en vez de FindKey) y SetKey+GotoNearest (sustituyendo a FindNearest) void __fastcall TFormDatos. file:///D|/Manuales/databases/ttable. } void __fastcall TFormX::miEliminarFiltroClick(TObject *Sender) { miActivarFiltro->Checked = False. } NB: Los filtros también son aplicables a componentes de tipo TQuery Índices Se pueden hacer búsquedas usando el índice activo de una tabla (establecido por IndexName o IndexFieldNames) usando los métodos FindKey y FindNearest. Un rango es una restricción de las filas visibles de una tabla en la que se muestran sólo aquéllas tuplas en las cuales los valores de ciertas columnas se encuentran entre dos valores dados. else Table->Cancel(). // FormSearch => diálogo del tipo OK/Cancel con TDBEdits if (FormSearch->ShowModal() == mrOk) Table->GotoNearest().html (3 of 6) [27/02/2003 16:24:28] . Table->Filter = "". Table->Refresh(). Table->Filtered = False.ButtonClick(TObject *Sender) { Table->SetKey(). } Rangos También se puede limitar el conjunto de registros de un conjunto de datos utilizando rangos mediante los métodos SetRange y CancelRange. Debe existir un índice sobre esas columnas.

"Nombre")). Codigo. mientras que el segundo se utiliza para buscar el valor de una columna utilizando como clave una diferente (por ejemplo. if (VarIsNull(V)) DatabaseError("Empleado no encontrado".C++ Builder void __fasctcall TFormAgenda::TabControlChange(TObject *Sender) { AnsiString Letra. else // Activamos el rango correspondiente Table->SetRange(ARRAYOFCONST((Letra)). al revés. "Código"). El primero intenta encontrar un registro con los valores deseados (usando índices si los hay). const AnsiString Nombre) { Variant V = tbEmpleados->Lookup( "Apellido. if (TabControl->TabIndex == 0) // Si es la pestaña con el asterisco mostramos todas las filas. "Nombre. VarArrayOf(ARRAYOFCONST((Apellido. file:///D|/Manuales/databases/ttable.html (4 of 6) [27/02/2003 16:24:28] . AnsiString TDataModulePersonal::ObtenerNombre(int Codigo) { return VarToStr(tbClientes->Lookup("Código". Letra = TabControl->Tabs->Strings[TabControl1->TabIndex]. para encontrar el código de un empleado del que conocemos su nombre). } Locate & Lookup Los métodos Locate y Lookup amplían las posibilidades de los métodos de búsqueda con índices.Apellido").Nombre". Nombre))). 0). 0). Table->CancelRange().ARRAYOFCONST((Letra + "zzz"))). para buscar el nombre de un empleado conociendo su código personal o. } AnsiString TDataModulePersonal::NombreDeEmpleado(int Codigo) { Variant V = tbEmpleados->Lookup("Codigo". } int TDataModulePersonal::ObtenerCodigo(const AnsiString Apellido. if (VarIsNull(V)) DatabaseError("Empleado no encontrado". return V. // Actualizamos los controles asociados Table->Refresh(). Codigo.

TableDetail->Fields->Fields[x]->Assign(TableMaster->Fields>Fields[x]).C++ Builder return V.GetElement(0) + " " + V. try { // Asignaciones a campos.SetLength(Longitud). Rslt. i <= Longitud. throw. TableDetailFecha->Value = Date(). file:///D|/Manuales/databases/ttable. i++) { LastChar = strchr("AEIOUNS". // == TableDetail->FieldByName("Fecha")->AsDateTime = Date().GetElement(1). } Actualizaciones Actualización programada TableDetail->Edit(). for (int i = 1. } return Rslt. Rslt[i] = LastChar. // == TableDetail->FieldValues["Fecha"] = Date()... LastChar) ? random(26) + 'A' : Vocales[random(5)]. } Inserción de datos AnsiString RandomString (int Longitud) { char* Vocales = "AEIOU". AnsiString Rslt. TableDetailConcepto->Clear().html (5 of 6) [27/02/2003 16:24:28] . } catch (Exception&) { TableDetail->Cancel(). char LastChar = 'A'. // Post TableDetail->Post().

2) Tabla->AppendRecord( ARRAYOFCONST ( RandomString(longitud). int registros) { int intentos = 3. while (registros > 0) try { 1) Tabla->Append(). } catch(Exception&) { intentos--. registros--. random(MAXINT) ) )). Tabla->FieldValues["Entero"] = random(MAXINT). Tabla->Post(). © Fernando Berzal Galiano file:///D|/Manuales/databases/ttable. } } Refresco de los datos El contenido actual de la fila activa se puede obtener llamando de forma consecutiva a Edit y Cancel (lo que es más eficiente que llamar a Refresh sobre el conjunto completo de datos) Table->Edit(). if (intentos == 0) throw. randomize().html (6 of 6) [27/02/2003 16:24:28] . int longitud = Tabla->FieldByName("Cadena")->Size.C++ Builder } void CrearDatosSinteticos (TTable *Tabla. Table->Cancel(). // NOTA: Sería más eficiente si se agrupasen // distintas inserciones en una única transacción intentos = 3. Tabla->FieldValues["Cadena"] = RandomString(longitud).

En tiempo de ejecución.html (1 of 4) [27/02/2003 16:24:28] .C++ Builder Curso de C++ Builder Acceso a bases de datos TQuery El componente TQuery permite realizar consultas en SQL. Enlazar el DataSource que tenía la tabla a la nueva consulta. UPDATE o DELETE. Los parámetros son variables que se escriben en la sentencia SQL precedidos de : (dos puntos). En la propiedad SQL de la consulta. Ejemplo: q q q q Cambiar la tabla de clientes por una consulta. que podamos editar su conjunto de datos sin tener que preocuparnos de cómo almacenar los cambios en la base de datos). o ExecSQL() para ejecutar una sentencia SQL de tipo INSERT. Enlazarla con la base de datos BCDEMOS (propiedad DatabaseName). se puede usar Open() para ejecutar una consulta (SELECT). no todas las consultas son actualizables. que permite que una consulta sea actualizable (es decir. Por desgracia. En los siguientes apartados se describen sus propiedades y métodos básicos: La consulta SQL La propiedad SQL es de tipo TStringList (un lista de cadenas de caracteres) y contiene la sentencia SQL que ha de ejecutarse sobre la base de datos indicada mediante la propiedad DatabaseName. Ejecución de sentencias SQL Para ejecutar en tiempo de diseño la sentencia SQL correspondiente a una consulta (un SELECT) basta con poner su propiedad Active a true (lo que equivale a invocar al método Open()). Sentencias SQL con parámetros En las sentencias SQL se pueden utilizar parámetros. El valor de tales parámetros se puede establecer file:///D|/Manuales/databases/tquery. teclear: select * from customer where CustNo > 1300 Otra propiedad bastante interesante del componente TQuery es LiveRequest.

query->ParamByName("ValorMinimo")->AsInteger = 1300. Query->Open(). En tiempo de diseño: Preparar una consulta SQL con: select * from customer where CustNo > :ValorMinimo Editar la propiedad Params estableciendo el parámetro ValorMinimo como un integer con valor 1300. Liberación de recursos Query->Close(). Preparación inicial de una consulta if (! Query->Prepared) Query->Prepare(). query->SQL->Add( "select * from customer where CustNo > :ValorMinimo"). Consultas dependientes [linked queries] Mediante consultas también se pueden establecer relaciones maestro/detalle. } En los parámetros también se pueden utilizar comodines: Query->ParamByName("id")->AsString = Edit->Text + "%". Los métodos Prepare() y UnPrepare() sirven para ejecutar consultas preparadas. La propiedad Prepared nos indica si una consulta ha sido preparada o no. query->Open(). En tiempo de ejecución: { query->SQL->Clear(). que serán más eficientes si se ejecutan múltiples veces siempre que nuestra base de datos permita este tipo de consultas optimizadas. Para ello hemos de dejar file:///D|/Manuales/databases/tquery.html (2 of 4) [27/02/2003 16:24:28] . if (Query->Prepared) Query->UnPrepare().C++ Builder accediente a la propiedad Params del componente TQuery o mediante el método ParamByName.

SIN especificar su tipo. query->ExecSQL(). CantRegistros--. } Datos sintéticos insert into TablaAleatoria(Entero. return query->RowsAffected. Consultas heterogéneas El motor de bases de datos de Borland (BDE) permite incluso realizar consultas que involucren tablas almacenadas en distintas bases de datos. Este tipo de consultas NO son actualizables. while (CantRegistros > 0) try { Query->ParamByName("ENT")->AsInteger = random(MAXINT). query->DatabaseName = ADatabase. donde ALIAS es el alias BDE de la base de datos donde se encuentra la tabla tabla. } catch(Exception&) { if (--Intentos == 0) throw. Para ello. query->SQL->Text = Instruccion. try { int Intentos = 3. :Cad) void RellenarTabla(TQuery *Query. Query->ParamByName("CAD")->AsString = RandomString(35).html (3 of 4) [27/02/2003 16:24:28] . Cadena) values (:Ent.C++ Builder un parámetro de la consulta detalle asociado a una columna del conjunto de datos que hace de maestro. en la consulta SQL hay que indicar las tablas utilizando la notación :ALIAS:tabla. const AnsiString Instruccion) { std::auto_ptr query(new TQuery(NULL)). update & delete) int __fastcall ejecutarSQL(const AnsiString ADatabase. Intentos = 3. por lo que usualmente preferiremos utilizar tablas (TTables). int CantRegistros) { randomize(). Query->ExecSQL(). file:///D|/Manuales/databases/tquery. Query->Prepare(). Para enlazar la consulta basta entonces establecer su propiedad DataSource para que apunte a la tabla maestra. Actualizaciones (insert.

} } © Fernando Berzal Galiano file:///D|/Manuales/databases/tquery.C++ Builder } } __finally { Query->UnPrepare().html (4 of 4) [27/02/2003 16:24:28] .

Invocarlo tantas veces como sea necesario con ExecProc(). El esquema de utilización de procedimientos almacenados es: q Indicar su nombre en la propiedad StoredProcName. select count(Numero). TotalClientes int ) as declare variable Precio int. Llamar al método UnPrepare() cuando ya no se vaya a ejecutar más veces el procedimiento almacenado. q q q q Procedimientos almacenados que devuelven valores create procedure EstadisticasProducto (CodProd int) returns ( TotalPedidos int. begin select Precio from Articulos where Codigo = :CodProd into :Precio. count(distinct RefCliente) from Pedidos where :CodProd file:///D|/Manuales/databases/tstoredproc.C++ Builder Curso de C++ Builder Acceso a bases de datos TStoredProc El componente TStoredProc representa un procedimiento almacenado en un servidor de bases de datos. CantidadTotal int.html (1 of 5) [27/02/2003 16:24:28] . Establecer sus parámetros (igual que en una consulta TQuery). Preparar su ejecución con el método Prepare(). TotalVentas int.

.html (2 of 5) [27/02/2003 16:24:28] .::EstadisticasProducto(TObject *Sender) { AnsiString S. sp->ParamByName("TotalClientes")>AsInteger. sum(Cantidad*:Precio*(100-Descuento)/100) from Detalles where Detalles. ARRAYOFCONST((sp->ParamByName("TotalPedidos")>AsInteger. :TotalVentas. sp->ParamByName("CodProd")->AsString = S. sp->ParamByName("TotalVentas")>AsFloat)))). S) && Trim(S) != "" ) { TStoredProc *sp = DataModuleProductos->spEstadisticas. end ^ void __fastcall . :TotalClientes. if ( InputQuery("Información".RefArticulo = :CodProd into :CantidadTotal. } } Procedimientos almacenados que devuelven conjuntos de datos file:///D|/Manuales/databases/tstoredproc.C++ Builder in ( select RefArticulo from Detalles where RefPedido = Numero ) into :TotalPedidos. sp->ParamByName("CantidadTotal")>AsInteger. ShowMessage( Format( "Pedidos: %d\nClientes: %d\nCantidad: %d\nTotal: %m".. "Código del producto". sp->ExecProc(). select sum(Cantidad).

description TDESCRIPTION. create domain TDESCRIPTION as VARCHAR(128). SUB TID not null references CATEGORY. Creamos sendos procedimientos almacenado recursivos que nos devuelven todas las categorías por debajo (o por encima) de una categoría dada en la jerarquia: create procedure DESCENDANTS (super integer) returns (sub integer) as begin FOR SELECT sub FROM HIERARCHY WHERE SUPER = :super INTO :sub DO BEGIN if (sub is not null) then begin SUSPEND.html (3 of 5) [27/02/2003 16:24:28] . create table HIERARCHY ( SUPER TID not null references CATEGORY.C++ Builder Definimos una base de datos (en InterBase) para almacenar una jerarquía de conceptos (como las categorías de un índice en Internet tipo Yahoo!): create domain TID as INTEGER. for select * from DESCENDANTS(:sub) into :sub do begin if (sub is not null) then SUSPEND. end end END end ^ create procedure ANCESTORS (sub integer) file:///D|/Manuales/databases/tstoredproc. primary key (ID) ).SUB) ). create table CATEGORY ( ID TID not null. primary key (SUPER.

C++ Builder returns (super integer) as begin FOR SELECT id FROM HIERARCHY WHERE SUB = :sub INTO :super DO BEGIN if (super is not null) then begin SUSPEND. end end END end ^ set term .^ Para utilizar los procedimientos almacenados anteriores.html (4 of 5) [27/02/2003 16:24:28] . se puede escribir alguna de las siguientes consultas parametrizadas en la propiedad SQL de un TQuery: select distinct * from descendants(:id) select distinct * from ancestors(:id) Ejecución de un procedimiento almacenado en una hebra independiente file:///D|/Manuales/databases/tstoredproc. for select * from ANCESTORS(:super) into :super do begin if (super is not null) then SUSPEND.

} © Fernando Berzal Galiano file:///D|/Manuales/databases/tstoredproc. }.StoredProcSPThread (de tipo TStoredProc). public: __fastcall TSPThread().html (5 of 5) [27/02/2003 16:24:28] . void __fastcall TSPThread::Execute() { DataModuleSPThread->DatabaseSPThread->Open().C++ Builder class TSPThread : public TThread { protected: void __fastcall Execute(). } } // Ejecución void __fastcall TForm1::Btn1Click(TObject *Sender) { new TSPThread. } __finally { DataModuleSPThread->SessionSPThread->Close(). __fastcall TSPThread::TSPThread():TThread(True) // Crear hebra "suspendida" { FreeOnTerminate = True. .DatabaseSPThread (de tipo TDatabase). Resume(). // Ejecutar la hebra } // // // // DataModuleSPThread es un módulo de datos con tres componentes: .SessionSPThread (de tipo TSession). y . try { DataModuleSPThread->StoredProcSPThread->ExecProc().

. entre otros muchos. TIntegerField.. Por medio de esta clase pueden establecer los atributos de un campo (tipo. Nuevos en C++Builder 4: file:///D|/Manuales/databases/tfield.html (1 of 7) [27/02/2003 16:24:29] . TFloatField y TDateField.). si es obligatorio. TField es una clase base de la que se derivan otras muchas. y también se puede acceder a su valor a través de propiedades como AsString o AsInteger.C++ Builder Curso de C++ Builder Acceso a bases de datos TField Acceso a las columnas de un conjunto de datos La clase TField representa un campo (una columna) en un conjunto de datos. Sus descendientes incluyen a TStringField. si es un campo calculado o de búsqueda. tamaño. índice.

TField* __fastcall TDataSet::FieldByName(const AnsiString Nombre). La propiedad Fields de TDataSet. __property int TFields::Count.html (2 of 7) [27/02/2003 16:24:29] .C++ Builder Acceso a los valores de los campos Para recuperar o establecer el valor de un campo podemos usar: q Un objeto TField creado con el editor de campos [Fields Editor]. __property TField* TFields::Fields[int Index]. Ejemplo file:///D|/Manuales/databases/tfield. q __property TFields* TDataSet::Fields. q El método FieldByName() de TDataSet.

Restricción en el valor del campo. De esta forma se pueden especificar aquellos campos que se quieren incluir en el conjunto de datos y sus propiedades. Ejemplo q Seleccionar del menú contextual (botón derecho del ratón) de cualquier TDataSet la opción Fields Editor. q Añadir los campos que deseemos utilizar. Valor en la fila activa. Personalización de la visualización. Texto descriptivo empleado por TDBGrid. q Seleccionar Add Fields en el menú del Fields Editor. file:///D|/Manuales/databases/tfield. Control de la edición del campo. Tabla->Fields->Fields[0]->Value = "Pérez Martín". Mensaje de error asociado. seleccionándolos en el Fields Editor).html (3 of 7) [27/02/2003 16:24:29] .C++ Builder TablaApellidos->Value = "Pérez Martín". q Ver las propiedades de los campos en el Inspector de Objetos (p. Propiedades interesantes de TField Propiedad FieldName DisplayLabel Value IsNull DisplayFormat EditMask CustomConstraint ConstraintErrorMessage Descripción Nombre de la columna en la BD.ej. El Editor de Campos [Fields Editor] Desde el menú contextual de cualquier descendiente de TDataSet (vg: TTable o TQuery) se permite el acceso al "Fields Editor" en tiempo de diseño. Indica si el valor es nulo. Tabla->FieldByName("Apellidos")->Value = "Pérez Martín".

Text = Miles[i / 1000] file:///D|/Manuales/databases/tfield. "I". "CCC". Al editar valores. "LXXX". "MM". static AnsiString Centenas[10] = {"". "D". "C". AnsiString &Text. "VIII". "CM"}. // Hay que ser consecuentes con el lenguaje } else { int i = Sender->AsInteger. "VII". "CC". if (Sender->AsInteger > 3999) { Text = "Infinitum".. "VI". "II". "III". "X". Al visualizar valores. "IX"}. "M".::tbFieldGetText (TField *Sender. "XXX". "DC". Validación a nivel de campos. "XL". static AnsiString Decenas[10] = {"". "XC"}. Uso de TField Visualizacion personalizada Definiendo la respuesta al evento GetText Seleccionar un campo de tipo entero y hacer que se visualice con números romanos. "DCC". "MMM"}. "DCCC". "L".C++ Builder ReadOnly Campo de sólo lectura Los eventos de TField Evento OnChange OnValidate OnGetText OnSetText Descripción Cuando cambia el valor del campo.html (4 of 7) [27/02/2003 16:24:29] . "XX". "LX". static AnsiString Miles[4] = {"".. "V". void __fastcall . "IV". "CD". bool DisplayText) { static AnsiString Unidades[10] = {"". "LXX".

1). for ( i=1. AnsiString S = Text. Utilizando el evento OnValidate: Un nombre propio no puede incluir dígitos ni otros simbolos file:///D|/Manuales/databases/tfield.C++ Builder + Centenas[i / 100 % 10] + Decenas[i / 10 % 10] + Unidades[i % 10]. const AnsiString Text) { int i. Definiendo la respuesta al evento SetText: Forzar que las iniciales de los nombres sean siempre letras mayúsculas void __fastcall ..::tbFieldSetText(TField *Sender.Length(). i<=S. } 2.html (5 of 7) [27/02/2003 16:24:29] . } } Restricciones a nivel de campos 1. i++) if ( i==1 || S[i-1]==' ') CharUpperBuff(&S[i]. Sender->AsString = S..

C++ Builder

void __fastcall ...::tbFieldValidate(TField *Sender) { AnsiString S = Sender->AsString; for (int i = S.Length(); i > 0; i--) if (S[i] != ' ' && !IsCharAlpha(S[i])) DatabaseError("Carácter no permitido en nombre propio", 0); }

3. Controlando el valor que puede tomar un campo mediante sus propiedades EditMask y CustomConstraint. Cuando se utiliza esta última, lo normal es definir también ConstraintErrorMessage para que el usuario sepa por qué no puede darle determinados valores a un campo. Valores no nulos CustomConstraint = value is not null Código postal EditMask = !99999;1;_ Teléfono o fax EditMask = !999 99 99 99;0;_ Dirección de correo electrónico CustomConstraint = value is null or value='' or value like '%_@%_.%_'

Campos calculados
Se crean con New field (Calculated) desde el menú contextual del editor de campos y se manejan a través del evento OnCalcFields, que se produce cada vez que se cambia o se modifica la fila activa del conjunto de datos (si está a true la propiedad AutoCalcFields del conjunto de datos).

file:///D|/Manuales/databases/tfield.html (6 of 7) [27/02/2003 16:24:29]

C++ Builder

Campos de búsqueda [lookup fields]
Se pueden crear con la opción New field (Lookup) del menú contextual del editor de campos. Se definen mediante las propiedades KeyFields, LookupDataset, LookupKeyFields y LookupResultField. Mediante LookupCache se pueden cargar los valores permitidos en la propiedad LookupList, la cual se puede actualizar llamando a RefreshLookupList.

BLOBs: TBlobField
Los campos de tipo BLOB [Binary Large OBject] en una base de datos se pueden utilizar para almacenar ficheros completos, imágenes, sonidos o cualquier otro tipo de información digitalizada. El contenido de este tipo de campos se puede modificar invocando al método LoadFromFile, mientras que su complementario (SaveToFile) nos permite recuperar la información almacenada en la base de datos. Imágenes en formato JPG (jpeg.hpp) void __fastcall ...::DataSourceImagenDataChange(TObject *Sender, TField *Field) { if (tbImagenesFoto->IsNull) Image->Picture->Graphic = NULL; else { std::auto_ptr BS(new TBlobStream(tbImagenesFoto, bmRead)); auto_ptr Graphic(new TJPEGImage); Graphic->LoadFromStream(BS.get()); Image->Picture->Graphic = Graphic.get(); } }

© Fernando Berzal Galiano

file:///D|/Manuales/databases/tfield.html (7 of 7) [27/02/2003 16:24:29]

C++ Builder

Curso de C++ Builder Acceso a bases de datos
TSession

El componente TSession gestiona una sesión de la base de datos (un conjunto de conexiones desde una misma aplicación). Cada vez que se inicia una aplicación que accede a bases de datos a través del motor de bases de datos de Borland, el BDE establece un objeto de tipo TSession global llamado Session con el cual se puede acceder a las propiedades de la sesión actual. En principio, no hay que crear un objeto TSession propio salvo que se esté construyendo una aplicación multihebra. Este componente incluye algunos métodos de interés:

Gestión de alias BDE
AddAlias(), AddStandardAlias(), ModifyAlias(), DeleteAlias() y SaveConfigFile() son métodos que pueden usarse para gestionar alias BDE en tiempo de ejecución.
void __fastcall TSession::AddAlias (const AnsiString Nombre, const AnsiString Ctrldor, TStrings *Lista); void __fastcall TSession::AddStandardAlias (const AnsiString Nombre, const AnsiString Dir, const AnsiString Ctrldor); void __fastcall TSession::ModifyAlias (const AnsiString Alias, TStrings *Parametros); void __fastcall TSession::DeleteAlias (const AnsiString Alias); void __fastcall TSession::SaveConfigFile();

Acceso al catálogo
GetAliasNames(), GetDatabaseNames(), GetDriverNames(), GetTableNames() y GetStoredProcNames() se pueden utilizar para conseguir información acerca de las bases de datos disponibles en el sistema.
void __fastcall TSession::GetDriverNames (TStrings *Lista);
file:///D|/Manuales/databases/tsession.html (1 of 2) [27/02/2003 16:24:29]

C++ Builder

void __fastcall TSession::GetDriverParams (const AnsiString Controlador, TStrings *Lista); void __fastcall TSession::GetDatabaseNames (TStrings *Lista); void __fastcall TSession::GetAliasNames (TStrings *Lista); AnsiString __fastcall TSession::GetAliasDriverName (const AnsiString Alias); void __fastcall TSession::GetAliasParams (const AnsiString Alias, TStrings *Lista); void __fastcall TSession::GetTableNames (const AnsiString Alias, const AnsiString Patron, bool Extensiones, bool TablasDeSistema, TStrings *Lista); void __fastcall TSession::GetStoredProcNames (const AnsiString Alias, TStrings *Lista);

Ejemplo:

Session->GetDatabaseNames(DBNamesComboBox->Items);

© Fernando Berzal Galiano

file:///D|/Manuales/databases/tsession.html (2 of 2) [27/02/2003 16:24:29]

C++ Builder

Curso de C++ Builder Acceso a bases de datos
TDatabase

El componente TDatabase permite controlar las conexiones a una base de datos. Aunque su uso no es estrictamente necesario, hay ciertas operaciones para las que resulta imprescindible:

Conexiones persistentes con bases de datos
La propiedad KeepConnections de TDatabase se utiliza para controlar cómo se manejan las conexiones con las bases de datos cuando se cierra un dataset. Si KeepConnections está a false, cuando se cierra el último dataset, la conexión con la base de datos se pierde y habrá que reiniciarla la próxima vez que se abra otro dataset, lo que consumirá una cantidad considerable de tiempo y, si no hacemos nada para evitarlo, volverá a solicitar la clave de acceso del usuario.

Establecimiento de la conexión [Login]
El componente TDatabase también permite controlar el login de una forma automática:
q

Estableciendo la propiedad LoginPrompt a false y fijando explícitamente los parámetros de la conexión. Desde el código

file:///D|/Manuales/databases/tdatabase.html (1 of 4) [27/02/2003 16:24:30]

C++ Builder

Database->AliasName = "Oracle"; Database->DatabaseName = "MiDB"; Database->Params->Values["user name"] = "scott"; Database->Params->Values["password"] = "tiger"; Table->DatabaseName = Database->DatabaseName; Table->TableName = "CUSTOMER"; Table->Open();

Desde el inspector de objetos En el editor de listas asociado a la propiedad Params:
USER NAME=scott PASSWORD=tiger

q

Interceptando el evento OnLogin, el cual se genera cada vez que se ha de establecer una conexión cuando la propiedad LoginPrompt está a true.
void __fastcall ...::DatabaseLogin (TDatabase *Database, TStrings *LoginParams) { LoginParams->Values["user name"] = "scott"; LoginParams->Values["password"] = "tiger"; }

Schema cache
void __fastcall ...::DatabaseLogin (TDatabase *Database, TStrings *LoginParams) { ... // Schema cache AnsiString S; S.SetLength(255); int L = GetTempPath(255, S.c_str()); if (S.IsPathDelimiter(L)) L--;

file:///D|/Manuales/databases/tdatabase.html (2 of 4) [27/02/2003 16:24:30]

C++ Builder

S.SetLength(L); Database1->Params->Values["ENABLE SCHEMA CACHE"] = "TRUE"; Database1->Params->Values["SCHEMA CACHE DIR"] = S; }

Control de Transacciones
Otro uso más del componente TDatabase (puede que el más importante) es el control explícito de las transacciones con la base de datos. Una transacción es una colección de operaciones sobre la base de datos (inserciones, modificaciones o eliminaciones de registros) que ha de realizarse de forma atómica. Una transacción con la base de datos se inicia explícitamente llamando al método StartTransaction(). Las modificaciones realizadas sobre la base de datos no se harán efectivas hasta que se invoque al método Commit(). Si se quiere cancelar la transacción en curso hay que recurrir al método Rollback(), lo cual hará que las operaciones efectuadas en la transacción sean ignoradas. Mediante la propiedad TransIsolation se puede establecer la el nivel de aislamiento entre distintas transacciones. El nivel tiRepeatableRead (lecturas repetibles) será siempre el deseable, aunque con determinados servidores SQL sólo se llega a tiCommitedRead ("lecturas comprometidas") y las bases de datos de escritorio (tipo Paradox, dBase o Access) sólo permiten tiDirtyRead. Una transferencia bancaria TLocateOptions Opt;
// Iniciar la transacción Database->StartTransaction(); try { if (! Table->Locate("Cliente", cliente1, Opt)) DatabaseError("No existe el primer cliente", 0); Table->Edit(); Table->FieldValues["Saldo"] -= importe; Table->Post(); if (! Table->Locate("Cliente", cliente2, Opt)) DatabaseError("No existe el segundo cliente", 0);
file:///D|/Manuales/databases/tdatabase.html (3 of 4) [27/02/2003 16:24:30]

C++ Builder Table->Edit(). for (int i = ADatabase->DataSetCount . } © Fernando Berzal Galiano file:///D|/Manuales/databases/tdatabase. Table->Refresh().html (4 of 4) [27/02/2003 16:24:30] . Table->Post(). i >= 0. Table->FieldValues["Saldo"] += importe. } catch(Exception&) { // Cancelar la transacción Database->Rollback(). // Confirmar la transacción Database->Commit(). } Cancelar los cambios realizados desde el ultimo commit/rollback void CancelarCambios (TDatabase* ADatabase) { ADatabase->Rollback().1. throw. i--) ADatabase->DataSets[i]->Refresh().

file:///D|/Manuales/databases/examples/agenda. 32 caracteres) DIRECCIÓN (memo) FOTO (graphic) NACIMIENTO (date) BDE Administrator Panel de control de Windows Es la utilidad que permite gestionar los alias del motor de bases de datos de Borland.DB con los siguientes campos: q q q q q NOMBRE (alpha. 64 caracteres) EMAIL (alpha. consultar y ordenar tablas almacenadas en distintos formatos (como Paradox o dBase).C++ Builder Curso de C++ Builder Acceso a bases de datos Un ejemplo completo Database Desktop Es una herramienta incluida en los entornos de desarrollo de Borland/Inprise (Delphi.db (en formato Paradox). Creación de tablas Crear una tabla Paradox llamada AGENDA.dbf (en formato dBase) y BCDEMOS:vendors.html (1 of 3) [27/02/2003 16:24:30] . C++Builder y JBuilder) que permite crear. visualizar. Visualización de tablas Visualizar el contenido de las tablas BCDEMOS:holdings.

Esto es equivalente a mantener la propiedad Active del conjunto de datos a true (aunque es preferible porque no tiene sentido mantener conexiones abiertas cuando no se están utilizando). En su propiedad PATH ponemos la ruta al directorio donde hemos almacenado anteriormente la tabla AGENDA. Creamos un módulo de datos que contendrá un componente TTable denominado TableAgenda con su TDataSource asociado (dsAgenda). Hemos de llamar al método Open de nuestra tabla cuando se produce el evento OnActivate del formulario.cpp del formulario. Con el "Fields Editor" del menú contextual de TableAgenda creamos los cinco componentes TField correspondientes a las cinco columnas de nuestra tabla. En la propiedad DataSource de todos los componentes data-aware seleccionaremos dmAgenda->dsAgenda. Para que los componentes del módulo de datos sean visibles desde el formulario hemos de añadir el #include correspondiente en el fichero .DB.html (2 of 3) [27/02/2003 16:24:30] . De la misma forma interceptamos el evento OnDeactivate del formulario e invocamos al método Close de la tabla. Añadimos al formulario principal los componentes necesarios para poder manejar nuestra agenda. Al módulo de datos lo llamamos dmAgenda y la unidad correspondiente la guardamos como DataAgenda. Tenemos que establecer las propiedades DatabaseName y TableName del componente TTable. así como la propiedad DataSet del TDataSource.C++ Builder Creación de alias Creamos un nuevo alias de tipo STANDARD (el usado para tablas Paradox y dBase) y lo denominamos AGENDA. Para introducir fotos en nuestra base de datos podemos utilizar el componente file:///D|/Manuales/databases/examples/agenda. C++Builder Desarrollo de la aplicación Creamos un proyecto llamado Agenda y su formulario principal lo guardamos con el nombre FormAgenda. NOTA: La creación de alias la prodríamos haber realizado desde la opción Alias Manager del Database Desktop e incluso desde el código de nuestra aplicación.

Finalmente.. findNext y findPrior). podemos traducir las pistas asociadas a los distintos botones del TDBNavigator (propiedad Hints) y permitir su visualización (ShowHints). También podríamos permitir la impresión de fichas con los datos de nuestra tabla. Para ello. los cuales devolverán un valor booleano según la búsqueda se haya realizado con éxito o no. Para evitar que los mensajes asociados al TDBNavigator aparezcan en inglés debemos interceptar el evento BeforeAction de este componente. deberíamos tratar mejor la introducción de fechas (para lo cual lo ideal es crear un componente derivado de TDateTimePicker). NOTA: El conjunto de datos debe estar en modo edición para poder establecer el valor de la imagen. Así mismo. Para permitir búsquedas en nuestro conjunto de datos podemos utilizar filtros NOTA: Se podría crear un cuadro de diálogo genérico que nos permita realizar búsquedas sobre cualquier conjunto de datos.html (3 of 3) [27/02/2003 16:24:30] . Así mismo. © Fernando Berzal Galiano file:///D|/Manuales/databases/examples/agenda. un botón que lo llame y el método LoadFromFile de TGraphicField. una vez que tengamos nuestra aplicación terminada. Para ello tendríamos que utilizar un TQuickReport o acceder directamente al canvas de la impresora (TPrinter). nuestro diálogo TDBDlgSearch debería tener una propiedad DataSet (definida utilizando la palabra reservada __property) así como métodos que permitan realizar la búsqueda (vg: find. por ejemplo. Sería aconsejable establecer las validaciones oportunas a nivel de campos para que se sólo se puedan introducir direcciones de correo electrónico válidas.C++ Builder OpenPictureDialog. podríamos distribuirla generando un programa de instalación con. También podemos utilizar el portapapeles de Windows para poner la imagen. el InstallShield Express for C++Builder..

con una o más columnas que tienen un nombre y un tipo (numérico.. los estándares SQL-86 y SQL-89 no eran adecuados para aplicaciones reales y en 1992 apareció el SQL-92 (ANSI X3. Las bases de datos SQL son autodescriptivas: las tablas del catálogo (cuya implementación depende del DBMS) almacenan información acerca de las tablas de la base de datos (metadatos). cuando Chamberlin y Boyce publicaron el primer artículo de SEQUEL. Codd ("A relational model of data for large shared data banks". aún está por conseguir su estandarización de hecho. Una cuarta generación de SQL.html (1 of 13) [27/02/2003 16:24:31] . Proceedings of the ACM SIGFIDET Workshop. Commun. Los orígenes de SQL se remontan a 1974. fecha. que fue añadida en el SQL-89. que estaba basado en un trabajo de E.135-1992. 249–264). pp. El SQL-86 no incluía la integridad referencial. May 1974.. 377–387).. Visión general El concepto fundamental de SQL es el de tabla. el estándar actualmente utilizado por la mayor parte de las bases de datos. el SQL3. En 1978. Algunos de los datos pueden ser desconocidos o inaplicables.C++ Builder Curso de C++ Builder Acceso a bases de datos SQL SQL es el lenguaje que se utiliza usualmente para consultar y gestionar bases de datos relacionales. desarrolló la primera especificación de SQL en 1986. que después se convertiría en SQL ("SEQUEL: A structured English query language".) y su violación produce excepciones que bloquean la ejecución de las sentencias que las ocasionan. 1974. 13:6. en cooperación con el grupo correspondiente de ISO. No obstante. ACM. Las restricciones de integridad se utilizan para forzar el cumplimiento de determinadas condiciones ('business rules'. Los disparadores [triggers] especifican acciones que el DBMS ha de realizar cada vez que se produce algún evento determinado y los procedimientos almacenados sirven para encapsular conjuntos de sentencias SQL. pp.F. cadena. integridad referencial. Los datos se almacenan como filas en las tablas (tuplas). y SQL utiliza 'null' para representar este hecho. el ANSI comenzó a estandarizar un lenguaje de definición de datos El comité técnico X3H2 del ANSI reconoció la importancia del modelo relacional y.. ISO/IEC 9075:1992).). DML: Lenguaje de manipulación de datos SELECT SELECT [DISTINCT] lista-select | * file:///D|/Manuales/databases/sql.

La claúsula WHERE. agrupa las tuplas que tienen los mismos valores en todas las columnas especificadas. tabla . los grupos resultantes de GROUP BY que no satisfagan la condición se eliminan. 7. La claúsula GROUP BY. La lista de columnas separadas por comas que aparece en el SELECT determina las columnas que se devuelven (* devuelve todas).'BARCELONA'. 3. . cuando está presente. cuando aparece. 2.C++ Builder FROM tabla. 6. Ejemplo: Seleccionar aquellos vuelos que tengan como origen Madrid. Si existe una claúsula HAVING. WHERE condición GROUP BY columnas HAVING condición ORDER BY columnas Las consultas a la base de datos se realizan en SQL mediante la sentencia SELECT: 1. elimina las tuplas que no satisfacen la condición. DISTINCT. Recuperar todas las filas de la(s) tabla(s) especificada en FROM. si existe. Ejemplo: Visualizar todos los vuelos que tengan como origen o destino Granada SELECT * FROM VUELOS WHERE ORIGEN='GRANADA' OR DESTINO='GRANADA' Claúsula IN Expresa la pertenencia del valor de una columna a un determinado conjunto de valores. Cuando se indica más de una. elimina duplicados. 4. . La claúsula ORDER BY sirve para ordenar los valores devueltos por una consulta. Barcelona o Sevilla. 5. se devuelve su producto cartesiano.html (2 of 13) [27/02/2003 16:24:31] .'SEVILLA') o también SELECT * file:///D|/Manuales/databases/sql. SELECT * FROM VUELOS WHERE ORIGEN IN ('MADRID'.

C++ Builder FROM VUELOS WHERE ORIGEN='MADRID' OR ORIGEN='BARCELONA' OR ORIGEN='SEVILLA' Ejemplo: Visualizar todos los vuelos existentes excepto aquellos que llegan a Londres o a Copenhague.00' AND '12. Bajo estas condiciones.00' equivale a SELECT * FROM VUELOS WHERE HORA_SALIDA >= '06.'COPENHAGUE') Claúsula BETWEEN Sirve para establecer o expresar un rango de valores (valores extremos incluidos). Ejemplo: Recuperar todos los vuelos que salgan entre las 6 y las 12 de la mañana SELECT * FROM VUELOS WHERE HORA_SALIDA BETWEEN '06.00. cadenas de caracteres que comparten ciertos caracteres: '%' equivale a una cadena de caracteres de longitud comprendida entre 0 y n (el '*' en MS-DOS) y '_' equivale a un único carácter (igual que '?' en MS-DOS). BA British Airways) y los cuatro siguientes corresponden al número de vuelo.00.00. recupérense todos los vuelos que no pertenecen a IBERIA.00. Los dos primeros caracteres indican la compañía a la que pertenece cada vuelo (vgt: IB Iberia. con la ayuda de metasímbolos (comodines).00' Ejemplo: La columna NUM_VUELO representa los vuelos con 6 caracteres.00' AND HORA_SALIDA <= '12. SELECT * FROM VUELOS WHERE NUM_VUELO NOT BETWEEN 'IB0000' AND 'IB9999' Claúsula LIKE Sirve para especificar. SELECT * FROM VUELOS WHERE DESTINO NOT IN ('LONDRES'. file:///D|/Manuales/databases/sql.html (3 of 13) [27/02/2003 16:24:31] .

Pueden especificarse detrás de SELECT o en la claúsula HAVING (nunca dentro de WHERE). Ejemplo: Número de vuelos incluidos en nuestra base de datos. SELECT * FROM VUELOS WHERE NUM_VUELO LIKE 'IB%' o SELECT * FROM VUELOS WHERE NUM_VUELOS LIKE 'IB____' Expresiones aritméticas Pueden ser utilizadas tanto en la lista de columnas que sigue a SELECT como en la claúsula WHERE. SELECT COUNT(*) FROM VUELOS Claúsula GROUP BY-HAVING Sirve para dividir una tabla en grupos de filas que comparten características comunes.6 FROM AVIONES Funciones de agregación Son funciones que operan con todas las filas que cumplen la condicion expuesta en la claúsula WHERE. ENVERGADURA*3.html (4 of 13) [27/02/2003 16:24:31] . al menos.SUM.C++ Builder Ejemplo: Recuperar todos los vuelos de Iberia. SELECT LONGITUD*3. q q f(expresión) aplica una función (MIN. VELOCIDAD_CRUCERO/1.28.AVG. Su resultado es un único valor.28. una columna. file:///D|/Manuales/databases/sql.MAX. Ejemplo: Visualizar la longitud y la envergadura de todos los aviones expresando las magnitudes en pies en vez de en metros y la velocidad de crucero en mph (en lugar de Km/h).COUNT) a una expresión aritmética en la cual debe participar. COUNT(*) cuenta el número de filas de una tabla.

AVG(x) no siempre será igual a SUM(x)/COUNT(*). mientras que colA<>colB será cierta si sólo una de las dos columnas es nula (será falsa cuando ambas sean nulas). Dependiendo del sistema gestor de bases de datos. Ejemplo: Visualizar los destinos que tengan más de dos vuelos. SELECT DESTINO FROM VUELOS GROUP BY DESTINO HAVING COUNT(*) > 2 Ejemplo: Visualizar los vuelos de Iberia que tengan plazas libres. Las columnas sobre las que haya definido un índice único (UNIQUE) sólo pueden incluir un valor nulo (en este caso sí se consideran iguales dos valores nulos).C++ Builder Ejemplo: Primera salida y número de vuelos diarios para cada destino SELECT DESTINO. COUNT(*) FROM VUELOS GROUP BY DESTINO Notas: q q q GROUP BY crea una serie de subtablas compuestas por las filas que comparten el mismo valor en la(s) columna(s) de agrupamiento (la columna DESTINO en el ejemplo) y las funciones de agregación se aplican a cada subtabla de forma independiente. GROUP BY agrupa todos los valores nulos en un único grupo. MIN(HORA_SALIDA). sino indeterminados. los valores nulos son mayores o menores que cualquier otro valor cuando se devuelve un conjunto de datos ordenado. Las funciones de agregación ignoran los campos nulos.html (5 of 13) [27/02/2003 16:24:31] . DISTINCT no elimina los valores nulos repetidos. Es decir. file:///D|/Manuales/databases/sql. No se puede poner en GROUP BY una columnaque no se haya incluido en la sentencia SELECT. La claúsula HAVING permite elegir aquellos grupos que se quieren visualizar y no interfiere en la agrupación realizada por GROUP BY. La expresión booleana colA=colB es falsa en cuanto colA o colB sean nulos. Dos valores nulos no son iguales ni son distintos. CAPACIDAD-COUNT(*) FROM RESERVAS WHERE NUM_VUELO LIKE 'IB%' GROUP BY NUM_VUELO HAVING COUNT(*)<CAPACIDAD Valores nulos q q q q q q q Cualquier operación aritmética sobre un campo nulo nos devolverá como resultado un valor nulo. exceptuando la función COUNT. SELECT NUM_VUELO.

. En el primer caso.<>.. WHERE columna operador {ANY/ALL} (subconsulta) Nota: =ANY equivale a IN..>=) o la claúsula IN.. file:///D|/Manuales/databases/sql. WHERE columna concatenador (SELECT . SELECT * FROM RESERVAS WHERE FECHA_SALIDA='20...<=. Ejemplo: Visualizar las tuplas de T cuyo valor para la columna X es nulo: SELECT * FROM T WHERE X IS NULL Subconsultas Responden a la siguiente sintaxis: SELECT .. la subconsulta ha de devolver un único valor..html (6 of 13) [27/02/2003 16:24:31] .. Ejemplo: Plazas libres que hay en cada vuelo MADRID-LONDRES del día 20/02/2001. FROM . La subconsulta puede estar correlacionada con la consulta exterior: Ejemplo: Reservas cuyo número de plazas libres sea mayor que la media para ese mismo vuelo.02.2001' AND NUM_VUELO IN ( SELECT NUM_VUELO FROM VUELOS WHERE ORIGEN='MADRID' AND DESTINO='LONDRES') ANY y ALL se usan para poder utilizar operadores de comparacion con subconsultas que nos devuelvan más de un valor como resultado: SELECT ..=.>.C++ Builder q La expresión IS NULL (e IS NOT NULL) sirve en una consulta para devolver las tuplas cuyo valor para la columna indicada sea nulo (o no).) El concatenador puede ser un operador de comparación (<. FROM .

.. NUM_VUELO Peculiaridades Algunos gestores de bases de datos incluyen extensiones no estándar como. DESTINO. un sobrenombre que se le da a una tabla y que debe ser £nico para toda la consulta.) file:///D|/Manuales/databases/sql. EXISTS y NOT EXISTS se emplean para comprobar la existencia o ausencia del valor devuelto por una subconsulta: Ejemplo: Obtener los vuelos con reservas efectuadas en los cuales aún quedan plzas libres. ordenando el resultado de mayor a menor número de plazas libres de mayor a menor.. INSERT INTO tabla VALUES (valor.. DESTINO. . por ejemplo.C++ Builder SELECT * FROM RESERVAS A WHERE PLAZAS_LIBRES > (SELECT AVG(PLAZAS_LIBRES) FROM RESERVAS WHERE NUM_VUELO=A.NUM_VUELO) A es un alias. SUM(PLAZAS-LIBRES) FROM VUELOS WHERE EXISTS (SELECT * FROM RESERVAS WHERE RESERVAS....NUM_VUELO) GROUP BY NUM_VUELO ORDER BY 3 DESC. Ordenar por destino para igual número de plazas libres: SELECT NUM_VUELO. mecanismos para limitar el tamaño de una consulta (que siempre se puede hacer mediante procedimientos almacenados): q q q IBM DB2: fetch first . rows only Oracle: . top valor [percent] INSERT La sentencia INSERT se utiliza para insertar tuplas en una tabla..NUM_VUELO=VUELOS.html (7 of 13) [27/02/2003 16:24:31] . and rownum <= valor SQL Server: .

cada tupla de la tabla ha de referenciar a una tupla existente en otra tabla con los mismos valores para las columnas incluidas en la clave externa).C++ Builder INSERT INTO tabla SELECT .. Una claúsula opcional WHERE selecciona los datos que han de modificarse. DELETE DELETE FROM tabla [WHERE condición] DELETE permite eliminar tuplas. etcétera. triggers. procedimientos almacenados. La siguiente tabla recoge algunos de los más usuales: Servidor SQL estándar Cadenas Enteros Reales Números Fechas Otros date time timestamp file:///D|/Manuales/databases/sql. se modifican todas las tuplas de la tabla. vistas. DDL: Lenguaje de definición de datos El sublenguaje de definición de datos de SQL se utiliza para crear. UNIQUE prohíbe que existan valores duplicados en una columna y CHECK restringe los valores que puede tomar una columna. ALTER TABLE para modificarlas y DROP TABLE para eliminarlas. Igual que UPDATE. . Cuando esta claúsula se omite. las claves primarias (PRIMARY KEY) aseguran que los valores de las columnas especificadas son únicos y no nulos. CREATE TABLE sirve para crear tablas.. Por desgracia. Se pueden definir restricciones sobre las columnas de una tabla: NOT NULL prohíbe que se inserten valores nulos en una columna. no está estandarizado suficientemente por el momento y muchos detalles dependen de la base de datos que utilicemos. incluye una claúsula WHERE opcional. UPDATE UPDATE tabla SET columna=valor.html (8 of 13) [27/02/2003 16:24:31] . finalmente. [WHERE condición] La sentencia UPDATE sirve para actualizar datos... También se pueden definir restricciones a nivel de tabla: CHECK puede involucrar a varias columnas. modificar y eliminar tablas. Los tipos de datos permitidos para las columnas de las tablas varían según el servidor que utilicemos. las claves externas (REFERENCES) sirven para especificar restricciones de integridad referencial (esto es.

. Definición de dominios con create domain (*) create type . long [raw] number(p.NextVal q Nombre InterBase Oracle SQL Server Identidades Definición de columnas con el atributo identity (valor_inicial.. clob.incremento) file:///D|/Manuales/databases/sql. si queremos obtener la hora actual utilizaremos la palabra reservada "Now" en InterBase..clob. Aparte de los tipos de datos estándar el usuario también puede definir sus propios tipos: Servidor IBM DB2 InterBase Oracle Mecanismo create distinct type . date [var]binary[(n)] numeric[(p[. datetime Las mayores diferencias suelen aparecer al manejar fechas. incremento) q Definición: create_sequence id increment by valor start with valor Secuencias q Uso: id.dbclob timestamp numeric(p.html (9 of 13) [27/02/2003 16:24:31] . Por ejemplo. "sysdate" en Oracle o la función "getdate()" en SQL Server. image...s) blob..d])] decimal[(p[. text.C++ Builder IBM DB2 char(n) varchar(n) char(n) varchar(n) char(n) varchar[2](n) integer smallint real=float double InterBase float integer=int double smallint precision Oracle SQL Server int char[(n)] smallint varchar[(n)] tinyint float[(n)] real date [var]graphic(n) decimal(p.d])] money.s) time blob.' q Uso con gen_id (id... Procedimiento almacenado sp_addtype (*) Creación de reglas: create rule SQL Server Asociación de reglas con tipos de datos: sp_bindrule Valor por defecto: create default & sp_binddefault (*) reconocidos automáticamente por C++Builder Generadores Las distintas bases de datos ofrecen distintos mecanismos para asignar enteros diferentes a cada tupla (sin garantizar la secuencialidad de los valores): Servidor Mecanismo q Definición de generadores con create generator q Valor establecido con set generator Generadores q Eliminación con delete from rdb$generators where rdb$generator_name='..d) blob decimal(p..d) date rowid.CurrVal & id.

end ^ Detalles de InterBase file:///D|/Manuales/databases/sql.BeforePost(TDataSet *DataSet) { spNextID->ExecProc(). Table..::Table. end ^ En el cliente (aplicación C++Builder): TStoredProc *spNextID void __fastcall T.. En un trigger (InterBase): set term ^. existe un índice único.. o el valor de la clave primaria no nos importa realmente en nuestra aplicación.html (10 of 13) [27/02/2003 16:24:31] .. En el servidor (InterBase): create procedure nextID returns (cod integer) as begin cod = gen_id(ID).C++ Builder Uso de generadores con C++Builder El uso correcto de generadores en C++Builder consiste en crear un procedimiento almacenado en el servidor que devuelva un valor entero e invocar a dicho procedimiento interceptanto el evento OnNewRecord o BeforePost de la tabla en la aplicación cliente. sobre alguna columna alternativa a la clave primaria que utilizaremos como criterio de ordenación para la navegación. } También podemos ahorrarnos trabajo y asignar la clave primaria en el trigger si la tabla no tiene columnas con valores default... como sucede con las claves artificiales. o casi único. create trigger BItabla for tabla active before insert as begin Codigo = gen_id(generador.ID->Value = spNextID->ParamByName("COD")->AsInteger. 1).

.. on . substring Procedimientos almacenados y triggers en InterBase create procedure nombre [ ( ParámetrosDeEntrada ) ] [ returns ( ParámetrosDeSalida ) ] as CuerpoDeProcedimiento create trigger nombre for tabla [active | inactive] {before | after} {delete | insert | update} [position prioridad] as CuerpoDeProcedimiento CuerpoDeProcedimiento ::= declaración* begin .. Funciones de agregación: count. Consultas Valores nulos: is [not] null Sinónimos para las columnas: .. avg Subconsultas: in... sum.. min. end Declaración de variables declare variable id tipo file:///D|/Manuales/databases/sql.. max. trim.. (active|inactive) set statistics index ... as .html (11 of 13) [27/02/2003 16:24:31] .. alter index . exists Cadenas Operador like (comodines % y _) Concatenación: || Funciones: upper..C++ Builder Restricciones Valores nulos no permitidos: not null Valores por defecto: default Restricciones: check Identificación de las restricciones: constraint Clave primaria: primary key Clave candidata: unique Clave externa: references | foreign key Acciones referenciales: (on delete|on update) (no action|cascade|set default) Columnas calculadas: computed by Índices create [unique] [asc|desc] index . lower..

C++ Builder NB: Al usarse.html (12 of 13) [27/02/2003 16:24:31] .end) when exception id do instrucción when sqlcode n do instrucción when gdscode n do instrucción Instrucciones de control exit suspend (similar a los iteradores del lenguaje CLU) Variables especiales new & old (igual que en Oracle) Excepciones file:///D|/Manuales/databases/sql.. los identificadores de variables van precedidos de ':' Asignación variable = expresión Ejecución de un procedimiento almacenado NB: No se pueden pasar expresiones como parámetros execute procedure nombre [(ParsEntrada)] [returning_values ParsSalida] select * from nombre [(ParsEntrada)]. delete & singleton select vg: select columna from tabla where condición into :variable Iteradores sobre consultas (con cursores en Oracle o SQL Server) for select into variables do instrucción Instrucción compuesta begin instrucción* end Lanzamiento de excepciones exception id Captura de excepciones (al final de un bloque begin.. si se usa suspend dentro de un bucle Estructuras condicionales if (condición) then instrucción [else instrucción] Bucles while (condición) do instrucción Instrucciones SQL: insert. update.

html (13 of 13) [27/02/2003 16:24:31] .C++ Builder create exception id "mensaje" Alertas InterBase: C++Builder: componentes) UDFs User Defined Functions: DLLs + declare external function post_event mensaje Componente TIBEventAlerter (página Samples de la paleta de © Fernando Berzal Galiano file:///D|/Manuales/databases/sql.

q Club Builder Tutoriales. ejemplos. enlaces y prácticamente cualquier cosa que esté relacionada con C++Builder.C++ Builder Curso de C++ Builder Enlaces interesantes En español q Calling Dr. Marteens "La Cara Oculta de C++Builder" en PDF. Ejemplos y trucos para sacarle el máximo partido a la VCL (en Delphi y C++Builder). q BCBDEV. file:///D|/Manuales/links/index.COM Más artículos. trucos. FAQs y pistas sobre C++Builder. trucos y componentes shareware para C++Builder. etc. componentes y tutoriales para C++Builder. Muy recomendable. En inglés q Bytamin-C: The C++Builder Developer Site! Componentes. herramientas. utilidades. ejemplos. q The Bits Página británica con información. información técnica. noticias. q Delphi Super Page Montones de recursos para Delphi y C++Builder: componentes shareware y freeware. q Borland C++Builder La página oficial del C++Builder en Inprise. ejemplos. un libro en español acerca del desarrollo de aplicaciones de gestión con C++Builder.html (1 of 2) [27/02/2003 16:24:32] . artículos.

Dobb's Journal q Productos relacionados r r Delphi InterBase q Programación r r r ACCU (Association of C & C++ Users) Mathtools.net (portal técnico para científicos e ingenieros) Patrones de diseño (porque no todo se diseña con el ratón) Página principal © Fernando Berzal Galiano file:///D|/Manuales/links/index.C++ Builder Otros sitios de interés q Publicaciones r r r C++Builder Developer's Journal C++Builder Informant Dr.html (2 of 2) [27/02/2003 16:24:32] .

Una visión general del IDE de C++ Builder 2.2. Páginas de componentes.1.3.3. Componentes en C++ Builder 3. Un estudio detallado del IDE de C++ Builder 2. Compilación. 4. Introducción 2. 3.6.Índice Curso de C++ Builder Índice del curso 1.C++ Builder .4. 3. Componentes visuales y no visuales. El sistema de ayuda 2.5. El IDE de C++ Builder 2. El almacén de objetos 2. La VCL de C++ Builder file:///D|/Manuales/toc. métodos y gestores de eventos. ejecución y depuración de programas 2.2.html (1 of 5) [27/02/2003 16:24:32] . Propiedades. Ejercicios: Ejemplos de aplicaciones simples y de consola 3.1.

Herencia Múltiple.4.6.5. 4.1. Polimorfismo. 5.1.5. Controles de edición y Editor. Clases Abstractas. El Paradigma de la POO en C++.5.6.7. Encapsulamiento. 5. Abstracción.7. 5. Herencia. 5.3. 4. Ejercicios: Pizarra. Constructores y Destructores (Inicialización de Clases I). 5.Índice 4.2. 5. 4. Un paseo por la VCL. Sobrecarga de funciones.2.6. 5. 5. Clases de formularios y aplicaciones.C++ Builder .3.3. Propiedades Virtuales. Restricciones al uso de la VCL en C++ Builder.1.html (2 of 5) [27/02/2003 16:24:32] . 5.4. Clases de componentes. Herencia de Constructores y Destructores (Inicialización de Clases II). 5. Programación Orientada a Objetos en C++ 5. file:///D|/Manuales/toc. 5.. 5.1.5.2. Restricciones de acceso en C++.2. 4. 5.5. Creación y Destrucción de Objetos.1.

Tratamiento de excepciones 6. Programación con hebras 7.7.1 Uso de recursos compartidos 7. Acceso a bases de datos file:///D|/Manuales/toc.4. 6. 6.5 Ejemplos (ZIP) 8.3. Polimorfismo en las clases y métodos virtuales.2 Sincronización entre hebras 7. 7. 6. Especificación de excepciones. Excepciones de la VCL.1.html (3 of 5) [27/02/2003 16:24:32] .5.2.Índice 5.2 La clase TThread 7.C++ Builder .3 Ejecución de hebras 7. Lanzamiento de excepciones. Excepciones no tratadas.2.4 Coordinación entre hebras 7..4.1 Introducción 7. Captura de excepciones.4. 6. 6.

5 El componente TDataSource 8.5 El componente TQuery: Consultas SQL 8.2 El motor de bases de datos de Borland (BDE) 8.C++ Builder .6.3 Componentes de acceso a bases de datos 8.2 Cursores 8.1 Introducción 8.6 El componente TStoredProc: Procedimientos almacenados 8.6 Conjuntos de datos 8.3 Actualizaciones en caché 8.6.7.1 TDataSet y sus derivados 8.Índice 8.2 El componente TDatabase 8.6.6.6.4 Controles de acceso a datos 8.8 Herramientas y utilidades 8.html (4 of 5) [27/02/2003 16:24:32] .6.6.8 Ejemplos y ejercicios Apéndice: SQL Enlaces interesantes file:///D|/Manuales/toc.7.7 Sesiones y conexiones 8.4 El componente TTable: Tablas 8.7 El componente TField: Acceso a los campos 8.1 El componente TSession 8.

html (5 of 5) [27/02/2003 16:24:32] .C++ Builder .Índice Volver file:///D|/Manuales/toc.

C++ Builder .html [27/02/2003 16:24:32] .Apéndices Curso de C++ Builder Apéndices Listado de propiedades. métodos y eventos de: Aplicaciones Formularios Componentes Estructura y configuración de un proyecto de C++ Builder. La paleta de componentes Lista completa de menús Página principal © Francisco Cortijo Bon file:///D|/Manuales/appendix/index.

Application->Run().2. Application->CreateForm(__classid(TPpalFrm). PpalFrm).5. LPSTR. } //--------------------------------------------------------------------- PPAL. USEFORM("Ppal. antes de POLIMORFISMO.cpp". &PpalFrm).OOP .cpp").h> #pragma hdrstop USERES("Ejemplo. } return 0.res"). //--------------------------------------------------------------------WINAPI WinMain(HINSTANCE. } catch (Exception &exception) { Application->ShowException(&exception).CPP //--------------------------------------------------------------------#include <vcl. HINSTANCE.Ejemplo 1 Curso de C++ Builder Ejemplo 1 Corresponde al final de la sección 5. USEUNIT("ObjGraf. int) { try { Application->Initialize().H file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1. EJEMPLO.html (1 of 8) [27/02/2003 16:24:33] .

hpp> //----------------------------------------------------------------------class TPpalFrm : public TForm{__published: // IDE-managed Components TPaintBox *PaintBox. void __fastcall BotonSalirClick(TObject *Sender).hpp> <ExtCtrls.hpp> <Forms. void __fastcall PaintBoxPaint(TObject *Sender). void __fastcall FormCreate(TObject *Sender).hpp> <StdCtrls.OOP .h" file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1.html (2 of 8) [27/02/2003 16:24:33] .h> #pragma hdrstop #include "Ppal. private: // User declarations public: // User declarations __fastcall TPpalFrm(TComponent* Owner). }.hpp> #include "ObjGraf. TBitBtn *BotonSalir.h" #include <Buttons. //----------------------------------------------------------------------extern PACKAGE TPpalFrm *PpalFrm. void __fastcall FormDestroy(TObject *Sender). //----------------------------------------------------------------------#endif PPAL.hpp> <Controls.Ejemplo 1 //----------------------------------------------------------------------#ifndef PpalH #define PpalH //----------------------------------------------------------------------#include #include #include #include #include <Classes.CPP //----------------------------------------------------------------------#include <vcl.

clYellow. Cir2 = new TCirculo (PaintBox.Ejemplo 1 //----------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*. 70. 210. clGreen. Cuad1 = new TCuadrado (PaintBox. 20). Cir2->Mostrar(). } //----------------------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1. Cuad2 = new TCuadrado (PaintBox.html (3 of 8) [27/02/2003 16:24:33] . 25). TCuadrado *Cuad1. 40. } 30). } //----------------------------------------------------------------------void __fastcall TPpalFrm::PaintBoxPaint(TObject *Sender) { Cir1->Mostrar(). Cuad1->Mostrar(). clRed.dfm" TPpalFrm *PpalFrm. delete Cuad2. 100. TCirculo *Cir1. delete Cir2. delete Cuad1. 150. 100. //----------------------------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { delete Cir1.OOP . // Punteros a objetos de las clases derivadas. //----------------------------------------------------------------------__fastcall TPpalFrm::TPpalFrm(TComponent* Owner): TForm(Owner) { } //----------------------------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Cir1 = new TCirculo (PaintBox. 120. clBlack. } //----------------------------------------------------------------------void __fastcall TPpalFrm::BotonSalirClick(TObject *Sender) { Application->Terminate(). *Cir2. 45). 200. Cuad2->Mostrar(). *Cuad2.

// Constructor de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. // OJO: Se ha cambiado Color por FColor TColor TPaintBox public: // Pueden usarlas todas. // Metodo virtual puro // NUEVAS FORMAS DE ACCESO AL DECLARAR PRIVATE LOS MIEMBROS FX y FY. (int _X). // OJO: Se ha cambiado el nombre a // los miembros X e Y por FX y FY. // Otros metodos virtual void Mostrar (void) = 0. // Puede acceder SOLO los objetos de esta clase. {read=FColor. write=SetX }. int _Y=0). // Metodo virtual puro void SetX void SetY virtual int virtual int protected: // Pueden acceder los objetos de esta clase y // sus descendientes. {read=GetAncho }. {read=FY. *PaintBox. int FY. __property __property __property __property __property int int TColor int int X Y Color Ancho Alto = = = = = {read=FX. GetAncho (void) = 0.OOP . file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1. {read=GetAlto }. write=FColor}. // Metodo virtual puro GetAlto (void) = 0.H //----------------------------------------------------------------------#ifndef ObjGrafH #define ObjGrafH //*************************************************/ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int FX. FColor. TColor _Color=clBlack. int _X=0.html (4 of 8) [27/02/2003 16:24:33] . (int _Y).Ejemplo 1 OBJGRAF. write=SetY }.

int _Y=0. void Mostrar (void). int _Y=0.} (void) {return(Radio*2).} int Lado.} . // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { protected: // Pueden acceder los objetos de esta clase y // sus descendientes.OOP . // Instanciacion del metodo virtual puro de // la clase TObjGraf }.html (5 of 8) [27/02/2003 16:24:33] (void) {return(Lado). int _Lado=1).} (void) {return(Lado). inline int GetAncho inline int GetAlto public: // Metodos // Constructores y destructores TCuadrado (TPaintBox *_PaintBox. (void) {return(Radio*2). int _X=0. TColor _Color=clBlack. TColor _Color=clBlack. // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { protected: // Pueden acceder los objetos de esta clase y // sus descendientes. file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1. // Instanciacion del metodo virtual puro de // la clase TObjGraf }. //*************************************************/ // Definicion de la clase derivada TCirculo. int _X=0. inline int GetAncho inline int GetAlto public: // Metodo constructor TCirculo (TPaintBox *_PaintBox. //*************************************************/ // Definicion de la clase derivada TCuadrado. int Radio.Ejemplo 1 }. int _Radio=1). void Mostrar (void).

Ancho) desde un // constructor de la clase base. int _Y) { PaintBox = _PaintBox. } // Funciones de escritura de las propiedades virtuales X e Y void TObjGraf :: SetX (int _X) { if (_X < 0) FX = 0. } void TObjGraf :: SetY (int _Y) { if (_Y < 0) FY = 0.html (6 of 8) [27/02/2003 16:24:33] . GetAlto) para fijar el valor de una // propiedad virtual (Alto. // MUY IMPORTANTE: Estas tres lineas han cambiado: FX = _X.CPP //----------------------------------------------------------------------#include <vcl. FColor = _Color. else FX = _X. else if (_X > (PaintBox->Width . int _X. // (GEtAncho. // No se puede llamar a los metodos virtuales puros FY = _Y.OOP . TColor _Color.Ejemplo 1 //----------------------------------------------------------------------#endif OBJGRAF.h> #pragma hdrstop #include "ObjGraf.Ancho)) FX = PaintBox->Width . else file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1.h" //----------------------------------------------------------------------#pragma package(smart_init) /*****************************************************/ // Metodos asociados a la clase base TObjGraf /*****************************************************/ TObjGraf :: TObjGraf (TPaintBox *_PaintBox.Ancho.

PaintBox->Canvas->Ellipse(X. _Y) { Lado = _Lado. PaintBox->Canvas->Brush->Color = Color.OOP . _Color. PaintBox->Canvas->Rectangle(X. /*****************************************************/ TCirculo :: TCirculo (TPaintBox *_PaintBox. int _Y. else FY = _Y. _Y) { Radio = _Radio. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCuadrado :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. int _X. /*****************************************************/ TCuadrado :: TCuadrado (TPaintBox *_PaintBox.Alto)) FY = PaintBox->Height .html (7 of 8) [27/02/2003 16:24:33] . } /*****************************************************/ // Metodos asociados a la clase derivada TCuadrado.Alto. int _Radio) : TObjGraf (_PaintBox. TColor _Color. int _Lado) : TObjGraf (_PaintBox. Y+Lado).Ejemplo 1 if (_Y > (PaintBox->Height . } file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1. // TCirculo deriva de la clase base TObjGraf. TColor _Color. int _Y. X+Radio*2. int _X. Y+Radio*2). // TCuadrado deriva de la clase base TObjGraf. PaintBox->Canvas->Brush->Color = Color. _X. X+Lado. _Color. } /*****************************************************/ // Metodos asociados a la clase derivada TCirculo. _X. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCirculo :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. Y. Y.

Ejemplo 1 Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/oop/Ejemplo1.html (8 of 8) [27/02/2003 16:24:33] .OOP .

USEUNIT("ObjGraf. } catch (Exception &exception) { Application->ShowException(&exception). Application->Run(). PpalFrm).CPP //---------------------------------------------------------------------- #include <vcl.H file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2.cpp". En este ejemplo se muestra el POLIMORFISMO (Polimorfismo de clases y métodos virtuales). int) { try { Application->Initialize(). &PpalFrm). //---------------------------------------------------------------------WINAPI WinMain(HINSTANCE.html (1 of 10) [27/02/2003 16:24:34] . } //---------------------------------------------------------------------- PPAL.res"). EJEMPLO. Application->CreateForm(__classid(TPpalFrm).Ejemplo 2 Curso de C++ Builder Ejemplo 2 Corresponde al final de la sección 5. USEFORM("Ppal.OOP .cpp"). HINSTANCE. } return 0.h> #pragma hdrstop USERES("Ejemplo2. LPSTR.

void __fastcall FormCreate(TObject *Sender). }.hpp> <ExtCtrls.hpp> <StdCtrls.CPP //---------------------------------------------------------------------#include <vcl.h> file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. void __fastcall FormDestroy(TObject *Sender). void __fastcall BotonSalirClick(TObject *Sender). //---------------------------------------------------------------------extern PACKAGE TPpalFrm *PpalFrm.html (2 of 10) [27/02/2003 16:24:34] . public: // User declarations __fastcall TPpalFrm(TComponent* Owner). void __fastcall PaintBoxPaint(TObject *Sender).OOP . TBitBtn *BotonSalir.Ejemplo 2 //---------------------------------------------------------------------#ifndef PpalH #define PpalH //---------------------------------------------------------------------#include #include #include #include #include <Classes.hpp> #include "ObjGraf.hpp> //---------------------------------------------------------------------class TPpalFrm : public TForm { __published: // IDE-managed Components TPaintBox *PaintBox.hpp> <Forms. private: // User declarations TObjGraf **Objs. //---------------------------------------------------------------------#endif PPAL.hpp> <Controls.h" #include <Buttons.

100. //---------------------------------------------------------------------__fastcall TPpalFrm::TPpalFrm(TComponent* Owner) : TForm(Owner) { } //---------------------------------------------------------------------void __fastcall TPpalFrm::FormCreate(TObject *Sender) { Objs = new TObjGraf * [4]. 120.OOP . 45). i++) delete Objs[i]. 70. 20). file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. 25). 150. (PaintBox. 100. clGreen.dfm" TPpalFrm *PpalFrm. i<4. 30). i<4. 40.h" //---------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*. clBlack. Objs[0] Objs[1] Objs[2] Objs[3] } //---------------------------------------------------------------------void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { for (int i=0. (PaintBox. i++) Objs[i]->Mostrar(). 210. } //---------------------------------------------------------------------void __fastcall TPpalFrm::PaintBoxPaint(TObject *Sender) { for (int i=0. clYellow. delete []Objs.html (3 of 10) [27/02/2003 16:24:34] . } //---------------------------------------------------------------------void __fastcall TPpalFrm::BotonSalirClick(TObject *Sender) { Application->Terminate(). (PaintBox. } = = = = new new new new TCirculo TCuadrado TCirculo TPelota (PaintBox. clRed. 200.Ejemplo 2 #pragma hdrstop #include "Ppal.

void SetX void SetY virtual int virtual int protected: TColor TPaintBox public: // Constructores de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. write=SetX }. {read=GetAncho }. {read=FY. write=FColor}. FColor. // Metodo virtual puro file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2.OOP . {read=FColor. // Metodo virtual puro // NUEVAS FORMAS DE ACCESO AL DECLARAR PRIVATE LOS MIEMBROS FX y FY. int FY. TObjGraf (TObjGraf *ObjGraf). int _Y=0). // Otros metodos virtual void Mostrar (void) = 0.H //---------------------------------------------------------------------#ifndef ObjGrafH #define ObjGrafH //*************************************************/ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int FX. int _X=0. (int _Y).Ejemplo 2 //---------------------------------------------------------------------- OBJGRAF. // Metodo virtual puro GetAlto (void) = 0. TColor _Color=clBlack. write=SetY }. GetAncho (void) = 0. __property __property __property __property __property int int TColor int int X Y Color Ancho Alto = = = = = {read=FX. {read=GetAlto }. (int _X). *PaintBox.html (4 of 10) [27/02/2003 16:24:34] .

// Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { private: int FRadio. // Otros metodos void Mostrar (void). que a su // vez deriva de la clase base TObjGraf //*************************************************/ // Tipo definido por enumeracion para la direccion de TPelota // La codificacion es: /* NO 10 \ \ O 8 ---/ / 9 SO */ file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. (void) {return(FRadio*2). TColor _Color=clBlack.Ejemplo 2 }. // Instanciacion del metodo virtual puro de // la clase TObjGraf __property int Radio = }.html (5 of 10) [27/02/2003 16:24:34] N 2 | | | | 1 S NE 6 / / ---.} (void) {return(FRadio*2).4 E \ \ 5 SE . {read=FRadio. int _Radio=1). int _Y=0. // TPelota deriva de la clase TCirculo. //*************************************************/ // Definicion de la clase derivada TCirculo. int _X=0.OOP . inline int GetAncho inline int GetAlto public: // Constructores TCirculo (TPaintBox *_PaintBox.} //*************************************************/ // Definicion de la clase derivada TPelota. write=FRadio}.

NO=10}. int _Radio=1. //*************************************************/ // Definicion de la clase derivada TCuadrado. write=FVelocidad}. __property int Velocidad = {read = FVelocidad. int _Lado=1). int _Y=0. SetDireccion (TDireccion _Direccion).} (void) {return(FLado). void Mover (void). // Otros metodos void Mostrar (void). SE=5. __property TDireccion Direccion = {read = GetDireccion.Ejemplo 2 enum TDireccion {S=1. write=SetDireccion}. TColor _Color=clBlack. }. int _X=0. int _Y=0. // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf {private: inline int GetAncho inline int GetAlto public: // Constructores TCuadrado (TPaintBox *_PaintBox. GetDireccion (void). N=2.} file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. NE=6. void Borrar (void). int FDirY. E=4. class TPelota: public TCirculo { private: int FDirX. int _X=0. void TDireccion public : // Constructores TPelota (TPaintBox *_PaintBox.html (6 of 10) [27/02/2003 16:24:34] . int _Velocidad=5). TColor _Color=clBlack. int FVelocidad.OOP . (void) {return(FLado). TDireccion _Direccion=SE. O=8. // Otros metodos int FLado. SO=9.

html (7 of 10) [27/02/2003 16:24:34] .h> #pragma hdrstop #include "ObjGraf.OOP . FY = _Y.h" //---------------------------------------------------------------------#pragma package(smart_init) /*****************************************************/ // Metodos asociados a la clase base TObjGraf /*****************************************************/ // Constructores TObjGraf :: TObjGraf (TPaintBox *_PaintBox. //---------------------------------------------------------------------#endif {read=FLado. OBJGRAF. FColor = _Color. FX = ObjGraf->FX. FColor = ObjGraf->Color. FY = ObjGraf->FY.Ejemplo 2 void Mostrar (void). write=FLado}. FX = _X. int _Y) { PaintBox = _PaintBox. } TObjGraf :: TObjGraf (TObjGraf *ObjGraf) { PaintBox = ObjGraf->PaintBox. int _X. // Instanciacion del metodo virtual puro de // la clase TObjGraf __property int Lado = }.CPP //---------------------------------------------------------------------#include <vcl. } // Funciones de escritura de las propiedades virtuales X e Y file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. TColor _Color.

PaintBox->Canvas->Brush->Color = Color. else FY = _Y.html (8 of 10) [27/02/2003 16:24:34] . X+Radio*2. else if (_Y > (PaintBox->Height . PaintBox->Canvas->Ellipse(X. TColor _Color.Ancho. que a su // vez deriva de la clase base TObjGraf /*****************************************************/ TPelota :: TPelota (TPaintBox *_PaintBox. _Y) { Radio = _Radio. // TCirculo deriva de la clase base TObjGraf. /*****************************************************/ TCirculo :: TCirculo (TPaintBox *_PaintBox. Y.Alto)) FY = PaintBox->Height . TColor _Color. Y+Radio*2). } void TObjGraf :: SetY (int _Y) { if (_Y < 0) FY = 0.Ejemplo 2 void TObjGraf :: SetX (int _X) { if (_X < 0) FX = 0. else FX = _X. // TPelota deriva de la clase TCirculo. else if (_X > (PaintBox->Width .Alto. int _Radio) : TObjGraf (_PaintBox. _X.Ancho)) FX = PaintBox->Width .OOP . _Color. int _Y. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCirculo :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. } /*****************************************************/ // Metodos asociados a la clase derivada TPelota. int _X. file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. } /*****************************************************/ // Metodos asociados a la clase derivada TCirculo.

_Y. return (_Dir). Mostrar ().Ejemplo 2 int _X. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TPelota :: Mostrar (void) { PaintBox->Canvas->Pen->Color = clBlack. } TDireccion TPelota :: GetDireccion (void) { TDireccion _Dir. TDireccion _Direccion. int _Y. } void TPelota :: Mover (void) { Borrar (). Velocidad = _Velocidad.html (9 of 10) [27/02/2003 16:24:34] . _Color. _Dir = (TDireccion) ((FDirY == +1) ? 1 : ((FDirY == -1 ) ? 2 : 0)). X+Radio*2. PaintBox->Canvas->Brush->Color = PaintBox->Color. PaintBox->Canvas->Ellipse(X. _Radio) { Direccion = _Direccion. Y += FDirY * Velocidad. Y. } /*****************************************************/ file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. int _Radio. Y. PaintBox->Canvas->Brush->Color = Color. X+Radio*2. PaintBox->Canvas->Ellipse(X.OOP . _X. Y+Radio*2). } // Otras funcione propias de TPelota void TPelota :: Borrar (void) { PaintBox->Canvas->Pen->Color = PaintBox->Color. Y+Radio*2). _Dir = (TDireccion) (_Dir + (FDirX == +1) ? 4 : ((FDirX == -1 ) ? 8 :0)). int _Velocidad) : TCirculo (_PaintBox. } void TPelota :: SetDireccion (TDireccion _Dir) { FDirY = (_Dir & 1) ? +1 : ((_Dir & 2) ? -1 : 0). X += FDirX * Velocidad. FDirX = (_Dir & 4) ? +1 : ((_Dir & 8) ? -1 : 0).

Y.OOP . /*****************************************************/ TCuadrado :: TCuadrado (TPaintBox *_PaintBox.html (10 of 10) [27/02/2003 16:24:34] . int _Lado) : TObjGraf (_PaintBox. int _X.Ejemplo 2 // Metodos asociados a la clase derivada TCuadrado. TColor _Color. X+Lado. PaintBox->Canvas->Rectangle(X. Y+Lado). } Atrás © Francisco Cortijo Bon file:///D|/Manuales/intro/ejemplos/oop/Ejemplo2. _Y) { Lado = _Lado. int _Y. _Color. _X. } // Instanciacion del metodo virtual puro de la clase TObjGraf void TCuadrado :: Mostrar (void) { PaintBox->Canvas->Pen->Color = Color. // TCuadrado deriva de la clase base TObjGraf. PaintBox->Canvas->Brush->Color = Color.

CPP Curso de C++ Builder Estructura y configuración de un proyecto Fichero "main. if (MainForm->Color == clBtnFace) MainForm->Color = clWhite. RadioButton2->Hide(). CheckBox->Checked = false.cpp" //----------------------------------------------------------------#include <vcl. RadioButton1->Hide(). } //----------------------------------------------------------------void __fastcall TMainForm::FormCreate(TObject *Sender) { MainForm->Caption = "Primer programa con C++ Builder". //----------------------------------------------------------------__fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner) { } //----------------------------------------------------------------void __fastcall TMainForm::ExitButtonClick(TObject *Sender) { Application->Terminate().Estructura y configuración de un proyecto de C++ Builder: MAIN.html (1 of 3) [27/02/2003 16:24:34] . file:///D|/Manuales/appendix/project/main_cpp.h" //----------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.h> #pragma hdrstop #include "main.dfm" TMainForm *MainForm.

RadioButton2->Show().html (2 of 3) [27/02/2003 16:24:34] . " + Edit- } //----------------------------------------------------------------- Atrás file:///D|/Manuales/appendix/project/main_cpp. Sr/Sra. else LabelOutput->Caption >Text. } else { RadioButton1->Hide(). = "Escogió Opción 2. LabelOutput->Caption = "". else LabelOutput->Caption >Text. Sr/Sra. OKButton->Enabled = false. } else { if (Edit->Text == "") LabelOutput->Caption desconocido/a". RadioButton2->Hide(). Sr/Sra. } { = "Escogió Opción 1. " + Edit- = "Escogió Opción 2. Sr/Sra. = "Escogió Opción 1.Estructura y configuración de un proyecto de C++ Builder: MAIN. OKButton->Enabled = true.CPP } //----------------------------------------------------------------void __fastcall TMainForm::CheckBoxClick(TObject *Sender) { if (CheckBox->Checked == true) { RadioButton1->Show(). RadioButton1->Checked = true. } } //----------------------------------------------------------------void __fastcall TMainForm::OKButtonClick(TObject *Sender) { if (RadioButton1->Checked) if (Edit->Text == "") LabelOutput->Caption desconocido/a".

Estructura y configuración de un proyecto de C++ Builder: MAIN.CPP © Francisco Cortijo Bon file:///D|/Manuales/appendix/project/main_cpp.html (3 of 3) [27/02/2003 16:24:34] .

void __fastcall CheckBoxClick(TObject *Sender). TCheckBox *CheckBox. TButton *OKButton.Estructura y configuración de un proyecto de C++ Builder: MAIN. TRadioButton *RadioButton2.h" //----------------------------------------------------------------#ifndef mainH #define mainH //----------------------------------------------------------------#include <Classes.H Curso de C++ Builder Estructura y configuración de un proyecto Fichero "main. //----------------------------------------------------------------extern PACKAGE TMainForm *MainForm. //----------------------------------------------------------------#endif file:///D|/Manuales/appendix/project/main_h. TLabel *LabelOutput.hpp> #include <Forms. void __fastcall OKButtonClick(TObject *Sender). private: // User declarations public: // User declarations __fastcall TMainForm(TComponent* Owner). void __fastcall FormCreate(TObject *Sender). TButton *ExitButton. TRadioButton *RadioButton1.hpp> #include <StdCtrls. }. TEdit *Edit.hpp> //----------------------------------------------------------------class TMainForm : public TForm { __published: // IDE-managed Components TLabel *LabelEdit. void __fastcall ExitButtonClick(TObject *Sender).html (1 of 2) [27/02/2003 16:24:34] .hpp> #include <Controls.

Estructura y configuración de un proyecto de C++ Builder: MAIN.H //----------------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/project/main_h.html (2 of 2) [27/02/2003 16:24:34] .

cpp" //----------------------------------------------------------------#include <vcl.Estructura y configuración de un proyecto de C++ Builder: INICIAL. } return 0. Application->Run(). } //----------------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/project/inicial_cpp. int) { try { Application->Initialize(). USEFORM("main.CPP Curso de C++ Builder Estructura y configuración de un proyecto Fichero "Inicial. &MainForm). MainForm).res").h> #pragma hdrstop USERES("Inicial.html [27/02/2003 16:24:35] . } catch (Exception &exception) { Application->ShowException(&exception).cpp". //----------------------------------------------------------------WINAPI WinMain(HINSTANCE. LPSTR. Application->CreateForm(__classid(TMainForm). HINSTANCE.

file:///D|/Manuales/appendix/project/inicial_bpr.lib PACKAGES = Vcl40.dfm LIBFILES = IDLGENFILES = IDLFILES = LIBRARIES = SPARELIBS = Vcl40..bpi tee40. # It is recommended to use the IDE to change any of the values in this # section.bpi Dss40.bpi Vclx40.bpi bcbsmp40.bpi TeeUI40.bpi \ ibsmp40.bpi Inet40.bpr" # -------------------------------------------------------------------------!if !$d(BCB) BCB = $(MAKEDIR)\.obj main.exe OBJFILES = Inicial.bpi \ NMFast40.bpi DEFFILE = # -------------------------------------------------------------------------PATHCPP = .obj RESFILES = Inicial.bpi Vcldb40.. !endif # -------------------------------------------------------------------------# IDE SECTION # -------------------------------------------------------------------------# The following section of the project makefile is managed by the BCB IDE.BPR Curso de C++ Builder Estructura y configuración de un proyecto Fichero "Inicial.Estructura y configuración de un proyecto de C++ Builder: INICIAL.04 # -------------------------------------------------------------------------PROJECT = Inicial.bpi teedb40.bpi Inetdb40.bpi vcldbx40.bpi vcljpg40.res RESDEPEN = $(RESFILES) main.bpi dclocx40.bpi Qrpt40. # -------------------------------------------------------------------------VERSION = BCB.html (1 of 5) [27/02/2003 16:24:35] .bpi Vclmid40.04.

Estructura y configuración de un proyecto de C++ Builder: INICIAL.0.. DEBUGLIBPATH = $(BCB)\lib\debug RELEASELIBPATH = $(BCB)\lib\release USERDEFINES = SYSDEFINES = _RTLDLL.Lib $(PACKAGES) sysinit.-w-par -w-inl -Vx -tW -tWM \ -D$(SYSDEFINES).obj $(OBJFILES) ALLRES = $(RESFILES) ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib # -------------------------------------------------------------------------!ifdef IDEOPTIONS [Version Info] IncludeVerInfo=0 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=3082 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1. PATHASM = .$(BCB)\lib.csm -w -Ve -r.0.0.-c -b.lib cp32mti..obj Memmgr.BPR PATHPAS = .USEPACKAGES # -------------------------------------------------------------------------CFLAG1 = -I$(BCB)\include. PATHRC = .$(BCB)\lib.$(BCB)\include\vcl AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /mx /w2 /zd LFLAGS = -L$(BCB)\lib\obj..$(RELEASELIBPATH) \ -I$(BCB)\include.0 InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion=1.\ -a8 -k -y -v -vi.-v -JPHNE -M RFLAGS = -i$(BCB)\include.0.html (2 of 5) [27/02/2003 16:24:35] .$(BCB)\include\vcl -Od -Hc H=$(BCB)\lib\vcl40.0 file:///D|/Manuales/appendix/project/inicial_bpr.$(USERDEFINES) IDLCFLAGS = -I$(BCB)\include -I$(BCB)\include\vcl -src_suffixcpp PFLAGS = -U$(BCB)\lib\obj.$(RELEASELIBPATH) -aa -Tpe -x -Gn -v # -------------------------------------------------------------------------ALLOBJ = c0w32.$(BCB)\include\vcl -$YD -$W -$O.NO_STRICT.

$(BCB)\include\vcl [HistoryLists\hlLibraryPath] Count=1 Item0=$(BCB)\lib\obj.autodepend # -------------------------------------------------------------------------!if !$d(BCC32) BCC32 = bcc32 !endif !if !$d(CPP32) CPP32 = cpp32 !endif file:///D|/Manuales/appendix/project/inicial_bpr.Estructura y configuración de un proyecto de C++ Builder: INICIAL. # -------------------------------------------------------------------------.$(BCB)\lib [HistoryLists\hlDebugSourcePath] Count=1 Item0=$(BCB)\source\vcl [Debugging] DebugSourceDirs=$(BCB)\source\vcl [Parameters] RunParams= HostApplication= RemoteHost= RemotePath= RemoteDebug=0 [Compiler] InMemoryExe=0 ShowInfoMsgs=0 [CORBA] AddServerUnit=1 AddClientUnit=1 PrecompiledHeaders=1 !endif # -------------------------------------------------------------------------# MAKE SECTION # -------------------------------------------------------------------------# This section of the project file is not used by the BCB IDE. It is for # the benefit of building from the command-line using the MAKE utility.BPR Comments= [HistoryLists\hlIncludePath] Count=1 Item0=$(BCB)\include.html (3 of 5) [27/02/2003 16:24:35] .

PATH..PATH. + $(ALLRES) ! # -------------------------------------------------------------------------.PATH. + $(DEFFILE). + $(ALLLIB). + $(PROJECT).Estructura y configuración de un proyecto de C++ Builder: INICIAL.PATH.CPP = $(PATHCPP) .pas.PAS = $(PATHPAS) !endif !if $d(PATHASM) .ASM = $(PATHASM) !endif !if $d(PATHRC) .RC = $(PATHRC) !endif # -------------------------------------------------------------------------$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE) $(BCB)\BIN\$(LINKER) @&&! $(LFLAGS) + $(ALLOBJ).C = $(PATHCPP) !endif !if $d(PATHPAS) .PATH.html (4 of 5) [27/02/2003 16:24:35] .BPR !if !$d(DCC32) DCC32 = dcc32 !endif !if !$d(TASM32) TASM32 = tasm32 !endif !if !$d(LINKER) LINKER = ilink32 !endif !if !$d(BRCC32) BRCC32 = brcc32 !endif !if !$d(IDL2CPP) IDL2CPP = idl2cpp !endif # -------------------------------------------------------------------------!if $d(PATHCPP) .hpp: $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< } file:///D|/Manuales/appendix/project/inicial_bpr.

i: $(BCB)\BIN\$(CPP32) $(CFLAG1) -n.obj: $(BCB)\BIN\$(BCC32) $(CFLAG1) -n$(@D) {$< } . {$< } .res: $(BCB)\BIN\$(BRCC32) $(RFLAGS) -fo$@ $< # -------------------------------------------------------------------------- Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/project/inicial_bpr.obj: $(BCB)\BIN\$(TASM32) $(AFLAGS) $<.rc.asm.c.Estructura y configuración de un proyecto de C++ Builder: INICIAL.obj: $(BCB)\BIN\$(DCC32) $(PFLAGS) {$< } .cpp.obj: $(BCB)\BIN\$(BCC32) $(CFLAG1) -n$(@D) {$< } .BPR .i: $(BCB)\BIN\$(CPP32) $(CFLAG1) -n.c.cpp.html (5 of 5) [27/02/2003 16:24:35] . {$< } . $@ .pas.

Sign up to vote on this title
UsefulNot useful