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]

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

El editor de código. file:///D|/Manuales/intro/2.5. Está perfectamente integrado con el inspector de objetos y el diseñador de formularios. Editor de código. Figura 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.IDE 4.

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

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

8. 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. 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. por lo que el usuario no puede elegir la ubicación de los componentes disponibles por defecto en la paleta de componentes. 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. aunque se le pueden añadir más mediante las opciones del menú de componentes (opción Component del menú principal). Cada componente tiene asignada una página. La paleta de componentes. Podemos decir que es un gran almacén de componentes listos para ser incorporados a una aplicación. todos los componentes de C++ Builder se encuentran cargados por defecto. todos los componentes disponibles se encuentran organizados en distintas páginas o carpetas según su funcionalidad. Conocer los componentes y su filosofía de trabajo (propiedades. 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. métodos y eventos) es fundamental para un programador. que se abre seleccionando View | Component List. pinchar sobre el formulario donde se desea colocalo. seleccionándolo y colocándolo en un formulario. Enlaces adicionales: file:///D|/Manuales/intro/2. Figura 2. Una estrategia alternativa (y menos utilizada) es seleccionar el componente en la ventana Components. Su aspecto es el que mostramos en la figura 2.IDE 3.html (8 of 26) [27/02/2003 16:23:53] .8. Por conveniencia. Todos los componentes (visuales y no visuales) están accesible rápida y cómodamente gracias a la paleta de componentes. A diferencia con Visual Basic.

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

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

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

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

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

El editor de código está relacionado muy estrechamente con el inspector de objetos.IDE A diferencia con Visual Basic. 7. Por esto es importante saber qué partes de ese código está mantenido automáticamente.html (14 of 26) [27/02/2003 16:23:53] . Administrador de Proyectos file:///D|/Manuales/intro/2. Cuando queramos eliminar un manejador de evento que ha sido generado automáticamente es conveniente no borrar "a mano" la función. C++ Builder nos permite el acceso a la totalidad del código fuente de la aplicación. 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). y sobre todo ¡¡¡evitar modificarlo!!!. Al hacer doble click en un 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. No tenemos que preocuparnos de cuál es exactamente el prototipo que debemos de usar para la función que maneje el evento. EJERCICIO 3: Uso del inspector de objetos para escribir gestores de eventos con el editor de código.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

html (4 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.

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

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

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

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

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

añadir el componente MainMenu al formulario y hacer doble click sobre él para acceder al diseñador de menús.html (1 of 2) [27/02/2003 16:23:55] . file:///D|/Manuales/appendix/components/Standard. 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. proceder como con el componente MainMenu. o incluso para mostrar resultados. Muestra texto que el usuario no puede seleccionar ni manipular. Para añadir opciones al menú y a los submenús. Se usa para mostrar textos de título.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). Label encabezamientos. Muestra un área de edición de texto en la que el usuario puede introducir y modificar múltiples líneas de texto.Paleta de componentes . ya que puede establecerse su valor (propiedad Caption) en tiempo de ejecución. Para configurar el menú desplegable. Crea menús desplegables (también llamados menús contextuales) que aparecen cuando se pincha con el botón PopupMenu derecho del ratón.

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

Crea un botón que puede contener un gráfico pero no contiene texto. como códigos postales o números de teléfono. file:///D|/Manuales/appendix/components/Additional. salvo que proporciona la posibilidad de especificar formatos particulares. Crea una rejilla que puede usarse para mostrar cadenas en filas y columnas. Permite la introducción y edición de datos.Paleta de componentes . Crea una rejilla que puede usarse para mostrar datos en filas y columnas. normalmente. dentro de un panel para crear una barra de herramientas.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"). Estos botones se agrupan. como lo hace el componente Edit.html (1 of 2) [27/02/2003 16:23:55] .

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

Se emplea para gestionar eficientemente grandes conjuntos de imágenes o "bitmaps". Se emplea para construir cuadros de diálodo con múltiples páginas dentro de la misma ventana. Es una barra que muestra un rango y un indicador que muestra el valor actual y que permite modificarlo. Paracrear una lista de imágenes. 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. TabControl PageControl ImageList Divisor de páginas mutuamente exclusivas accesibles por pestañas.Paleta de componentes . tabulaciones. color. indentación o numeración). negrita o itálica).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.html (1 of 2) [27/02/2003 16:23:56] . Es una especialización del componente Memo: proporciona la posibilidad de 1) modificar propiedades acrerca de la fuente de letra (familia. y 3) marcación de texto y arrastre del mismo. tamaño. RichEdit TrackBar file:///D|/Manuales/appendix/components/Win32. 2) modificar propiedades de formato (alineamiento.

html (2 of 2) [27/02/2003 16:23:56] . La fecha DateTimePicker puede seleccionarse desde el calendario o empleando la barra de scroll o las flechas. Área para indicar el estado de acciones o textos de pista amplios ("Hints") en la parte baja de la ventana. MonthCalendar Muestra un calendario que representa un solo mes. 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. Muestra una lista de elecciones que está acompañada de una barra de scroll para seleccionar fechas. como una película. Muestra un encabezamiento sobre columnas de texto o números. Gestiona botones rápidos y otros controles.Win32 ProgressBar UpDown HotKey Animate Es una barra rectangular que se va "llenando" de izquierda a derecha. 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. TreeView ListView HeaderControl StatusBar ToolBar CoolBar PageScroller Muestra un conjunto de objetos estructurados jerárquicamente. Permite ver una lista en columnas. Este control puede dividirse en varias partes para proporcionar cabeceras para múltiples columnas. Asigna una combinación de teclas a cualquier componente. file:///D|/Manuales/appendix/components/Win32. Muestra una colección de controles "CoolBand" dentro de bandas que pueden moverse y redimensionarse.Paleta de componentes . Se emplea para mostrar cómo progresa una operación.

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.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 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. or to represent data received from a server in a multi-tiered database 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. See Creating a data provider for the application server. ClientDataSet file:///D|/Manuales/appendix/components/MIDAS. See Connecting to the SocketConnection application server Establishes an OLEnterprise connection to a remote server in a multi-tiered database application.Paleta de componentes .

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

See Creating decision datasets with the Decision Query DecisionQuery editor. file:///D|/Manuales/appendix/components/Decision_Cube. DecisionGrid Displays single and multidimensional data in table form.Paleta de componentes . See Using decision DecisionGraph graphs. Specialized form of TQuery used to define the data in a decision cube.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 and Using decision grids. Displays fields from a decision grid as a dynamic graph that changes when dimensions are modified. DecisionPivot Use to open or close decision cube dimensions or fields by pressing buttons. See Using decision sources. See Using decision cubes. See Using decision pivots.html [27/02/2003 16:23:59] . DecisionSource Defines the current pivot state of a decision grid or a decision graph.

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

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

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

html (2 of 2) [27/02/2003 16:24:00] . Muestra una ventana de diálogo modal común de Windows para seleccionar y abrir ficheros gráphicos.Paleta de componentes . file:///D|/Manuales/appendix/components/Dialogs. 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. PrinterSetupDialog Muestra una ventana de diálogo común de Windows para configurar impresoras. tamaño y estilo de letra. Es idéntica a la ventana asociada a OpenDialog salvo que contiene una región para previsualización de imágenes. 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. Muestra una ventana de diálogo modal común de Windows para seleccionar y guardar ficheros gráphicos. 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 especificar color. Muestra una ventana de diálogo común de Windows para seleccionar y guardar ficheros. Muestra una ventana de diálogo común de Windows para especificar información de impresión.Dialogs OpenDialog SaveDialog OpenPictureDialog Muestra una ventana de diálogo común de Windows para seleccionar y abrir ficheros.

Paleta de componentes .1 para permitir compatibilidad con aplicaciones antiguas. En la siguiente tabla se indica qué control debería usarse en su lugar: Control 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.Win 3. Estos controles no deberían usarse al desarrollar nuevas aplicaciones.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.1.1 Esta página incluye controles propios de Windows 3.html (1 of 2) [27/02/2003 16:24:01] .1 Iconos de los componentes agrupados en la página Win 3.

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

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.html [27/02/2003 16:24:01] . El código fuente está disponible en el directorio \EXAMPLES\CONTROLS\SOURCE de la instalación.

html [27/02/2003 16:24:02] . lets you create 2D graphs. and end-user functionality of the chart component. VSSpell Visual Speller. appearance. lets you customize a spelling checker. Choose Properties to display a tabbed control panel that lets you define the values. Son aplicaciones completas y portables creadas por otros desarrolladores.Paleta de componentes . F1Book Formula One. Lets you create highly customized charts. Chartfx file:///D|/Manuales/appendix/components/ActiveX. 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. lets you design a spreadsheet with its full-featured Designer. VtChart Lets you create true 3D charts.

Las páginas cuyo título está precedido por el símbolo español. 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. están traducidas al Standard Additional Win32 System Dialogs Data Access Data Controls QReport Decision Cube Internet MIDAS ActiveX Samples Win 3.1 file:///D|/Manuales/appendix/components/index.html [27/02/2003 16:24:02] . siguiendo el criterio de utilidad en este curso. por defecto. en 14 páginas.

Para ello escribiremos un gestor para el evento OnCreate asociado al componente MainForm. if (MainForm->Color == clBtnFace) MainForm->Color = clWhite. por ejemplo. 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 modificar su valor en tiempo de ejecución haremos que. Escribiremos el siguiente fragmento de código: //-----------------------------------------------------------void __fastcall TMainForm::FormCreate(TObject *Sender) { MainForm->Caption = "Primer programa con C++ Builder". Modificación y consulta de propiedades en tiempo de ejecución Curso de C++ Builder Ejercicio 4. 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".html (1 of 3) [27/02/2003 16:24:02] .Ejercicio 4. Recordar que basta con hacer doble click en OnCreate (pestaña Events del inspector de objetos) del componente MainForm. } //------------------------------------------------------------ A continuación. el título se establezca en el momento de la creación de la ventana. Modificación y consulta de propiedades en tiempo de ejecución Sobre el formulario que estamos empleando.

if (MainForm->Color == clBtnFace) MainForm->Color = clWhite.1. Figura E4.Ejercicio 4. el resultado es el mostrado en la figura E4. 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". CheckBox->Checked = false. file:///D|/Manuales/intro/ejemplos/ej4.html (2 of 3) [27/02/2003 16:24:02] . Modificación y consulta de propiedades en tiempo de ejecución //------------------------------------------------------------ Finalmente. El programa al iniciar su ejecución después de modificar propiedades en tiempo de ejecución. } //-----------------------------------------------------------// Lectura // Escritura // Escritura Si generamos el ejecutable y ejcutamos el programa.1.

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

CheckBox->Checked = false. // Lectura // Escritura // Escritura // Hide() es el metodo que oculta el // componente sobre el que se aplica. Métodos asociados a componentes Modificaremos el gestor del evento OnCreate del componente MainForm para que no se muestren los dos botones de radio. if (MainForm->Color == clBtnFace) MainForm->Color = clWhite. RadioButton2->Hide().1. Métodos asociados a componentes Curso de C++ Builder Ejercicio 5.html (1 of 2) [27/02/2003 16:24:03] . Figura E5. //--------------------------------------------------------------void __fastcall TMainForm::FormCreate(TObject *Sender) { MainForm->Caption = "Primer programa con C++ Builder". RadioButton1->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.1.Ejercicio 5. el resultado es el mostrado en la figura E5. } //--------------------------------------------------------------- Si generamos el ejecutable y ejcutamos el programa.

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

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

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

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

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.html (1 of 2) [27/02/2003 16:24:03] .

Cualquier uso de este material debe ser comunicado a los autores.html (2 of 2) [27/02/2003 16:24:03] .C++ Builder © 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. file:///D|/Manuales/contents.

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

. En 1995. que supuso la revolución en la programación para Windows e inició el desarrollo rápido y sencillo de aplicaciones visuales. técnicamente. Esta forma de trabajo se hizo más popular con Visual Basic. que dominar un entorno de programación visual. Los marcos de trabajo se pueden clasificar en dos categorías: 1. Los marcos de trabajo C++ (OWL y MFC) 2. Delphi ofrecía el desarrollo rápido de aplicaciones (RAD) empleando componentes (objetos que pueden ubicarse en formularios y manipulados por medio de propiedades. Delphi empleaba como base al lenguaje Object Pascal (una ampliación file:///D|/Manuales/intro/4. suele traducirse en conocer el leguaje base del entorno. mejor que MFC. y su marco de trabajo. También resulta más sencillo que OWL para los programadores que conocen la API. Microsoft desarrolló su propio marco de trabajo. 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..VCL Tan importantes son los marcos de trabajo. 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. La VCL.) la arquitectura de OWL es. métodos y eventos). Aunque MFC se usa más que OWL (Microsoft. MFC es una biblioteca de clases menos abstracta que el OWL y más cercana a la API.html (2 of 7) [27/02/2003 16:24:04] .

por lo que se ejecutaban mucho más rápido que los de Visual Basic. El objetivo final de la VCL es crear clases que representan a componentes. está escrita en Object Pascal..2 mostramos una pequeña parte de la jerarquía de clases que forman la VCL. Jerarquía de clases de la VCL. métodos y eventos). 4. En las secciones 4.2. La VCL hace un uso extensivo del concepto de herencia.1.3 describimos con más detalle las clases más importantes de la VCL. En la figura 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. de hecho.. Es file:///D|/Manuales/intro/4. Figura 4.2 y 4. 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.1. La VCL desarrollada para Delphi es la misma que se emplea como núcleo de C++ Builder. 4. además de innecesario. Un paseo por la VCL Conocer en profundidad la VCL se nos antoja imposible.html (3 of 7) [27/02/2003 16:24:04] .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.

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

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

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

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

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

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

3. 1. Propiedad Active Descripción Especifica si la aplicación está activa y tiene el foco. métodos y eventos Curso de C++ Builder TApplication .html (1 of 4) [27/02/2003 16:24:05] . por ejemplo. 2.Propiedades.Propiedades. métodos y eventos q q q 1. 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. Este cuadro aparece cuando ocurre el evento OnHint. Eventos de las aplicaciones. Métodos de las aplicaciones. Pueden emplearse las funciones GetShortHint() y GetLongHint() para obtener las dos partes de la propiedad Hint Hint y ShowHint file:///D|/Manuales/appendix/tapplication.TApplication . Propiedades de las aplicaciones. ShowHint determina si los cuadros de sugerencia estarán activados o desactivados para toda la aplicación. Propiedades de las aplicaciones. Hint especifica el texto que debe aparecer en el cuadro de ayuda o texto de sugerencia asociado a la aplicación.

Crea un nuevo formulario. Generalmente. métodos y eventos MainForm especifica qué formulario actúa como ventana principal de la aplicación. se gestiona a través de WinHelp. HelpContext() y HelpJump() MessageBox() file:///D|/Manuales/appendix/tapplication.html (2 of 4) [27/02/2003 16:24:05] . Para ocultarla. Devuelve un valor que depende del botón seleccionado para cerrar el cuadro de diálogo. Método BringToFront() Descripción Establece la última ventana activa como la que se muestra por encima de todas las demás. respectivamente. Generan un evento OnHelp. Icon y Title Especifican el icono y el texto. y si no hay un gestor para este evento. 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. Muestra un mensaje al usuario en cuadro de diálogo que puede incorporar botones. MainForm y ShowMainForm ShowMainForm especifica si la aplicación debe mostrar la ventana principal al iniciar su ejecución. 2.TApplication . HelpFile y Para especificar el fichero de ayuda asociado a la aplicación. CreateForm() HelpCommand().Propiedades. Pueden establecerse en tiempo de diseño seleccionando Project | Options | Application. Métodos de las aplicaciones. CurrentHelpFile. Se emplean para gestionar la ayuda asociada a una aplicación. 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.

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

Los métodos HelpContext() y HelpJump() gestionan automáticamente este evento.Propiedades.html (4 of 4) [27/02/2003 16:24:05] . 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.TApplication . Ocurre cuando la aplicación recibe una petición de ayuda. Ocurre cuando se pulsa una tecla. Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tapplication. respectivamente. 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. métodos y eventos OnMinimize y OnRestore OnHelp Ocurren cuando la aplicación se minimiza o se reestablece al tamaño normal.

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. 2. OnKeyDown.html [27/02/2003 16:24:05] . y 3. OnKeyUp Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tip/tip_tecla. por este orden: 1.

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

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

Propiedades. El valor devuelto cuando se cierra un formulario modal (abierto con el método ShowModal()). Canvas ClientRect ModalResult FormState file:///D|/Manuales/appendix/tform. minimizado o maximizado) o consultar su estado. Propiedades en tiempo de ejecución. WindowState 1. Visible Indica si el formulario es visible o no.. etc. ShowHint determina si los cuadros de sugerencia estarán activados o desactivados para el formulario. en el área de cliente. si es visible. Para establecer el estado inicial del formulario (normal. Suele usarse con el gestor del evento OnPaint. 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. por ejemplo.TForm . texto.).2. 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. Propiedad Active Descripción Indica si el formulario está activo (si tiene el foco).html (3 of 6) [27/02/2003 16:24:06] . Proporciona información acerca del estado en que se encuentra un formulario (si se está creando.. si es modal. Este cuadro aparece cuando ocurre el evento OnHint. 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. La propiedad Canvas da acceso a esta superficie para dibujar líneas. mapas de bits. El lienzo es la superficie del formulario sobre la que se puede dibujar.

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

OnMouseMove. Eventos asociados al movimiento y pulsación con el ratón.Propiedades. Eventos asociados a la pulsación de alguna tecla. respectivamente. 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. Un formulario se activa cuando se recibe el foco y se desactiva cuando el foco pasa a otro formulario de la misma aplicación. cuando se pincha con él sobre el formulario. Para responder a los eventos que suceden al mover el ratón o OnMouseUp. Hace una llamada a OnCloseQuery para asegurarse de que es correcto cerrarlo.html (5 of 6) [27/02/2003 16:24:06] .TForm . 3. métodos y eventos Release() Destruye un formulario y libera toda la memoria asociada. El evento OnClose ocurre cuando se cierra un formulario. Evento OnActivate y OnDeactivate Descripción Ocurren cuando se activa o desactiva un formulario. OnCreate y OnDestroy OnClose y OnCloseQuery OnMouseDown. 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. OnClick y OnDblClick file:///D|/Manuales/appendix/tform.

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

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. 3. Atrás file:///D|/Manuales/appendix/tip/tip_form. El constructor del formulario. OnCreate. OnClose. OnActivate. De la misma manera. 3. que enumeramos ordenadamente: 1. OnPaint. cuando se destruye el formulario se generan los siguientes eventos. que enumeramos ordenadamente: 1. OnDestroy. OnShow. 4. 5. 4.html (1 of 2) [27/02/2003 16:24:06] . El destructor del formulario (si existe). OnCloseQuery. 2. 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.

OnDblClick. que enumeramos ordenadamente: 1. 3. Así. Si se quiere atender a la pulsación del ratón sobre un formulario o un control. una pulsación del ratón genera los siguientes eventos. cuando el usuario pulsa dos veces sobre un formulario o un control se generan los siguientes eventos. Atrás file:///D|/Manuales/appendix/tip/tip_raton. 2. 3. que enumeramos ordenadamente: 1. OnMouseDown. OnMouseDown.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. OnClick. De la misma manera. 4. OnMouseUp. OnMouseUp.html (1 of 2) [27/02/2003 16:24:06] . OnClick. 2. Si se tienen que utilizar OnMouseDown y OnMouseUp hay que tener en cuenta que OnClick lleva involucrado los eventos OnMouseDown y OnMouseUp. tan sólo hay que atender al evento OnClick.

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.

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

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

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

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

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

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

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. Sr/Sra.. En main. RadioButton1 es un puntero a un objeto de tipo TRadioButton. desconocido/a".Propiedad Name --#endif Observar que.. . } //-------------------------------------------------------------------------- Accedemos a la propiedad Checked de RadioButton1 mediante el operador -> porque RadioButton1 es un puntero. En el listado anterior. al primer botón de radio se le asignó el valor RadioButton1 a su propiedad Name. Atrás © Francisco Cortijo Bon file:///D|/Manuales/appendix/tip/tip_name.... por ejemplo.html (2 of 2) [27/02/2003 16:24:07] .

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

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

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

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

bpr (Borland Project).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. definiciones de clases. 2. file:///D|/Manuales/appendix/project/index. Para este trabajo estructura los ficheros asociados a una aplicación en un proyecto. bibliotecas y el ejecutable final. declaraciones de funciones (prototipos). La extensión de estos ficheros es . de una serie de módulos adicionales que pueden contener declaraciones de clases. Para la creación de un ejecutable se requiere: 1. etc. 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. Ejecutar el programa make para que interprete el fichero makefile y desencadene las órdenes oportunas para la creación del ejecutable. Se puede decir que un fichero de proyecto es un fichero makefile.html (1 of 4) [27/02/2003 16:24:08] . 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. opcionalmente. de acuerdo a lo especificado en el fichero makefile.

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

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

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

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

html (2 of 2) [27/02/2003 16:24:08] .C++ Builder .3 6.5 Sección 7 Sección 8 Atrás file:///D|/Manuales/exercises.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.

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

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

1. En la lista siguiente se detallan las modificaciones a realizar. por file:///D|/Manuales/intro/ejemplos/ej2. básicamente. 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. Las modificaciones se realizarán usando el Inspector de Objetos (pestaña Properties). Name: Se refiere al nombre con el que se va a referenciar al componente desde el programa. al texto que aparece sobre un botón). Al ser un identificador (como un nombre de variable. Uso del inspector de objetos para modificar propiedades Curso de C++ Builder Ejercicio 2.html (1 of 3) [27/02/2003 16:24:09] .1. El formulario de la figura 6 modificado. 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.Ejercicio 2. Figura E2.

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

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

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

Aplicaciones de consola. ejecutándose sobre una consola MS-DOS. indicar que se va a crear una aplicación de consola (Console). 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.Aplicaciones simples Curso de C++ Builder Ejemplos de aplicaciones simples 1. Una aplicación de consola se crea usando el asistente Console Wizard. Veamos cómo.Ejemplos . Seleccionar File | New | Console Wizard y en el asistente. En cualquier caso. C++ Builder permite la creación de este tipo de aplicaciones.html (1 of 6) [27/02/2003 16:24:10] . 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.

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

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

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

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

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 .

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

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. Añadir un nuevo formulario al proyecto: seleccionar File | New Form y fijar Name =SaludoBox y Caption= Cuadro de salutación. Este formulario tiene un único componente Label llamada Label.Ejemplos . El aspecto del formulario será el siguiente: file:///D|/Manuales/intro/ejemplos/controles/index. Configurar el formulario secundario. tres Edit (solapa Standard).html (2 of 5) [27/02/2003 16:24:10] .

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

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

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

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

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

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

bmp) y Salir (Name = ExitBtn.Ejemplos . Glyph: dooropen. Cambiar las propiedades: s s s Name = FileOpenBtn Left = 4 Glyph: Pinchar dos veces en la propiedad Glyph y seleccionar el icono fileopen. Glyph: filesave. 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. Repetir estos pasos para los botones Salvar Fichero (Name =FileSaveBtn.html (4 of 15) [27/02/2003 16:24:12] . file:///D|/Manuales/intro/ejemplos/editor/index.Editor de texto lugar del formulario.bmp.bmp). Se colocarán los botones para abrir fichero. Para el botón Abrir Fichero: Seleccionar un componente SpeedButton (solapa Additional) y colocarlo en el panel. salvar fichero y salir del programa.

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

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

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

Ejemplos . Conf. Caption=&Imprimir y Enabled=false. impresora: Name=FilePrintSetUp.Editor de texto Añadir las opciones: Nuevo. Guardar: Name=FileSave y Caption= &Guardar.3. (separador). Guardar. Configurar impresora. Imprimir. (separador) y Salir. Incluir un separador: Caption = Imprimir: Name=FilePrint. Guardar como: Name=FileSaveAs y Caption= Guardar &como. Abrir. Menú Edición.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. file:///D|/Manuales/intro/ejemplos/editor/index. 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. Guardar como.

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

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

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

le asignamos las misma función al evento OnClick.Ejemplos . seleccionar el componente ExitBtn en el inspector de objetos.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. Opción: Edición | Pegar y Pegar del menú contextual. Para cada opción. Así. pulsar en la pestaña Events y en en evento OnClick. Para ello. desplegar la lista de funciones pulsando sobre la flecha que aparece a la derecha del evento OnClick (ahora sólo está FileExitClick()) y seleccionarla. Dicho de otra forma. 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. proceder de la misma forma. Para seleccionar una de las funciones ya escritas. 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. } //------------------------------------------------------------ Como el botón rápido para salir ExitBtn debe realizar la misma tarea.html (12 of 15) [27/02/2003 16:24:12] .

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

Seleccionar FuncsEditor.. 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... éste se especifica también en la misma propiedad separado por la barra |. El código que abre esta ventana se completa como sigue: seleccionar la opción Ayuda | Acerca de .. Ahora.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. Salvar. Por ejemplo. Finalmente.. Se puede asociar a cada componente un cuadro de pista (Hint) fijando al valor de su propiedad Hint al texto que se quiere mostrar. o Acerca de . cuando se seleccione Ayuda | Acerca de . construir el proyecto y ejecutar. en el menú contextual debe abrirse la ventana que hemos creado. Seleccionar About.cpp Añadir esta unidad al proyecto.Ejemplos .html (14 of 15) [27/02/2003 16:24:12] . y completar el manipulador HelpAboutClick() de la siguiente forma: //----------------------------------------------------------- void __fastcall TMainForm::HelpAboutClick(TObject *Sender) { AboutBox->ShowModal().cpp y File | Include Unit Hdr. Seleccionar File | Save y darle el nombre About. 6. Sobre la barra de estado y los cuadros de pista (Hints). Si se desea que aparezca un texto más amplio en la barra de estado. construir el proyecto y ejecutarlo. Observar que al poner el cursor sobre el botón se muestra el cuadro de pista pero no en la barra de estado..

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

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

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

file:///D|/Manuales/intro/ejemplos/editor/fich_abrir. ¿Salvar los cambios?".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 . 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. int result = Application->MessageBox( "El fichero activo ha cambiado.

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

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

html (1 of 2) [27/02/2003 16:24:13] .Ejemplos . // Solo hay que guardarlo con SaveToFile().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. file:///D|/Manuales/intro/ejemplos/editor/fich_guardar. if (SaveDialog->FileName != "") { Memo->Lines->SaveToFile(SaveDialog->FileName).

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

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". if (SaveDialog->Execute()) { Memo->Lines->SaveToFile(SaveDialog->FileName). Memo->Modified = false. } file:///D|/Manuales/intro/ejemplos/editor/fich_guardar_como.html (1 of 2) [27/02/2003 16:24:13] .Ejemplos .

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 .

// Llamada a TMemo->Undo() } //----------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/editor/edic_deshacer.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] .Ejemplos .

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.Editor de texto Curso de C++ Builder Un sencillo editor de texto Opción: Edición | Cortar y Cortar del menú contextual.Ejemplos .html (1 of 2) [27/02/2003 16:24:13] .

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] .

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

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

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

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

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 | Seleccionar todo //----------------------------------------------------------- void __fastcall TMainForm::EditSelectAllClick(TObject *Sender) { Memo->SelectAll(). // TMemo->SelectAll() } //----------------------------------------------------------- file:///D|/Manuales/intro/ejemplos/editor/edic_seleccionar_todo.Ejemplos .

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

dos. una barra.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 | Ajustar //----------------------------------------------------------- void __fastcall TMainForm::EditWordWrapClick(TObject *Sender) { // Modificar la propiedad TMemo::WordWrap. Memo->WordWrap = !Memo->WordWrap. // Si WordWrap está activo. EditWordWrap->Checked = Memo->WordWrap. file:///D|/Manuales/intro/ejemplos/editor/edic_ajustar.Ejemplos . Si no.

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

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

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

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

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

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

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

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

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

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

1. Pilares de la POO. 5. Creación por Declaración.Programación Orientada a Objetos en C++ esquematizan en la figura 5. TObjGraf ObjGraf2. declarando una variable del tipo de la clase.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().h: #include "ObjGraf. } file:///D|/Manuales/intro/5. Un objeto se puede instanciar de una forma simple.1.1. Creación y Destrucción de Objetos Ya se ha dicho que una clase es únicamente una especificación.html (3 of 28) [27/02/2003 16:24:17] . Para poder utilizar la funcionalidad contenida en la misma. En Ppal. se deben instanciar las clases.h" En Ppal.2. Figura 5.

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

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.2 esquematizamos las propiedades y métodos que se van a asociar a los objetos de la clase TObjGraf: Figura 5.3. De esta manera la aplicación recupera los recursos (memoria) que ese objeto había acaparado cuando se creó. En un objeto podemos distinguir dos aspectos bien diferenciados: q q Estado -----------> Propiedades Comportamiento ---> Métodos En P. Encapsulamiento En la programación clásica (lenguaje C.html (5 of 28) [27/02/2003 16:24:17] .O. los datos y los procedimientos que los gestionan están relacionados explícitamente y se "encapsulan" en un objeto. En Ppal.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.O. La destrucción de objetos creados en tiempo de ejecución con new se realiza mediante el operador delete. p. Propiedades y métodos de los objetos de la clase TObjGraf.2.Programación Orientada a Objetos en C++ Cuando un objeto deja de ser útil hay que eliminarlo. En la figura 5.) existen datos y procedimientos que actúan sobre esos datos. 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. 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. } //-------------------------------------------------- 5.e.

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

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

además de los suyos propios. Mejora del mantenimiento. // Propiedad exclusiva de TCuadrado file:///D|/Manuales/intro/5. // Propiedad exclusiva de TCirculo }. En la figura 5. // Deriva de la clase base TObjGraf //*************************************************/ class TCuadrado : public TObjGraf { public: int Lado.3 esquematizamos el mecanismo de herencia para las nuevas clases y las nuevas propiedades que se asocian a los objetos de las clases derivadas. Reusabilidad de clases (propias o no).html (8 of 28) [27/02/2003 16:24:17] .4 En ObjGraf. Tomando como base la clase TObjGraf se van a construir dos nuevas clases.h: //*************************************************/ // Definicion de la clase derivada TCirculo // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { public: int Radio. TCirculo y TCuadrado. que derivan de TObjGraf.3.Programación Orientada a Objetos en C++ de los suyos propios. Las clases TCirculo y TCuadrado heredan las propiedades y métodos de la clase TObjGraf. //*************************************************/ // Definicion de la clase derivada TCuadrado. 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.

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

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

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

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

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

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

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

TPaintBox * PaintBox. int _Y=0). int _Y=0. int _Radio=1). 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. TColor _Color=clBlack. int Y. int _X=0. // Instanciacion del metodo virtual puro // de la clase TObjGraf }.html (16 of 28) [27/02/2003 16:24:17] . int Radio. TColor Color. file:///D|/Manuales/intro/5. // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { protected: // Pueden acceder los objetos de esta clase y sus descendientes. // Otros metodos virtual void Mostrar (void) = 0.Programación Orientada a Objetos en C++ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int X. // Metodo virtual puro }. // Puede acceder SOLO los objetos de esta clase. void Mostrar (void). // Constructor de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. public: // Pueden usarlas todas. protected: // Pueden acceder los objetos de esta clase y sus descendientes. int _X=0. TColor _Color=clBlack. public: // Metodo constructor TCirculo (TPaintBox *_PaintBox.

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

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

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

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

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

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

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

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

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

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

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

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.

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

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

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

.) { ShowMessage ("El divisor no puede ser cero.Tratamiento de excepciones try { Cociente = Dividendo / Divisor. ShowMessage ("Cociente = " + AnsiString(Cociente)).3. } catch (.. Ahora.3 Figura 6.html (4 of 16) [27/02/2003 16:24:19] .").2. Ventana resultante de la gestión de la excepción. file:///D|/Manuales/intro/6.2. Ventana Debugger Options Con esto indicamos al depurador de C++ Builder que nuestro programa se encargará de manejar las excepciones C++ que ocurran. Figura 6. } 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. al ejecutar el programa e intoducir el valor 0 como divisor se muestra la ventana mostrada en la figura 6.

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

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

cpp: void TPelota :: Mover (void) { Borrar (). try { X += FDirX * Velocidad. try { Y += FDirY * Velocidad.. En ObjGraf.) se capturará cualquier excepción. // Correcto: escribir sin modificar } 6. Captura de excepciones El bloque susceptible de producir alguna excepción ("zona crítica") se encierra en un bloque try. } file:///D|/Manuales/intro/6. 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.. } catch (EFueraRango) { FDirX = -FDirX..html (7 of 16) [27/02/2003 16:24:19] . }. en el bloque catch. }. Si se especifica catch (. en el momento que ocurra una excepción se ejecutará el bloque catch cuya clase concuerde con la de la excepción. } catch (EFueraRango) { FDirY = -FDirY. 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. Mostrar ().Tratamiento de excepciones } else FY = _Y. try { <bloque de instrucciones críticas> } catch (<tipo excepción1> <variable1>) { <manejador 1> } catch (<tipo excepción2> <variable2>) { .3. } Podemos especificar tantos bloques catch para un bloque try como deseemos..

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

Excepciones no tratadas Si una excepción que ha sido lanzada no encuentra un manejador apropiado. el proyecto debe estar como se indica en el proyecto Ejemplo3. Dos instantes del movimiento de la pelota. se llamará a la función terminate(). Excepciones de la VCL Si se utilizan componentes de la VCL en las aplicaciones. Normalmente. 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().html (9 of 16) [27/02/2003 16:24:19] . Pero de igual manera que con terminate() podemos definir nuestra propia función unexpected() con set_unexpected().4: Figura 6. Si no se realiza un tratamiento de la excepción. de E/S de archivos. 6. El resultado es el mostrado en la figura 6. C++ Builder incorpora un extenso conjunto de clases de excepción integradas que permiten tratar automáticamente errores de división por cero. 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. entonces se llama a la función unexpected() la cual por defecto llama a terminate().5. 6. de conversiones de tipos y otras file:///D|/Manuales/intro/6. la cual por defecto realiza un abort(). aparece un mensaje que describe el tipo de error que se ha producido.Tratamiento de excepciones la figura 6.2. 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. la VCL llevará a cabo un tratamiento por defecto.4. En este punto.4. 1. Clases de Excepciones.

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

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

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

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

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

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

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

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

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

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

// Metodo virtual puro __property __property __property __property __property }. {read=GetAlto }. TColor _Color=clBlack.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. *PaintBox.crean un (int _Y) throw (EFueraRango). // Metodo virtual puro virtual int GetAlto (void) = 0. write=SetY }. //*************************************************/ // Definicion de la clase base TObjGraf //*************************************************/ class TObjGraf { private: int FX. {read=FColor.html (4 of 10) [27/02/2003 16:24:20] . int FY. {read=FY. TObjGraf (TObjGraf *ObjGraf). // Otros metodos virtual void Mostrar (void) = 0.OOP . int _Y=0). // Si hay problemas. file:///D|/Manuales/intro/ejemplos/oop/Ejemplo3. // Metodo virtual puro protected: TColor TPaintBox public: // Constructores de objetos TObjGraf TObjGraf (TPaintBox *_PaintBox. FColor. {read=GetAncho }. write=SetX }. int int TColor int int X Y Color Ancho Alto = = = = = {read=FX. void SetX void SetY EFueraRango (int _X) throw (EFueraRango). //*************************************************/ class EFueraRango {}. int _X=0. write=FColor}. // objeto de clase virtual int GetAncho (void) = 0.

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

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

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

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

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

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

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

wav". que se escribirá por encima de todas las funciones de Ppal. file:///D|/Manuales/intro/ejemplos/Sonidos/index. MediaPlayer1->Play(). 3.wav". } catch (Exception & e) { Error (MediaPlayer1->FileName. } } //-------------------------------------------------------------void __fastcall TForm1::MSSoundBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\The Microsoft Sound. try { MediaPlayer1->Open().Sonidos 4.wav". Un cuadro de diálogo OpenDialog (pestaña Dialogs).cpp. La gestión de las interrupciones capturadas se realiza con una función común cuyo prototipo es: void Error (AnsiString & name. e). } catch (Exception & e) { Error (MediaPlayer1->FileName. Escribir los gestores de eventos asociados a la pulsación de los botones.Ejemplos . try { MediaPlayer1->Open(). MediaPlayer1->Close(). MediaPlayer1->Play(). MediaPlayer1->Wait = true. Exception & e). try { MediaPlayer1->Open(). MediaPlayer1->Play(). MediaPlayer1->Wait = true. } } //-------------------------------------------------------------void __fastcall TForm1::ErrorBtnClick(TObject *Sender) { MediaPlayer1->FileName = "C:\\WINDOWS\\MEDIA\\NoEsta. Así. MediaPlayer1->Close().html (2 of 4) [27/02/2003 16:24:20] . 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. MediaPlayer1->Wait = true. 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.Ejemplos . } //-------------------------------------------------------------- Cuando se ejecuta este programa.wav aparece la siguiente ventana: file:///D|/Manuales/intro/ejemplos/Sonidos/index. if (OpenDialog1->Execute()) { MediaPlayer1->FileName = OpenDialog1->FileName. MediaPlayer1->Close(). } } //-------------------------------------------------------------void __fastcall TForm1::OtrosBtnClick(TObject *Sender) { OpenDialog1->Title = "Abrir un fichero de sonido". MediaPlayer1->Wait = true. si se quiere reproducir un fichero cuyo formato no sea .Sonidos MediaPlayer1->Close(). OpenDialog1->Filter = "Ficheros de sonido (*. e).html (3 of 4) [27/02/2003 16:24:20] . OpenDialog1->InitialDir = "C:\\WINDOWS". try { MediaPlayer1->Open().WAV".Message)). } catch (Exception & e) { Error (MediaPlayer1->FileName.wav) | *. e). } catch (Exception & e) { Error (MediaPlayer1->FileName. MediaPlayer1->Play().ClassName()) + "\nDetalles: " + AnsiString(e. } } // if (OpenDialog1->Execute()) } //-------------------------------------------------------------void Error (AnsiString & name. Exception & e) { ShowMessage ("Fallo en la reproducción del fichero de sonido: " + name + "\nExcepción: " + AnsiString(e.

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

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.html (1 of 2) [27/02/2003 16:24:20] . 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] .

Aprovechamiento de los recursos del sistema Cuando se utiliza una sola hebra. 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?).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. podemos aprovechar los períodos de inactividad del sistema. La depuración de las aplicaciones es difícil. ¿Por qué usar Hebras? El uso de hebras (de paralelismo.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. La CPU permanece ocupada file:///D|/Manuales/threads/introduction. Las hebras han de coordinarse de algún modo. El diseño de aplicaciones multihebra es complejo. Ejemplo: Supongamos que nuestra aplicación tiene que ocuparse de la realización de copias de seguridad de los datos con los que trabaja. Consideraciones: q q q q Cada hebra supone una carga adicional al sistema.

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

..h). 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] . 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. Como sucede con cualquier otra clase. Ejemplo: Crear una hebra Abrimos el repositorio en su página New (al que se accede desde la opción del menú File->New. Para facilitar el trabajo.cpp y HPelota. Seleccionamos el elemento Thread Object. para lo cual se ha de crear una clase derivada de TThread.). C++Builder incluye un asistente que lo hace por nosotros. 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”. La clase TThread es abstracta porque posee un método virtual puro denominado Execute(). que será el que rellenemos con el código asociado a la hebra.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. Denominamos THebraPelota a la clase derivada de TThread.

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. tpTimeCritical La hebra tiene la prioridad más alta. donde se establecen los valores iniciales de cuantas propiedades sean necesarias. tpLowest Dos puntos por debajo del valor normal. 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. tpHigher Un punto por encima del valor normal. Dos características de las hebras conviene establecerlas en el constructor: su prioridad y cuándo debe liberarse la hebra. se invoca al constructor de su clase base (TThread): __fastcall TThread(bool CreateSuspended). 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.html (2 of 4) [27/02/2003 16:24:21] . tpLower Un punto por debajo 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.C++ Builder Inicialización de las hebras La inicialización de una hebra se realiza en su constructor. tpNormal La hebra tiene la prioridad normal. Antes de invocar al constructor de una clase derivada de TThread. tpHighest Dos puntos por encima del valor normal.

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

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

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

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

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

html (4 of 4) [27/02/2003 16:24:21] .. 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). } Nota: La sentencia Sleep(3000).a que se liberen todas las hebras delete[] Objs. // Esperar tres segundos. ++i) Objs[i]->Terminate(). // . Sleep(3000)...C++ Builder } void __fastcall TPpalFrm::FormDestroy(TObject *Sender) { for (int i=0. © Fernando Berzal Galiano file:///D|/Manuales/threads/execution..

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. las distintas hebras de una aplicación han de coordinar su ejecución. Es decir. Hay que tener cuidado para evitar que dos hebras accedan a un recurso compartido (vg: objeto o variable global) al mismo tiempo. Para evitar conflictos con otras hebras. aunque el funcionamiento de la aplicación es correcto. Uso de recursos compartidos Cuando varias hebras comparten el uso de un recurso.html (1 of 6) [27/02/2003 16:24:22] . 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. pueden ocurrir situaciones no deseadas si dos o más hebras acceden (o intentan acceder) al mismo recurso simultáneamente. Esto se debe a que los métodos Mostrar() y Borrar() de las distintas hebras se entrelazan en el acceso al Canvas del PaintBox. la ejecución de una hebra puede depender del resultado de las tareas que realicen en otras hebras. Por tanto. Hay que tener cuidado de no bloquear innecesariamente la ejecución de otras hebras (para no disminuir el rendimiento de la aplicación). puede que se necesite bloquear la ejecución de otras hebras al acceder a objetos o variables compartidas. Ejemplo: Si ejecutamos el ejemplo anterior. file:///D|/Manuales/threads/coordination. al acceder a propiedades o ejecutar métodos pueden efectuarse algunas operaciones que utilicen memoria no protegida de las acciones de otras hebras. Además. ¡Se ha de evitar el acceso simultáneo de las hebras al componente Canvas del PaintBox!. la visualización en el PaintBox sufre algunos errores de forma aleatoria.

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

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

. SC->Release().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).. por lo cual será necesario que en ciertas ocasiones una hebra espere a que otra termine la ejecución de una acción determinada. . file:///D|/Manuales/threads/coordination.. Ejemplo: q En ObjGraf.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(). 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.html (4 of 6) [27/02/2003 16:24:22] .. En TPelota::Mostrar() y en TPelota::Borrar(). Cada sección crítica se asocia a un recurso que se desea compartir por varias hebras. eliminar el bloqueo del objeto de tipo TCanvas y emplear en su lugar la sección crítica: { SC->Acquire(). Si se omite la llamada a Release() el recurso quedaría bloqueado para siempre.C++ Builder TCriticalSection. } Sincronización entre hebras Puede que las distintas hebras de una aplicación realicen tareas que no sean completamente independientes. Al finalizar sus operaciones. // ¡¡¡Habría que destruirla!!! .

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]

Ejemplo file:///D|/Manuales/databases/bde. tales como el controlador [driver] empleado y la localización de la base de datos. de forma que éstas sean independientes de la base de datos que se utilice.html (1 of 3) [27/02/2003 16:24:23] .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. Los alias se definen con ayuda del BDE Administrator (que se encuentra en el Panel de Control de Windows). 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 necesita un "alias" para acceder a una base de datos particular. que no es más que una colección de DLLs. 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 proporciona el Borland Database Engine (BDE).

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. (destino de scache. 512: Nivel de aislamiento superior para las transacciones implícitas (lecturas repetibles).cpp. ENABLE SCHEMA CACHE ahorra tiempo y ancho de banda: r r r r q ENABLE SCHEMA CACHE = TRUE SCHEMA CACHE DIR = . 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. y el formulario con el nombre Ppal. los alias BDE disponibles en la máquina. Guardar el proyecto con el nombre BDEje. q Ver qué valores se pueden seleccionar para la propiedad DataBaseName.html (2 of 3) [27/02/2003 16:24:23] . NOTA: El nivel de lecturas repetibles no es adecuado para las aplicaciones que tienen que estar pendientes de las actualizaciones realizadas en otros puestos. q Añadir un componente TTable (en la página Data Access) al formulario.ini & *.C++ Builder Crear una aplicación nueva..

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

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 nos ofrece un "potente" asistente para generar formularios sencillos que accedan a bases de datos. Para utilizar el asistente hay que seguir los siguientes pasos: 1.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).."). seleccionando "Database Form Wizard" de la pestaña "Business": file:///D|/Manuales/databases/components.html (1 of 16) [27/02/2003 16:24:25] . Llamar al asistente como si fuésemos a añadir a nuestro proyecto un formulario más (con "File/New. Conjuntos de datos (no visuales).

Seleccionar el tipo de formulario que deseemos (simple o maestro/detalle) y cómo queremos generarlo (mediante tablas o consultas). 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. Seleccionamos la tabla a la cual deseamos acceder. 2.html (2 of 16) [27/02/2003 16:24:25] . En este caso. Para comenzar.

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

Finalmente. El resultado obtenido 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 (para separar los objetos que modelizan los conjuntos de datos de los controles que constituyen la vista de esos conjuntos de datos): 7.C++ Builder 6.html (4 of 16) [27/02/2003 16:24:25] .

podemos optar por disponer los campos verticalmente (tal como se hace desde tiempos del dBase): 6. Para evitar el error que se producía anteriormente (el uso indiscriminado de cajas de edición incluso para las imágenes).html (5 of 16) [27/02/2003 16:24:25] . Disposición vertical de los controles 5. Seleccionamos la primera de las opciones: file:///D|/Manuales/databases/components. Por ejemplo. al indicarle al asistente que pusiese los campos horizontalmente. además.C++ Builder El formulario de la imagen está bien aunque aún necesita algunos retoques. 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. Por desgracia. Hemos de indicar. los campos de tipo MEMO (textos) o BLOB (imagen en el ejemplo) no deben mostrarse en una simple caja de edición.

y el resultado que obtenemos es el siguiente: file:///D|/Manuales/databases/components. .C++ Builder 7.. Como en el ejemplo anterior..html (6 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: 8.

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. Creamos ahora un formulario maestro/detalle (master/detail) con objetos de tipo TTable para modelizar los conjuntos de datos: file:///D|/Manuales/databases/components. Formularios maestro/detalle Utilicemos ahora el asistente para algo un poco más complejo: 1.C++ Builder Este formulario está algo mejor que el inicial y.html (7 of 16) [27/02/2003 16:24:25] . para que se vea correctamente la imagen.

C++ Builder 2. 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.html (8 of 16) [27/02/2003 16:24:25] . una tabla que contiene información acerca de los clientes de una empresa: 3.DBF de la base de datos BCDEMOS como tabla maestra del formulario. Seleccionamos la tabla CLIENTS.

C++ Builder 4. 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.html (9 of 16) [27/02/2003 16:24:25] .

C++ Builder 5. Escogemos todos sus campos: file:///D|/Manuales/databases/components. Seleccionamos la tabla detalle.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] .

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

Como siempre. 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] .C++ Builder 9.

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

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

db) con los pedidos realizados hasta el momento (orders.dbf y clients.db) y el proveedor de cada pìeza (relación entre items.db) y una serie de reservas (reservat.db como detalle de customer.dbf) o el importe total de lo que ha ganado cada proveedor (vendors.db).db) tiene un lugar de celebración (venues.db).db y parts. no sólo su símbolo.dbf). Mostrar las inversiones de los clientes (relación entre holdings.dbf) de cada cliente (clients. Mostrar los pedidos de cada cliente (orders.db) y los clientes que acuden a cada recinto (custoly. 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) indicando los detalles de los pedidos (items.db). Cada evento (event.db.db). 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.dbf) indicando el nombre de las empresas en las que se invierte (almacenado en master.html (15 of 16) [27/02/2003 16:24:25] . Mostrar el total de inversiones (holdings.

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

aunque cada fila es en TDBCtrlGrid realidad un panel en el que se pueden colocar controles de datos "replicables". 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). en su caso. A continuación. la propiedad Hints permite especificar mensajes de ayuda para cada botón (que habrá que traducir). edición y borrado de datos. 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. Es el campo o columna del datasource al que accede cada control. pero enlazado a datos. Análogo a TEdit.html (1 of 6) [27/02/2003 16:24:25] . TDBEdit Presenta un cuadro de edición para un campo concreto. Igual que las etiquetas normales. Estos componentes trabajan con los datos seleccionados por las propiedades DataSource y. Por su parte. Rejilla que permite incluir controles: Como un TDBGrid. DataField: Propiedad DataSource DataField Descripción Indica el datasource del que se obtienen y al que se envían los datos. así como la inserción. file:///D|/Manuales/databases/controls. Permite construir gráficos a partir de un conjunto de datos. no consume recursos en Windows. Dicho enlace se establece mediante un DataSource. Muestra el valor de TDBText un campo. Control de navegación: Sirve para controlar el cursor. La propiedad VisibleButtons se utiliza para TDBNavigator seleccionar qué botones podrá pulsar el usuario. 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. 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.

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

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

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

Esta propiedad la podemos establecer dinámicamente como respuesta al evento OnTitleClick.html (5 of 6) [27/02/2003 16:24:25] . } else DBGrid->DefaultDrawColumnCell(Rect. DFCS_BUTTONCHECK | check). State). 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. TGridDrawState State) { if (CompareText(Column->FieldName. } Podemos seleccionar la columna por la que se ordenan los datos usando la propiedad IndexFieldNames del conjunto de datos. } 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.C++ Builder void __fastcall TFormXXX::DBGridDrawColumnCell (TObject *Sender. "ACTIVO") == 0) { UINT check = 0. else Table->IndexFieldNames = Column->FieldName. DFC_BUTTON. const TRect Rect. int DataCol. se puede responder al evento OnBeforeAction del TDBNavigator de la siguiente forma: Append en vez de Insert file:///D|/Manuales/databases/controls. if (Table1->FieldValues["ACTIVO"]) check = DFCS_CHECKED. (RECT*) &Rect. DrawFrameControl(DBGrid1->Canvas->Handle. TColumn *TColumn. DataCol. DBGrid->Canvas->FillRect(Rect).

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

El nombre de la base de datos con la que se está trabajando. las actualizaciones se mantienen en la caché de la máquina del cliente hasta que el programador los envíe al servidor. El componente TDataSource asociado. file:///D|/Manuales/databases/tdataset. Devuelve true cuando el cursor está llega al final del conjunto de datos.html (1 of 8) [27/02/2003 16:24:26] . métodos y eventos que se utilizan en estas clases están definidas realmente en TDataSet. De hecho. Cuando está a true. Cuando está a false. todos los cambios realizador en los conjuntos de datos se pasan automáticamente a la base de datos. Determina si el usuario puede editar el conjunto de datos o no.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. 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. Devuelve true si el cursor está en el primer registro del conjunto de datos. TTable. la mayoría de las propiedades. TQuery y TStoredProc son casos particulares de conjuntos de datos.

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

Abre el conjunto de datos. Obtiene todos los registros desde la posición actual del cursor hasta el final del conjunto de datos y los almacena localmente. Devuelve un campo TField dado su nombre. Cuando se cierra un conjunto de datos Después de que un registro se haya eliminado. Mueve el cursor un número determinado de filas. Sitúa el cursor en el último registro. Cierra el conjunto de datos. Inserta un registro en el conjunto de datos con los datos que se le indiquen y los envía con Post(). 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é). Actualiza el contenido del registro actual leyéndolo de la base de datos. Desactiva los controles de datos asociados al conjunto de datos (muy útil para evitar el parpadeo de los controles visuales).html (3 of 8) [27/02/2003 16:24:26] Descripción (¿cuándo se genera?) Después de cancelar las modificaciones. Mueve el cursor al siguiente 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. Búsqueda de un registro en particular. Después de que se ha modificado un registro. Después de abrir un conjunto de datos. Devuelve el estado actual cuando las actualizaciones en caché se activan. Después de insertar un registro. Mueve el cursor al primer registro. Elimina el registro actual. Cuando se utiliza la caché. .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é. Activa los controles de datos asociados al conjunto de datos. Establece los valores para todos los campos de un registro. Permite la edición del registro actual. Recupera la lista con los nombres de los campos del conjunto de datos. este método ignora los cambios hechos previamente que todavía no han sido enviados a 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.

Antes de que se cancelen los cambios.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. Cuando ocurre un error al actualizar los datos. con la posibilidad de generar una excepción (DatabaseError) file:///D|/Manuales/databases/tdataset. Antes de que se inserte un registro. Antes de eliminar un registro. Antes de entrar en modo edición.html (4 of 8) [27/02/2003 16:24:26] . Siempre que se añade un nuevo registro. Antes de enviar las modificaciones. Cuando ocurre algún error al editar una tupla. Antes de que se cierre un conjunto de datos. Cuando se actualiza el registro en la BD. Cuando ocurre algún error al eliminar una tupla. Antes de abrir el conjunto de datos. } Validaciones a nivel de registros Comprobaciones como respuesta al evento BeforePost. 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(). Cuando ocurre un error al enviar los cambios.

mtConfirmation. } else { Abort(). } 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().html (5 of 8) [27/02/2003 16:24:26] . } } Gestión de errores Eventos de detección de errores: OnEditError. } while (! tbLineas->Eof). TMsgDlgButtons()<<mbYes<<mbNo. 0). 0)==mrYes) { do { tbLineas->Delete(). OnDeleteError Posible solución ante un error de bloqueo no concedido file:///D|/Manuales/databases/tdataset.C++ Builder void __fastcall TDataModulePersonal::tbEmpleadosBeforePost(TDataSet *DataSet) { if (Date() . if (! tbLineas->Eof) if (MessageDlg("¿Eliminar detalles?".tbEmpleadosHireDate->Value < 365 && tbEmpleadosSalary->Value > TopeSalarial) DatabaseError("¡Este es un enchufado!". OnPostError.

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

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

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

TDataSource se encarga de toda la comunicación necesaria entre ellos.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. 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. de forma que podemos utilizarlo para hacer nuestros componentes "data-aware". TDBEdit. 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. TDBListBox.html (1 of 2) [27/02/2003 16:24:27] . por ejemplo) con los controles visuales que muestran los datos (TDBGrid. solamente hay que modificar su propiedad DataSet. etc. TQuery y TStoredProc. Para cambiar el conjunto de datos enlazado a un componente de tipo TDataSource (ya sea éste una tabla o una consulta).). file:///D|/Manuales/databases/tdatasource. por ejemplo) recibe el foco. El código común a todos los controles de datos está recogido en TDataLink (y en su descendiente TFieldDataLink).

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

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

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

Los registros se mantienen en la caché hasta que se llama al método ApplyUpdates(). Cuando la propiedad CachedUpdates está a true. En su lugar.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. Para confirmar los cambios se ha de llamar a CommitUpdates(). Para anular los cambios almacenados en caché se puede usar el método CancelUpdates(). CachedUpdates. Los conjuntos de datos de C++ Builder vienen equipados con una propiedad. file:///D|/Manuales/databases/cache. los cambios en los registros no se escriben en la base de datos.html (1 of 2) [27/02/2003 16:24:27] . 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. También se pueden anular las modificaciones hechas en un registro con el método RevertRecord(). se escriben en un buffer de la máquina local.

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

Fijar las propiedades necesarias para especificar correctamente la relación maestro/detalle (vg: reunión CustNoÞCustNo usando como índice CustNo).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. q Establecer la propiedad MasterSource en la tabla detalle para que apunte al DataSource de la tabla maestra. 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. Filtros Para realizar búsquedas se pueden utilizar tablas con filtros. TableName.html (1 of 6) [27/02/2003 16:24:28] . 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). Además. por ejemplo) y sus correspondientes DataSources. Ejercicio q Crear un módulo de datos (DataModule) que contenga dos tablas (clientes y pedidos. ReadOnly Métodos: Open&Close. Entre sus múltiples propiedades y métodos destacan: q Propiedades: DatabaseName. hay que especificar IndexName o IndexFieldNames para establecer un orden en la tabla detalle (y ¡para que C++Builder lo haga eficientemente!). 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. Para ello es necesario realizar el #include correspondiente.

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

ButtonClick(TObject *Sender) { Table->SetKey(). } 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. Table->Filter = "". Debe existir un índice sobre esas columnas. else Table->Cancel(). Table->Filtered = False. } Rangos También se puede limitar el conjunto de registros de un conjunto de datos utilizando rangos mediante los métodos SetRange y CancelRange. Table->Refresh(). 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. Alternativamente se pueden utilizan las combinaciones SetKey+GotoKey (en vez de FindKey) y SetKey+GotoNearest (sustituyendo a FindNearest) void __fastcall TFormDatos. // FormSearch => diálogo del tipo OK/Cancel con TDBEdits if (FormSearch->ShowModal() == mrOk) Table->GotoNearest(). file:///D|/Manuales/databases/ttable. } void __fastcall TFormX::miEliminarFiltroClick(TObject *Sender) { miActivarFiltro->Checked = False.html (3 of 6) [27/02/2003 16:24:28] .C++ Builder Table->Refresh().

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

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

registros--. int registros) { int intentos = 3. randomize(). // NOTA: Sería más eficiente si se agrupasen // distintas inserciones en una única transacción intentos = 3. while (registros > 0) try { 1) Tabla->Append(). 2) Tabla->AppendRecord( ARRAYOFCONST ( RandomString(longitud). Tabla->Post().C++ Builder } void CrearDatosSinteticos (TTable *Tabla. Tabla->FieldValues["Cadena"] = RandomString(longitud).html (6 of 6) [27/02/2003 16:24:28] . Table->Cancel(). } catch(Exception&) { intentos--. Tabla->FieldValues["Entero"] = random(MAXINT). } } 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(). random(MAXINT) ) )). © Fernando Berzal Galiano file:///D|/Manuales/databases/ttable. int longitud = Tabla->FieldByName("Cadena")->Size. if (intentos == 0) throw.

teclear: select * from customer where CustNo > 1300 Otra propiedad bastante interesante del componente TQuery es LiveRequest. no todas las consultas son actualizables. En tiempo de ejecución. o ExecSQL() para ejecutar una sentencia SQL de tipo INSERT. Sentencias SQL con parámetros En las sentencias SQL se pueden utilizar parámetros. 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. Por desgracia.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. que permite que una consulta sea actualizable (es decir. Ejemplo: q q q q Cambiar la tabla de clientes por una consulta. se puede usar Open() para ejecutar una consulta (SELECT). Enlazar el DataSource que tenía la tabla a la nueva consulta. 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. Enlazarla con la base de datos BCDEMOS (propiedad DatabaseName). El valor de tales parámetros se puede establecer file:///D|/Manuales/databases/tquery. 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()). que podamos editar su conjunto de datos sin tener que preocuparnos de cómo almacenar los cambios en la base de datos).

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

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

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

html (1 of 5) [27/02/2003 16:24:28] . 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. Establecer sus parámetros (igual que en una consulta TQuery). TotalVentas int. 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.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. Preparar su ejecución con el método Prepare(). Invocarlo tantas veces como sea necesario con ExecProc(). CantidadTotal int. select count(Numero). El esquema de utilización de procedimientos almacenados es: q Indicar su nombre en la propiedad StoredProcName.

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

html (3 of 5) [27/02/2003 16:24:28] . 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 (SUPER. create table HIERARCHY ( SUPER 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. create table CATEGORY ( ID TID not null. create domain TDESCRIPTION as VARCHAR(128).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. primary key (ID) ).SUB) ). SUB TID not null references CATEGORY. description TDESCRIPTION.

for select * from ANCESTORS(:super) into :super do begin if (super is not null) then SUSPEND.html (4 of 5) [27/02/2003 16:24:28] . end end END end ^ set term .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.^ Para utilizar los procedimientos almacenados anteriores. 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.

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

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

TField* __fastcall TDataSet::FieldByName(const AnsiString Nombre). __property int TFields::Count. Ejemplo file:///D|/Manuales/databases/tfield.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]. La propiedad Fields de TDataSet. q __property TFields* TDataSet::Fields. __property TField* TFields::Fields[int Index]. q El método FieldByName() de TDataSet.html (2 of 7) [27/02/2003 16:24:29] .

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

.::tbFieldGetText (TField *Sender. "LX". "IV". Al visualizar valores. "LXXX". void __fastcall . AnsiString &Text. "II". "XL". "VIII". "C". "I". "V". "L". static AnsiString Miles[4] = {"". Text = Miles[i / 1000] file:///D|/Manuales/databases/tfield. bool DisplayText) { static AnsiString Unidades[10] = {"". "IX"}. "DCCC".html (4 of 7) [27/02/2003 16:24:29] . "CM"}. "CC". "LXX". // Hay que ser consecuentes con el lenguaje } else { int i = Sender->AsInteger. 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. "XC"}. Validación a nivel de campos. "DCC". "III". static AnsiString Centenas[10] = {"". static AnsiString Decenas[10] = {"". "XX". "VI". "CCC". "M". Al editar valores. if (Sender->AsInteger > 3999) { Text = "Infinitum".. "MM".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. "VII". "XXX". "MMM"}. "X". "DC". "CD". "D".

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

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]

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

db (en formato Paradox). consultar y ordenar tablas almacenadas en distintos formatos (como Paradox o dBase). visualizar.DB con los siguientes campos: q q q q q NOMBRE (alpha.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. file:///D|/Manuales/databases/examples/agenda. C++Builder y JBuilder) que permite crear. 64 caracteres) EMAIL (alpha. 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. Creación de tablas Crear una tabla Paradox llamada AGENDA. Visualización de tablas Visualizar el contenido de las tablas BCDEMOS:holdings.html (1 of 3) [27/02/2003 16:24:30] .dbf (en formato dBase) y BCDEMOS:vendors.

Para introducir fotos en nuestra base de datos podemos utilizar el componente file:///D|/Manuales/databases/examples/agenda. 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). En la propiedad DataSource de todos los componentes data-aware seleccionaremos dmAgenda->dsAgenda.cpp del formulario. Para que los componentes del módulo de datos sean visibles desde el formulario hemos de añadir el #include correspondiente en el fichero . 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). Con el "Fields Editor" del menú contextual de TableAgenda creamos los cinco componentes TField correspondientes a las cinco columnas de nuestra tabla. 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. así como la propiedad DataSet del TDataSource. Hemos de llamar al método Open de nuestra tabla cuando se produce el evento OnActivate del formulario. C++Builder Desarrollo de la aplicación Creamos un proyecto llamado Agenda y su formulario principal lo guardamos con el nombre FormAgenda. 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. De la misma forma interceptamos el evento OnDeactivate del formulario e invocamos al método Close de la tabla.html (2 of 3) [27/02/2003 16:24:30] . Añadimos al formulario principal los componentes necesarios para poder manejar nuestra agenda.C++ Builder Creación de alias Creamos un nuevo alias de tipo STANDARD (el usado para tablas Paradox y dBase) y lo denominamos AGENDA.DB.

También podríamos permitir la impresión de fichas con los datos de nuestra tabla. Así mismo. Finalmente.html (3 of 3) [27/02/2003 16:24:30] . NOTA: El conjunto de datos debe estar en modo edición para poder establecer el valor de la imagen. los cuales devolverán un valor booleano según la búsqueda se haya realizado con éxito o no. podríamos distribuirla generando un programa de instalación con.. Para ello. 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. Para ello tendríamos que utilizar un TQuickReport o acceder directamente al canvas de la impresora (TPrinter). podemos traducir las pistas asociadas a los distintos botones del TDBNavigator (propiedad Hints) y permitir su visualización (ShowHints). deberíamos tratar mejor la introducción de fechas (para lo cual lo ideal es crear un componente derivado de TDateTimePicker). También podemos utilizar el portapapeles de Windows para poner la imagen. por ejemplo. © Fernando Berzal Galiano file:///D|/Manuales/databases/examples/agenda. un botón que lo llame y el método LoadFromFile de TGraphicField. Así mismo. Para evitar que los mensajes asociados al TDBNavigator aparezcan en inglés debemos interceptar el evento BeforeAction de este componente. una vez que tengamos nuestra aplicación terminada. el InstallShield Express for C++Builder. 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. findNext y findPrior). 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.C++ Builder OpenPictureDialog..

los estándares SQL-86 y SQL-89 no eran adecuados para aplicaciones reales y en 1992 apareció el SQL-92 (ANSI X3. fecha.). En 1978. que fue añadida en el SQL-89. el estándar actualmente utilizado por la mayor parte de las bases de datos. 1974. 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). en cooperación con el grupo correspondiente de ISO. Codd ("A relational model of data for large shared data banks". Los orígenes de SQL se remontan a 1974. pp. y SQL utiliza 'null' para representar este hecho.. que después se convertiría en SQL ("SEQUEL: A structured English query language". pp. ACM. aún está por conseguir su estandarización de hecho. 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. cuando Chamberlin y Boyce publicaron el primer artículo de SEQUEL. El SQL-86 no incluía la integridad referencial. el SQL3. 249–264). cadena..html (1 of 13) [27/02/2003 16:24:31] . 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. Proceedings of the ACM SIGFIDET Workshop.) y su violación produce excepciones que bloquean la ejecución de las sentencias que las ocasionan.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. 13:6. No obstante. Las restricciones de integridad se utilizan para forzar el cumplimiento de determinadas condiciones ('business rules'. que estaba basado en un trabajo de E..F.. desarrolló la primera especificación de SQL en 1986.135-1992. Visión general El concepto fundamental de SQL es el de tabla. 377–387). May 1974. Commun. Algunos de los datos pueden ser desconocidos o inaplicables. con una o más columnas que tienen un nombre y un tipo (numérico. DML: Lenguaje de manipulación de datos SELECT SELECT [DISTINCT] lista-select | * file:///D|/Manuales/databases/sql. ISO/IEC 9075:1992). integridad referencial. Una cuarta generación de SQL. Los datos se almacenan como filas en las tablas (tuplas).

La claúsula WHERE.'BARCELONA'. Ejemplo: Seleccionar aquellos vuelos que tengan como origen Madrid. DISTINCT. Si existe una claúsula HAVING. 4.html (2 of 13) [27/02/2003 16:24:31] . se devuelve su producto cartesiano. 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. Recuperar todas las filas de la(s) tabla(s) especificada en FROM. La claúsula ORDER BY sirve para ordenar los valores devueltos por una consulta. 3. Cuando se indica más de una. 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. tabla . si existe. SELECT * FROM VUELOS WHERE ORIGEN IN ('MADRID'. . elimina duplicados. 5. 2. los grupos resultantes de GROUP BY que no satisfagan la condición se eliminan. cuando aparece. La claúsula GROUP BY. 6. agrupa las tuplas que tienen los mismos valores en todas las columnas especificadas. La lista de columnas separadas por comas que aparece en el SELECT determina las columnas que se devuelven (* devuelve todas). 7. elimina las tuplas que no satisfacen la condición. .C++ Builder FROM tabla. Barcelona o Sevilla.'SEVILLA') o también SELECT * file:///D|/Manuales/databases/sql. cuando está presente.

Bajo estas condiciones. recupérense todos los vuelos que no pertenecen a IBERIA.00.00' equivale a SELECT * FROM VUELOS WHERE HORA_SALIDA >= '06.00.html (3 of 13) [27/02/2003 16:24:31] .00.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' Ejemplo: La columna NUM_VUELO representa los vuelos con 6 caracteres.00. file:///D|/Manuales/databases/sql. Los dos primeros caracteres indican la compañía a la que pertenece cada vuelo (vgt: IB Iberia.00' AND '12. SELECT * FROM VUELOS WHERE NUM_VUELO NOT BETWEEN 'IB0000' AND 'IB9999' Claúsula LIKE Sirve para especificar. 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). SELECT * FROM VUELOS WHERE DESTINO NOT IN ('LONDRES'. con la ayuda de metasímbolos (comodines). BA British Airways) y los cuatro siguientes corresponden al número de vuelo.'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' AND HORA_SALIDA <= '12.

ENVERGADURA*3. SELECT LONGITUD*3. 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. una columna. 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). file:///D|/Manuales/databases/sql.COUNT) a una expresión aritmética en la cual debe participar.C++ Builder Ejemplo: Recuperar todos los vuelos de Iberia. VELOCIDAD_CRUCERO/1. al menos.28. Ejemplo: Número de vuelos incluidos en nuestra base de datos. Su resultado es un único valor.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. COUNT(*) cuenta el número de filas de una tabla.28. q q f(expresión) aplica una función (MIN.AVG. SELECT COUNT(*) FROM VUELOS Claúsula GROUP BY-HAVING Sirve para dividir una tabla en grupos de filas que comparten características comunes.MAX. Pueden especificarse detrás de SELECT o en la claúsula HAVING (nunca dentro de WHERE).SUM.html (4 of 13) [27/02/2003 16:24:31] .

SELECT NUM_VUELO. 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. Ejemplo: Visualizar los destinos que tengan más de dos vuelos. MIN(HORA_SALIDA). SELECT DESTINO FROM VUELOS GROUP BY DESTINO HAVING COUNT(*) > 2 Ejemplo: Visualizar los vuelos de Iberia que tengan plazas libres. GROUP BY agrupa todos los valores nulos en un único grupo. 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. Es decir. La claúsula HAVING permite elegir aquellos grupos que se quieren visualizar y no interfiere en la agrupación realizada por GROUP BY. sino indeterminados. AVG(x) no siempre será igual a SUM(x)/COUNT(*). 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). Las funciones de agregación ignoran los campos nulos.C++ Builder Ejemplo: Primera salida y número de vuelos diarios para cada destino SELECT DESTINO. exceptuando la función COUNT. mientras que colA<>colB será cierta si sólo una de las dos columnas es nula (será falsa cuando ambas sean nulas). No se puede poner en GROUP BY una columnaque no se haya incluido en la sentencia SELECT. Dos valores nulos no son iguales ni son distintos. Dependiendo del sistema gestor de bases de datos.html (5 of 13) [27/02/2003 16:24:31] . DISTINCT no elimina los valores nulos repetidos. La expresión booleana colA=colB es falsa en cuanto colA o colB sean nulos. file:///D|/Manuales/databases/sql. los valores nulos son mayores o menores que cualquier otro valor cuando se devuelve un conjunto de datos ordenado.

FROM . SELECT * FROM RESERVAS WHERE FECHA_SALIDA='20.. WHERE columna concatenador (SELECT .02. 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.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 .. Ejemplo: Plazas libres que hay en cada vuelo MADRID-LONDRES del día 20/02/2001.. 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 . file:///D|/Manuales/databases/sql.<>... WHERE columna operador {ANY/ALL} (subconsulta) Nota: =ANY equivale a IN.>. la subconsulta ha de devolver un único valor.<=.html (6 of 13) [27/02/2003 16:24:31] ..=... En el primer caso.. FROM .>=) o la claúsula IN..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 (<.

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

Una claúsula opcional WHERE selecciona los datos que han de modificarse.. finalmente.. DDL: Lenguaje de definición de datos El sublenguaje de definición de datos de SQL se utiliza para crear. las claves primarias (PRIMARY KEY) aseguran que los valores de las columnas especificadas son únicos y no nulos. [WHERE condición] La sentencia UPDATE sirve para actualizar datos. triggers. Cuando esta claúsula se omite. modificar y eliminar tablas. no está estandarizado suficientemente por el momento y muchos detalles dependen de la base de datos que utilicemos. vistas.C++ Builder INSERT INTO tabla SELECT . 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. UNIQUE prohíbe que existan valores duplicados en una columna y CHECK restringe los valores que puede tomar una columna. las claves externas (REFERENCES) sirven para especificar restricciones de integridad referencial (esto es. incluye una claúsula WHERE opcional. etcétera.html (8 of 13) [27/02/2003 16:24:31] . También se pueden definir restricciones a nivel de tabla: CHECK puede involucrar a varias columnas. DELETE DELETE FROM tabla [WHERE condición] DELETE permite eliminar tuplas. Los tipos de datos permitidos para las columnas de las tablas varían según el servidor que utilicemos. se modifican todas las tuplas de la tabla.. 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). Igual que UPDATE. UPDATE UPDATE tabla SET columna=valor. 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. procedimientos almacenados. ALTER TABLE para modificarlas y DROP TABLE para eliminarlas.

dbclob timestamp numeric(p. si queremos obtener la hora actual utilizaremos la palabra reservada "Now" en InterBase. 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 . 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='.. "sysdate" en Oracle o la función "getdate()" en SQL Server.. long [raw] number(p.d) date rowid.. clob.incremento) file:///D|/Manuales/databases/sql.' q Uso con gen_id (id..html (9 of 13) [27/02/2003 16:24:31] .clob.s) blob... Por ejemplo. datetime Las mayores diferencias suelen aparecer al manejar fechas. Definición de dominios con create domain (*) create type .d])] decimal[(p[.s) time blob.d) blob decimal(p. date [var]binary[(n)] numeric[(p[..NextVal q Nombre InterBase Oracle SQL Server Identidades Definición de columnas con el atributo identity (valor_inicial.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. text..CurrVal & id..d])] money. incremento) q Definición: create_sequence id increment by valor start with valor Secuencias q Uso: id. image..

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

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 .. max... min..html (11 of 13) [27/02/2003 16:24:31] . sum. Consultas Valores nulos: is [not] null Sinónimos para las columnas: . trim.. on . as .... alter index . avg Subconsultas: in... end Declaración de variables declare variable id tipo file:///D|/Manuales/databases/sql.... exists Cadenas Operador like (comodines % y _) Concatenación: || Funciones: upper. lower. Funciones de agregación: count.. (active|inactive) set statistics index .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 .

.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)].C++ Builder NB: Al usarse.. 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.html (12 of 13) [27/02/2003 16:24:31] . 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.

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.html (13 of 13) [27/02/2003 16:24:31] .

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

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. Dobb's Journal q Productos relacionados r r Delphi InterBase q Programación r r r ACCU (Association of C & C++ Users) Mathtools.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] .

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

5.1. Sobrecarga de funciones. Abstracción.1. Restricciones al uso de la VCL en C++ Builder. Herencia Múltiple. 5. Encapsulamiento. 5. Herencia de Constructores y Destructores (Inicialización de Clases II).1.6.3. Controles de edición y Editor.5.Índice 4.3.. 4.5. 5.2. 5.6.2. Polimorfismo. file:///D|/Manuales/toc.2.1. Programación Orientada a Objetos en C++ 5. 4.4. 5. 5.1. 5. 5. 4. 5. Herencia. Creación y Destrucción de Objetos.6.7. 4.5. Clases Abstractas.5. 5. Restricciones de acceso en C++. Constructores y Destructores (Inicialización de Clases I). El Paradigma de la POO en C++.2.5. Propiedades Virtuales.4. 5.7.C++ Builder . Un paseo por la VCL. Clases de componentes.html (2 of 5) [27/02/2003 16:24:32] .3. Clases de formularios y aplicaciones. Ejercicios: Pizarra. 5.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Instanciacion del metodo virtual puro de // la clase TObjGraf __property int Radio = }.4 E \ \ 5 SE .} //*************************************************/ // Definicion de la clase derivada TPelota. 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. // Otros metodos void Mostrar (void). int _Radio=1). int _X=0.} (void) {return(FRadio*2). write=FRadio}. (void) {return(FRadio*2). {read=FRadio.html (5 of 10) [27/02/2003 16:24:34] N 2 | | | | 1 S NE 6 / / ---. // Deriva de la clase base TObjGraf //*************************************************/ class TCirculo : public TObjGraf { private: int FRadio. //*************************************************/ // Definicion de la clase derivada TCirculo.Ejemplo 2 }. int _Y=0. // TPelota deriva de la clase TCirculo.OOP . TColor _Color=clBlack. inline int GetAncho inline int GetAlto public: // Constructores TCirculo (TPaintBox *_PaintBox.

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

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

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

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

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

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

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

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

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

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

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

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

-c -b.$(BCB)\lib.lib cp32mti.$(USERDEFINES) IDLCFLAGS = -I$(BCB)\include -I$(BCB)\include\vcl -src_suffixcpp PFLAGS = -U$(BCB)\lib\obj.NO_STRICT.USEPACKAGES # -------------------------------------------------------------------------CFLAG1 = -I$(BCB)\include.Lib $(PACKAGES) sysinit. PATHASM = .$(BCB)\lib.obj $(OBJFILES) ALLRES = $(RESFILES) ALLLIB = $(LIBFILES) $(LIBRARIES) import32.0.0 InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion=1.obj Memmgr.Estructura y configuración de un proyecto de C++ Builder: INICIAL.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.\ -a8 -k -y -v -vi..-w-par -w-inl -Vx -tW -tWM \ -D$(SYSDEFINES).$(RELEASELIBPATH) -aa -Tpe -x -Gn -v # -------------------------------------------------------------------------ALLOBJ = c0w32. DEBUGLIBPATH = $(BCB)\lib\debug RELEASELIBPATH = $(BCB)\lib\release USERDEFINES = SYSDEFINES = _RTLDLL.0.csm -w -Ve -r.$(RELEASELIBPATH) \ -I$(BCB)\include. PATHRC = .-v -JPHNE -M RFLAGS = -i$(BCB)\include.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.BPR PATHPAS = ..$(BCB)\include\vcl AFLAGS = /i$(BCB)\include /i$(BCB)\include\vcl /mx /w2 /zd LFLAGS = -L$(BCB)\lib\obj..$(BCB)\include\vcl -$YD -$W -$O.0.0.

$(BCB)\include\vcl [HistoryLists\hlLibraryPath] Count=1 Item0=$(BCB)\lib\obj.html (3 of 5) [27/02/2003 16:24:35] .Estructura y configuración de un proyecto de C++ Builder: INICIAL.BPR Comments= [HistoryLists\hlIncludePath] Count=1 Item0=$(BCB)\include.autodepend # -------------------------------------------------------------------------!if !$d(BCC32) BCC32 = bcc32 !endif !if !$d(CPP32) CPP32 = cpp32 !endif file:///D|/Manuales/appendix/project/inicial_bpr. It is for # the benefit of building from the command-line using the MAKE utility. # -------------------------------------------------------------------------.$(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.

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

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

Sign up to vote on this title
UsefulNot useful