Sei sulla pagina 1di 133

Plataformas/C++

Realizado por: Ing. Jubert Pérez


Índice
Plataformas operativas......................................................................................... 4
Comunicaciones................................................................................................... 6
Especificaciones de COM................................................................................... 9
Introducción a C++.............................................................................................. 11
El C++ Builder de Borland.................................................................................. 23
Aquí comienza el swing....................................................................................... 24
Ejemplo 1............................................................................................................. 29
Ejemplo 1............................................................................................................. 30
Ejemplo 1............................................................................................................. 31
Ejemplo 1............................................................................................................. 36
Ejemplo 1............................................................................................................. 49
Ejemplo 1............................................................................................................. 51
Ejemplo 1............................................................................................................. 62
Ejemplo 1............................................................................................................. 75
Ejemplo 1............................................................................................................. 78
Ejemplo 1............................................................................................................. 80
Ejemplo 1............................................................................................................. 85
Ejemplo 1............................................................................................................. 91
Ejemplo 1............................................................................................................. 95
Ejemplo 1............................................................................................................. 96
Ejemplo 1............................................................................................................. 99
Anexos................................................................................................................. 104
Manual de Quick Report 3.................................................................................. 105
Extracto
Este taller está orientado a mostrar algunas de las diferentes plataformas existentes
para el desempeño de sistemas de computación, haciendo énfasis en la plataforma
Windows, plataforma que actualmente maneja la empresa. Basado en la plataforma
Windows se presentará el entorno de C++, como herramienta de desarrollo para software
intermedio que soporte las transacciones entre sistemas.
Plataformas operativas:

Existen muchas plataformas operativas orientadas a red, entre ellas podemos


mencionar, Unix, Windows, Novell, etc. En la actualidad los OS están orientados a red, las
diferencias entre los mismos radican en su concepción y forma de trabajo, aunque
aparentemente realizan las mismas funciones.

Si nos centramos en la plataforma windows, podemos notar que es un sistema


operativo distribuido, donde los servicios que el mismo presta no necesariamente se
centralizan, sino que se distribuyen a lo largo de la red. Esta característica brinda la
posibilidad de un crecimiento a gran escala sin la necesidad de redimensionar las
características del hardware que se posee, sin embargo entre las diferentes versiones del
sistema operativo los requerimientos de hardware van en crecimiento, esto en gran parte se
puede atribuir al hecho de que la tecnología de hardware evoluciona y por lo tanto el
software debe aprovechar esa Servidor
evolución y adaptarse. Servicios de
red
central
Funcionalidad:

Usuarios

FIG. 1.

En la actualidad los servicios de los OS están distribuidos en lo que se conoce como


servidores, estos últimos alojan los programas que brindan el servicio, estos servicios se
catalogan según su funcionalidad.

El manejo distribuido facilita muchos aspectos técnicos, mas involucra otros que
deben resolverse de la mejor forma, sin afectar la funcionalidad del sistema, por ejemplo,
para el manejo del tiempo distribuido, los sistemas operativos manejan técnicas como la
sincronización periódica de los relojes de cada máquina, o la introducción de componentes
de imprecisión para compensar las desigualdades.

En cuanto a la seguridad distribuida, la técnica utilizada actualmente es distribuir la


seguridad, esto se hace ya que no existe un único ente centralizado para este tipo de
sistemas, por lo que no cabe la posibilidad de aplicar la seguridad en un solo punto. Para
gozar de un acceso a un sistema único, el usuario tiene la facilidad de acceder a todos los
recursos de forma transparente.

BDC
PDC

WINS
DHCP
Segmento de
RED

FIG. 2.

Comunicaciones:
Este aspecto es muy importante, ya que dependiendo del enfoque puede ser tan
amplio como se desee, ahora bien nuestro enfoque será dirigido hacia las capas de software
que permiten comunicación entre aplicaciones.

Básicamente, la comunicación se basa en un protocolo, actualmente se maneja el


protocolo TCP/IP como el protocolo estándar más utilizado a nivel de OS. Bajo esta
premisa nacen una serie de mecanismos de comunicación a nivel de sistemas C/S, entre los
cuales podemos mencionar los Sockets, los cuales aparecieron en 1981 como la interfaz
genérica de Unix BSD 4.2. En 1985 el OS de SUN introdujo NFS y RPC sobre sockets. En
1986, AT&T lanzó la interfaz de capa de transporte (TLI : Transport Layer Interface), con
funcionalidad similar a la de los Sockets pero con mayor independencia de la red. Unís
SVR4 integra tanto Sockets como TLI. Los Sockets son por ahora mucho más prevalentes
que los TLI.

Prácticamente todos los sistemas operativos soportan Sockets. Windows no es la


excepción, para ello maneja lo que se conoce como WinSock, que es la interfaz de Sockets
de Berkeley.

Capas de software y la comunicación:

Este aspecto es de mucha importancia para el desarrollador, ya que es la manera de


cómo el sistema operativo permite la comunicación y transferencia de información entre
aplicaciones. Para iniciarnos en este punto hablemos primero de lo que son los objetos y
componentes distribuidos.

Los Objetos son por si mismos una impresionante combinación de datos y


funciones, con características muy propias que obran maravillas en entornos distribuidos.

Gracias a los Objetos nace lo que se conoce como ORB (Object Request Broker),
muy bien conocida como la capa de administración de los objetos, permite administrar el
acceso a los objetos, así como brindar el mecanismo de transferencia de información entre
el ente externo y el objeto. La tecnología de objetos distribuidos es extremadamente apta
para la creación de sistemas flexibles de C/S, porque los datos y lógica se encapsulan
dentro de los objetos, permitiéndoles así ubicarse en cualquier punto dentro de un sistema
distribuido. Los objetos distribuidos poseen el inherente potencial para permitir que
componentes granulares de software sean conectados y usados (plug-and-play), interoperen
entre redes, corran en diferentes plataformas, coexistan con aplicaciones de herencia a
través de envolturas de objetos, merodeen en redes y se administren solos, lo mismo que los
recursos que controlan. Esta tecnología cuenta con la capacidad para revolucionar la
computación de C/S porque facilita a programadores, usuarios y administradores de
sistemas el desarrollo, uso y administración de software.

Existe una diferencia notable entre un objeto clásico, de C++ por ejemplo, y un
objeto distribuido, el objeto clásico es un glóbulo inteligente que encapsula código y datos,
proporcionan magníficas facilidades de reutilización de código por medio de herencia y
encapsulado, sin embargo viven en un solo programa. Por el contrario, un objeto distribuido
es un glóbulo inteligente capaz de vivir en cualquier punto de una red, estos se empaquetan
como piezas de código independiente a las que puedan acceder clientes remotos mediante
invocaciones de métodos. El lenguajes y compilador usado para el desarrollo objetos
distribuidos es totalmente transparente para el cliente.

Los objetos distribuidos son piezas inteligentes de software capaces de comunicarse


transparentemente entre sí desde cualquier lugar del mundo. Pueden interrogarse unos a
otros, vienen, van y se desplazan.

Cuando se habla de objetos distribuidos se habla específicamente de componentes


de software independientes. Un componente es un objeto no atado a ningún programa,
lenguaje de cómputo o implementación en particular. Los componentes son las formas
indicadas para aplicaciones distribuidas.

El nacimiento de los Broker, originado de los objetos distribuidos, es la


infraestructura de componentes que permite que los objetos interoperen entre espacios de
direccionamiento, lenguajes, sistemas operativos y redes. El nombre comúnmente utilizado
para este nivel es el ORB (Object Request Broker), en español, el corredor de solicitudes de
objetos. Todo este mundo de tecnología conlleva al origen de lo que hoy día conocemos
como ambientes multi nivel, o multi capas, filosofía que muchos adoptan hoy día para
estructurar su plataforma de software en general.

FIG. 3.

Bajo la arquitectura multi nivel, se manejan, según el proveedor, diferentes tipos de


ORB, en nuestro caso, Windows, su ORB a evolucionado hasta la actual versión en
Windows 2000, inicialmente Windows ofreció al público su plataforma COM (Component
Object Model), posteriormente a partir de la versión 98 y NT 4.0 actualiza a lo que se
llamó DCOM (Distributed Component Object Model) y actualmente ofrece COM+ con
Windows 2000. Este es el mecanismo que utiliza Windows para la administración de
componentes y manejo de comunicación entre sistemas. Como referencia a otros entornos
mencionaremos CORBA (Common Object Request Broker Architecture), que ha sido el
proyecto de Middleware más importante (y ambicioso) que haya sido emprendido jamás en
la industria. Es resultado de un consorcio llamado Object Management Group, integrado
por más de 650 compañías en representación de la totalidad del espectro de la industria de
computación. La excepción notable es Microsoft.

CORBA especifica interfaces no código, escritas en un lenguaje de definición de


interfaces neutral (IDL: Interface Definition Language), el cual define las fronteras de un
componente, es decir, sus interfaces contractuales con clientes potenciales. Los
componentes generados para IDL deberán ser exportables entre lenguajes, herramientas,
sistemas operativos y redes. Además, con la adopción de la especificación CORBA 2.0 en
diciembre de1994, estos componentes deberán ser capaces de interoperar entre corredores
de objetos CORBA de proveedores múltiples.

Objetos

Contenedor de Objetos Clientes

Corredor de solicitudes de Objetos

FIG. 4.

Especificaciones de COM:

Los objetos COM presentan características muy particulares, la solicitud se realiza a


través de llamadas a métodos de Objetos, las especificaciones de la llamada se envía como
parámetros y la respuesta a la solicitudad retorna en forma de parámetro.
Las formas de un Objeto COM depende del tipo de transacción que se realizará en
el servicio, así por ejemplo se pueden implementar diferentes tipos de servidores tales
como:

1. Servidores de automatización
2. Aplicaciones de servicio WEB
3. Servidores de Objetos COM (in proccess)
4. Servidores de Controles ActiveX
5. Servidores de Objetos MTS

Los Objetos COM se presentan en 2 formas:

1. In Process
2. Out Process

La primera representa al tipo de objetos que se encuentra inmerso en el proceso, en


tal caso, los servidores COM en proceso son DLL que pueden crear objetos para que los
utilice la aplicación host, esta DLL reside en el mismo proceso que la aplicación que lo
llama.

Los Objetos COM fuera de proceso, son ejecutables que pueden crear objetos COM
para que los utilicen otras aplicaciones, estos no se ejecutan dentro del mismo proceso del
cliente, sino que son ejecutables que operan dentro del contexto de sus propios procesos.

Independientemente del tipo de objeto a crear, es necesario registrar el objeto en el


sistema operativo, esto se puede realizar de diferentes maneras, en el caso de los objetos
COM en proceso, se puede utilizar el utilitario del sistema operativo “regsrv32.exe”, así la
sintaxis sería regsrv32 <nombre de la DLL>, una vez registrada, podrá a través del
lenguaje de desarrollo instalarla como componente o como librería, y así utilizarla en la
aplicación. Un objeto COM en proceso es más versátil en aplicaciones WEB Enabled, ya
que no se requiere registrar el componente en el cliente, esto es porque en el servidor es
donde reside la aplicación que maneja el proceso, y es la aplicación quien invoca al objeto,
en el caso que una aplicación cliente requiera invocar un método de un objeto COM en el
servidor, es necesario que la aplicación se compile con la versión del componente activa,
esto genera la dependencia de la aplicación con la versión del componente.

Los Objetos COM fuero de proceso, por el contrario, no generan dependencia de la


versión del objeto, esto es, se pueden añadir métodos al objeto, sin necesidad de recompilar
la aplicación cliente. Este tipo de objeto se hace más versátil cuando las aplicaciones
necesitan simplemente ser servidas de un proceso sin formar parte de él. Este tipo de
objetos es el utilizado para crear servidores de automatización, los cuales poseen una
funcionalidad definida, la cual comparten a través de las interfaces que define el objeto.

1. Servidores de automatización: Utilizados para la automatización de


procesos, son objetos COM fuera de proceso, así por ejemplo tenemos los
servidores del Office.
2. Aplicaciones de servicio WEB: Son archivos ejecutables (CGI) o DLL que
se ejecutan en el servidor por llamadas desde el cliente para servir procesos
como: Manejo de Datos, Cálculos, Conexiones, etc. Presentan la
característica de poder realizar transferencia de información desde la página
activa hasta el servicio y viceversa.

3. Servidores de Objetos COM (in proccess): Son Objetos de propósito


general, sirven al cliente y pueden ser utilizados para servir llamadas desde
páginas ASP, JSP, etc.

4. Servidores de Controles ActiveX: Son servidores de automatización


utilizados para servir procesos basados en controles ActiveX.

5. Servidores de Objetos MTS: Son servidores de automatización utilizados


para el manejo de transacciones basados en procesos MTS (Microsoft
Transaction Server). Estos objetos pueden registrarse en el MTS de
Microsoft y permiten ser administrados por el mismo.

¿Cómo implementar estos objetos?, muchos de los lenguajes de última tecnología


permiten el desarrollo de este tipo de objetos, Visual Basic, Visual C++, Delphi, Power
Builder, C++ Builder, son algunas de las plataformas de desarrollo que permiten el manejo
de la tecnología COM de Windows.

¿Qué usaremos para manejar esta plataforma?. Tomando en cuenta los lineamientos
de la empresa en cuanto a la estandarización de lenguajes de desarrollo, así como el
resultado de las evaluaciones de herramientas de desarrollo, nos apegaremos para esto a C+
+, con la versión C++ Builder de Borland INC.

Para iniciar esta aventura es necesario que se realice una revisión del lenguaje, esto
con la finalidad de nivelar las diferencias que puedan existir en el grupo. Si el nivel de C++
es bueno, esta parte se puede obviar.

Para más información sobre COM, se puede consultar la página


www.codeproject.com/com. En esta página podrás obtener tutoriales e información sobre la
tecnología COM de Windows.

Introducción a C++:

Estructura de un programa en C++:

# include <librería.h>
.
.
.
<definición de estructuras / variables globales>

void mi_funcion(void)
{
.
.
.

.
.
.

void main(void)
{
.
.
.
mi_funcion();
}

La estructura es sumamente sencilla, se tiene la sección de cabecera donde se


especifican las librerías a importar, se declaran las variables y las estructuras de datos,
luego en la sección de código se definen las funciones y por último la función main(), que
es la principal, es la que se ejecuta al correr el programa.

Tipos de datos:

C++ maneja los siguientes tipos de datos:

TIPO RANGO OCUPACION


Char -128 a 127 8 bits
Unsigned char 0 a 255 8 bits
int -2147483648 a 2147483647 32 bits
Unsigned int 0 a 4294967295 32 bits
long Igual a int 32 bits
Unsigned long Igual a unsigned integer 32 bits
float 3.4 * 10E-38 a 4.4*10E+38 32 bits
double 1.7*10E-308 a 1.7*10E+308 64 bits
Long double 3.4*10E-4932 a 1.1*10E+4932 80
bool 0 ó 1 – false o true 8 bits
Declaración de Variables:

La sintaxis es la siguiente:

Int i //se declara a i como integer;


Int i=0 //se declara a i como integer y se la asigna el valor de cero;
char * c //se declara un apuntador a char
int Dias[12][31] //declaración de un arreglo bidimensional tipo integer;
char x[] = {‘A’,’B’} //matriz con 2 caracteres;
const seg = 3600 //constante sin tipo;

Estructuras:

Permiten manejar declaraciones de variables de diferentes tipos agrupadas en una


estructura única para ser accesadas a través de una variable del tipo de la estructura creada.

Ej.:

Struct ficha
{
string nombre;
int edad;
} Fich;

Aquí se declara la estructura ficha la cual posee dos campos, nombre del tipo string
y edad del tipo integer. Seguido a la definición de la estructura se define la variable fich que
hace referencia a la estructura creada.

Así podemos acceder los campos de la siguiente forma:

Fich.nombre = ”juan”;
Fich.edad = 24 ;
Int j = Fich.edad ;

Estructuras de Lazo :

La sentencia FOR :
Sintáxis :

for (i = 1 ; i<100 ; i++)


{
//Bloque de instrucciones
}

La sentencia WHILE :
Sintáxis :

While(num<=10)
{
// Bloque de instrucciones
}

Variante con DO :

Sintáxis :

do
{
// Bloque de instrucciones
}while(expresión)

La diferencia estriba en el hecho de que la primera forma evalúa primero y después


ejecuta, en la segunda se ejecuta y se evalúa después.

La sentencia break :

Es utilizada para salir de un bucle desde cualquier punto.

Ej. :

int i ;
for (i=1 ;i<100 ; i++)
{
cout << i << ’’ ‘’ ;
if (i==10) break //salir del bucle
}

Cadenas :

Es el uso más común del array de una dimensión de C++. El lenguaje no tiene un
tipo definido para las cadenas, en su lugar C++ define las cadenas utilizando un arreglo de
caracteres de una dimensión.

Ej. :

char str[10] ;
int i ;
cout << ‘’introducir cadena :’’ ;
cin >> str ;
for (i=0 ; i<80 ; i++) cout << str[i] << ‘’ ‘’;
Para el tratamiento de cadenas existe unidades stándar de C++ llamadas ‘’string’’,
‘’ctype’’, las cuales poseen una gran cantidad de funciones, algunas de estas son :

• gets() //Captura de cadenas suprimiendo espacios en blanco


• strcpy() //copia de cadenas
• strcat() //concatena cadenas
• strcmp() //compara cadenas
• strlen() //obtiene la longitud de la cadena

Intrucciones condicionales :

La sentencia if :

sintáxis :

if(expresión) then
{
//sentencias
}
else
{
//sentencias
}

La sentencia switch :

sintáxis :

switch(variable)
{
case (valor) : { sentencias ; break }
.
.
.
else { sentencias }
}
Del ‘’if’’ no se tiene mucho que decir, pues es la forma tradicional de como los
lenguajes manejan esta instrucción, mas el ‘’switch’’ es más variada, ya que permite
selección múltiple, nótese que el break permite que no se ejecuten los sub siguientes case,
así sólo un case se ejecutará. por otro lado el else permite la opción de ejecutar un código
en caso de no se cumpla ninguno de los case anteriores.

Punteros :
Los punteros son parte de la fuerza que le da a C++ el poder que manifiesta en las
aplicaciones. Básicamente un puntero es una variable que almacena la dirección de
memoria de otro objeto.

La declaración es como sigue :

tipo *nombre-variable ;

Ej. : int * p ;

Uso de punteros : Veamos algunos ejemplos para ilustrar el uso de este tipo de variable :

main()
{
int *p, q ;
p = &q ; //obtener la dirección de q ;
*p = 199 ; //asignar a q un valor usando un puntero ;
cout << ‘’el valor de q es :’’<<q ;
}

recuerde que un apuntador necesita apuntar a algo antes de asignarle un valor, esto es un
error típico, por ejemplo :

{
int *p ;
*p = 10 ; //error p no apunta a nada ;
}

cuando un apuntador no es inicializado apunta a null, esto también puede hacerse por
código :

Ej. :

p = NULL;

este convenio de puntero nulo, es muy utilizado en C++ como na condición de terminación
de bucles y sentencias if.

El puntero void :

Este puntero puede apuntar a cualquier tipo de objeto, recuerde que la asignación de
un puntero a otro se puede realizar sólo si son compatibles los tipos, no obstante, un
puntero void puede ser asignado a cualquier tipo de puntero sin el uso de una conversión
forzada.

Ej. :
int *p ;
void *v ;
v=p;

El uso más común de void es como tipo de devolución de funciones.

Aritmética de punteros :

Sólo hay cuatro operadores aritméticos que se pueden aplicar a las variables
puntero : (+, ++, -, y --).

Ej. :

p++ //incrementa en uno la dirección a la que apunta p.


p = p + 200 //incrementa en 200 la dirección a la que apunta p.

Punteros y arreglos :

Cuando se usa un arreglo sin índice, está generando un puntero al inicio del arreglo. Así por
ejemplo :

int nums[3] = {1, 2, 3} ;


int *p ;

p = nums ; //ambas líneas hacen lo mismo.


p = &nums[0] ;

Indexación de punteros :

Así como se puede acceder a un arreglo por medio de un puntero, se puede hacer lo
contrario, indexar un puntero como si se tratase de un arreglo.

Ej. :

char str[] ;
char *p ;
int i ;
p = str ;
for( i=0 ; p[i] ; i++ ) // itera mientras no se encuentre nulo.
cout << p[i] ;

Punteros a constantes de cadena :

Este punto es interesante, veamos de que se trata.


Ej. :

char *p ;
p = ‘’constante de cadena’’ ;
cout << p ;

Aquí p es declarado como un puntero a caracter, esto significa que puede apuntar a un
arreglo de caracteres.

Arreglos de punteros :

Es posible declarar punteros como arreglos.

Ej. :

int *p[20] ;

luego, es posible :

p[8] = &q ;

donde q es del tipo int.

Indirección múltiple :

Esto se refiere al hecho de que un puntero pueda apuntar a otro puntero.

Ej. :

char **mp, *p, ch ;


p = &ch ; //obtener la dirección de ch
mp = &p ; //obtener la dirección de p
**mp = ‘A’ ; //asignar ‘A’ usando indirección múltiple.

En el ejemplo anterior, primero se pasa la dirección de ch a p, luego se pasa la


dirección de p, que es la misma de ch, a mp, finalmente se asigna al contenido de mp el
caracter ‘A’, así ch tendrá ‘A’.

Funciones en C++:

En C++ no existen los procedimientos como en Pascal, un procedimiento en C es una


función tipo void.
Ej.:

void MiFuncion(void)
{
//Sentencias;
}

En este ejemplo no se definen parámetros, por lo que se coloca la palabra reservada


void, que indica que no existirá ningún tipo de pase de parámetros. Los parámetros pueden
manejarse de dos formas, por valor o por referencia.

Pase de parámetros por valor: Son en un sólo sentido, es decir, la función no retorna
actualizaciones en los parámetros.

Ej.:
int suma(int i, int j)
{
return(i+j);
}

Pase de parámetros por referencia: La función referencia las variables, lo que permite
retornar valores a través de los parámetros.

Ej:.

void suma(int i, int j, int *k)


{
*k=i+j;
}

Aquí se devuelve por referencia el resultado de la suma. La llamada sería:

int l=10 ;
int m=20 ;
int n ;
suma(l, m, &n) ; //se pasa la referencia de la variable.
cout << n; //se imprime la suma.

Otro forma :

Se define:

void suma(int i, int j, int &k) /se define la referencia del parámetro
{
k=i+j;
}
se referencia:

int l=10 ;
int m=20 ;
int n ;
suma(l, m, n) ;
cout << n; //se imprime la suma.

Punteros a funciones :

Es una característica poderosa de C++, aunque una función no es una variable, siempre
tiene una localización física en memoria que puede ser asignada a un puntero, la dirección
que es asignada al puntero es el punto de entrada a la función. El puntero puede ser usado
en lugar de la función.

Ej.:

#include <iostream.h>
int suma(int a, int b);
void main(void)
{
int (*p) (int a, int b);
int resultado;
p=suma;
resultado = (*p) (10, 20);
cout << resultado;
}

int suma(int a, int b)


{
return(a+b);
}

Archivos en C++

Archivos de Texto:
Ej:

#include <fstream.h>

ofstream es;

main()
{
es.open(“Archivo”,ios::app);
es<<”dato1\n”;
es<<”dato2\n”;
es<<”dato3\n”;
es.close();
return 0;
}

Este ejemplo muestra como se crea un archivo de texto y se introducen líneas al


mismo.

Ej:

#include <fstream.h>
#include <iostream.h>
ofstream es;

main()
{
char cad[200];
ifstream entrada(“archivo”);
if(¡entrada)
{
cout<<”no se puede abrir el archivo”;
}
entrada >>cad
cout<<cad
entrada.close;
return 0;
}

Este ejemplo muestra como se lee el archivo de texto.

El sistema ANSI de E/S:

Consta de varias funciones relacionadas entre sí. En cuanto al manejo de archivos


tenemos:
El puntero de archivo:

EJ:
Apertura de un archivo

FILE *fopen(char *nombrearchivo, char *modo)

Modos:
“r” : Abrir un archivo para leer
“w” : Crear un archivo para escribir
“a” : Añadir a un archivo
“rb” : Abrir un archivo binario para leer
“wb” : Crear un archivo binario para escribir
“ab” : Añadir a un archivo binario
“r+” : Abrir un archivo para lectura / escritura
“r+b” : Abrir un archivo binario para lectura / escritura
“w+b”: Crear un archivo binario para lectura / escritura
“a+b” : Añadir a un archivo binario o crearlo para lectura / escritura
“rt” : Abrir un archivo de texto para lectura
“wt” : Crear un archivo de texto para escritura
“at” : Añadir a un archivo de texto
“r+t” : Abrir un archivo de texto para lectura / escritura
“w+t” : Crear un archivo de texto para lectura / escritura
“a+t” : Añadir a un archivo de texto o crearlo para lectura / escritura

FILE *fp;
if ((fp=fopen(“prueba”,”w”))==NULL)
{
puts(“no puedo abrir el archivo\n”);
exit(1);
}

EJ: Escritura de un carácter:

int putc(int car, FILE *fp);

do
{
car=getchar();
if (EOF==putc(car, fp)
{
printf(“Error de Archivo”);
break;
}
}
Ej: Lectura de un carácter

int getc(FILE *fp);

while(!feof(fp)) car = getc(fp);

Ej: Cierre de un Archivo


int fclose(FILE *fp);

Ej: ferror() y rewind()

int ferror(FILE *fp) //determina si hubo error en la operación


void rewind(FILE *fp);

Ej: fread() y fwrite()

#include <stdio.h>
#include <stdlib.h>

main(void)
{
FILE *fp;
float f=12.23;
if((fp=fopen(“prueba”,”wb”))==NULL)
{
printf(“no puedo abrir el archivo”);
exit(1);
}
if(fwrite(&f, sizeof(float), 1, fp)!=1)
{
printf(“error de archivo”);
}
fclose(fp);
return 0;
}

Ej: fseek()

int fseek(FILE *fp, long num_bytes, int origen);

.
.
.
FILE *fp;
char car;
if((fp=fopen(“prueba”, “rb”))==NULL)
{
printf(“no puedo abrir el archivo”);
exit(1);
}
fseek(fp,234,0);
car = getc(fp); // se lee el carácter de la posición 235
De esta forma le hemos dado un breve paseo al lenguaje, de forma de conocer los
aspectos más usuales del mismo. Se recomienda al participante buscar bibliografía
avanzada sobre el lenguaje ya que los aspectos de profundidad del lenguaje son importantes
y muy útiles a la hora de desarrollar. En este taller no se pretende formar expertos
programadores en C++, ya que esto sólo se puede lograr con la práctica y la investigación.

EL C++ BUILDER de Borland.

Algo de historia: Para la década de los noventa windows dió un vuelco completo a
su producto Windows for work groups, el cual fue creado para trabajar en grupos de
usuarios conectados a un mismo segmento de red, windows 95 fue el bombazo de
Microsoft, Windows NT 4.0 se encontraba dando la talla a nivel de redes corporativas, el
mercado violentamente se nutrió de estos sistemas y hoy en día se considera que un
grandísimo número de usuarios en el mundo se manejan bajo estas plataforma. Como
lenguaje de desarrollo rápido, Microdoft introce Visual Basic, y posteriormente la versión
Visual de C++ denominada Microsoft Visual C++, las cuales tienen un éxito indiscutible,
sin embargo muchos programadores de otros lenguajes se encontraban escépticos ante este
nuevo mecanismo de programación, donde la exigencia al desarrollador era muchísimo
menor que la que exigían los lenguajes tradicionales, sin embargo para el desarrollo de
software intermedio siempre se recurrió a C++, aunque era menos visual que su homólogo
VB, era muchísimo más poderoso, esto por una razón, era C++. Borland dándose cuenta de
la gran demanda de desarrolladores hacia los entornos visuales lanza al mercado la versión
de Delphi 1.0 la cual de frente compite con VB, para conseguir posicionar a Delphi, el cual
posee como lenguaje nativo Pascal, en los primeros lugares, nutre al mismo de un gran
poder basándose en el lenguaje de programación y en la técnica de POO(Programación
Orientada a Objetos), esto colocó a Delphi en una posición muy buena en el mercado. La
estrategia de Borland siempre se basó en la de ofrecer lenguajes de desarrollo completos,
con los cuales se podía realizar cualquier tipo de desarrollo aparte de dotar el IDE de un
toque visual muy parecido al de Microsoft VB, con lo cual le daba un atractivo muy
especial. Hoy en día Delphi está lanzando su versión 6.0 y su versión para Linux (Kylix),
indudablemente herramientas muy atractivas para los desarrolladores de última generación.
Sin embargo, Pascal no es un lenguaje tan portable como C++, y sin pensarlo 2 veces
Borland lanza al mercado su producto visual C++ Builder, manejándose bajo un entorno
visual basando el código en el lenguaje C++. Actualmente conocemos la versión 5.0, sin
embargo Inprise anuncia para este año el destape de la versión 6.0.

Comparativamente, y esto es una apreciación muy personal, me atrevo a manifestar


que la versión de C++ Builder 5.0 de Borland supera a la versión de Visual C++ 6.0 de
Microsoft en cuanto a la forma de como generar las aplicaciones y a la gran cantidad de
componentes pre-construidos que posee lo cual permite un rendimiento extensivamente
grande a la hora de crear código. Borland C++ Builder también es capaz de compilar
fuentes basados en la MFC (Microsoft Fundation Class) de Microsoft Visual C++. Si a esto
añadimos la forma de realizar programación bajo el estándar COM de windows, la
capacidad de realizar programación basada en el WEB, CGI, WINCGI, DLL’s, Consola
Application, Service Application, etc., tenemos pues una herramienta lo suficientemente
poderosa para que el desarrollador realice sus aplicaciones con un mínimo esfuerzo y alto
rendimiento.

AQUI COMIENZA EL SWING:

Entremos en calor, lo primero que veremos será el entorno de desarrollo de C++


Builder:

Menús de Paleta de componentes pre-


Iconos de acceso construidos. cada tag posee
acceso directo un set de componentes.

Forma que
soportará la
programación
visual

Componentes pre-
construidos

Inspector de
Ventana de código Objetos

FIG 5.
Los Iconos de acceso directo manejan las mismas opciones del menú, El inspector
de objetos maneja las propiedades y eventos de cada objeto seleccionado, los componentes
están organizados por funcionalidad y en tag’s, cada tag o pestaña puede poseer varios
componentes. La forma es el panel que soportará los componentes y permitirá la
visualización de los mismo en tiempo de ejecución.

Más detalles del IDE:


El Inspector de Objetos:

Identifica al objeto seleccionado

Pestaña de selección de
eventos del objeto

Pestaña que selecciona las


propiedades del objeto

Definición de la propiedad

Propiedades del objeto

FIG. 6.

Objeto
seleccionado

Eventos del Objeto


Definición del proceso a
ejecutar cuando el evento
ocurre

FIG. 7.

Es a través del inspector de objetos que se definen las propiedades y los eventos del
objeto seleccionado, este elemento realiza las llamadas a la zona de código donde se
escribirá o se escribió la acción solicitada, para bien escribir el código a ejecutar, modificar
o simplemente revisar el mismo.

Veamos ahora el área de menús y componentes:

Menús y Componentes:

Menús de
Pestañas deopciones
componentes
Iconos de acceso
rápido
Selecciona el
Ambiente del
entorno a utilizar

FIG. 8.

Comencemos ahora a realizar una aplicación de consola. Para ello usaremos la siguiente
secuencia para el IDE:

1. New en el menú File:

FIG. 9.
2. Seleccionar
Consola
Aplicación
del diálogo
New Items
FIG. 10.

3. Aceptar las opciones mostradas en el Console Wizard

FIG. 11.

4. El siguiente diálogo se utilizará para escribir el código a ejecutar.

Árbol de
variables y
funciones
Zona para escritura del código.

FIG. 12.

Observe que el Entorno genera un Template (Plantilla), para que se comience a


escribir el código. Tenga presente que las aplicaciones por consola no manejarán una forma
visual de Windows, este tipo de aplicación corre igual que una aplicación de DOS, esto nos
indica que se tendrá que manejar por código el control de las salidas a la pantalla.

Veamos a continuación, algunas aplicaciones que manejan la consola como salida.

EJEMPLO1: (SALIDA POR CONSOLA)

#include <stdio.h>
#include <conio.h>

int main(void)
{
char c;
printf("Hola Mundo..!");
c=getch();
return 0;
}

La salida es como se muestra en la FIG. 13.

FIG. 13.

Este ejemplo muestra el texto “Hola Mundo y espera que se pulse una tecla para
terminar la aplicación.

EJEMPLO 2 (SALIDA POR CONSOLA)

#include <stdio.h>
#include <conio.h>

void main(void)
{
char *c;
char car='A';
c=&car;
printf("resultado:%c",*c);
car=getch();
}
El ejemplo 2 hace uso de un apuntador para transferir y mostrar el contenido, la
salida es como sigue:

FIG. 14.

EJEMPLO 3 (SALIDA POR CONSOLA)

#include <stdio.h>
#include <conio.h>

void main(void)
{
int i;
for (i=1;i<10;i++)
{
printf("salida Nro.%i\n",i);
}
char c;
printf("\n");//salto de línea
printf("pulse una tecla para salir..!");
c=getch();
}

La salida de este programa es como sigue:


FIG. 15.

¿Qué podemos desarrollar con C++ Builder?:

Las siguientes figuras nos ilustran la respuesta:

FIG. 16.
La pestaña New nos muestra:

 Aplicaciones (.EXE)
 Batch File
 Archivos C
 Componentes (Para incrustarlos en la paleta)
 Console Wizard (Aplicaciones de consola)
 Aplicaciones para el control panel
 Módulos para el control panel
 Archivos .cpp
 Módulo de datos (para agrupar componentes de conectividad a las bd)
 DLL Wizard (para hacer DLL´s)
 FORM Crea una nueva forma
 Header file (Archivos de cabecera)
 Library (Archivos .h)
 MFC Wizard (Aplicaciones con la MFC de Microsoft)
 Package (Paquetes de software instalables)
 Project Group (Grupos de proyectos)
 Report (Reportes)
 Resource DLL Wizard (Recursos de DLL)
 Service (Servicios)
 Service Application (Aplicaciones de servicio para el OS
 Text (Archivos de texto)
 Thread Object (Hilos)
 Unit (Unidades tipo pascal)
 Web Server Application (CGI, WCGI, DLL’s de WEB)

FIG. 17.
En la figura 17 se muestra la pestaña Active X, en la cual se manejan:

 Active Forms (Formas Activas para la WEB)


 Active Server Object (Servidor de Objetos ActiveX)
 ActiveX Controls (Controles ActiveX)
 ActiveX Library(Librerías ActiveX)
 Automation Object (Servidores de automatización)
 COM Object (Objetos COM)
 Com+ Event Object (Objetos de eventos COM+)
 Property Page (Páginas de propiedades)
 Transactional Object (Objetos de transacción)
 Type Library (Librerías de tipo)

FIG. 18.

En la figura 17 se muestra la pestaña Multitier, en la cual se manejan:

 CORBA Client (Clientes CORBA)


 CORBA IDL File (Archivos IDL de CORBA)
 CORBA Object Implementation (Objetos de implementación CORBA)
 CORBA Server (Servidor CORBA)
 Remote Data Module (Módulo Remoto de Datos)
 Transactional Data Module (Módulo de Datos Transaccional)

Las subsiguientes figuras 19 – 23, muestran el resto de tipos de desarrollo que se pueden
realizar con C++ Builder:
FIG. 19.

FIG. 20.

FIG. 21
FIG. 22.

FIG. 23.

EJEMPLO 4. aplicaciones ejecutables con BD (*.EXE)

Este tipo de aplicaciones son muy comunes, tienen la característica de residir en el


computador como un archivo ejecutable el cual contiene toda la funcionalidad, por lo que
es necesario ejecutarlo localmente.

Desarrollaremos una aplicación sencilla, la cual consiste en el mantenimiento de una


base de datos local, la cual poseerá la siguiente estructura:

posición Campo Descripción Llave


0 Cedula Cédula de la persona ( Entero de 12 ) primaria
1 Nombre Nombre de la persona ( Alpha de 25 ) no
2 Apellido Apellido de la persona ( Alpha de 25 ) no
Tabla 1.

En primera instancia crearemos la base de datos con el wizard de C++ Data Base Desktop

Siga los siguientes pasos:

1. Cierre todo a través de la opción de menú <File> <Close all> Fig. 24.

FIG. 24.

2. Abra una nueva aplicación a través de la opción de menú <File> <New


Application> Fig. 25.
FIG. 25

En este momento usted tiene una nueva forma disponible para incluirle
componentes y desarrollar su aplicación, tal como se muestra en la figura 26.

FIG. 26

3. Ahora crearemos la base de datos a través de la herramienta dispuesta en C++ Builder,


Data Base Desktop. Par ello siga la secuencia de opción de menú <Tools> <Data Base
Desktop>. Fig. 25.
FIG. 27.
En este momento en su pantalla aparecerá la siguiente pantalla:

FIG. 28.

4.Utilice la siguiente secuencia de opción de menú para entrar al diálogo donde escogerá el
manejador de BD deseado. <File> <New><Table> Fig. 29.
FIG. 30.

En este Momento aparecerá en la pantalla el diálogo para seleccionar el manejador de BD


apropiado, seleccionaremos Paradox7, que se incluye en C++ como manejador de BD
Local, y soporta SQL. El diálogo es mostrado en la Fig. 31. En la Fig. 32 observamos el
despliegue de los manejadores a través del combo box.

FIG. 31.

FIG. 32.

Al pulsar Ok, aparecerá el siguiente diálogo:


FIG. 33.

5. Procedemos entonces a introducir los campos de la tabla mostrados en la Tabla 1.,


tal como se muestra en la figura 34.

FIG. 34.

6. Salve la tabla en el directorio indicado para el ejemplo. Para esto utilice el botón Save ó
Save As y a través del Browser que aparecerá ubique el directorio.

Como se seleccionó Paradox se generarán 2 archivos uno de datos y el otro de


índices, tal como se observa en la figura 35. Cabe notar que dependiendo del manejador
seleccionado, los archivos se generan de forma diferente, para algunos manejadores no se
observarán las tablas físicamente, sino a través de una herramienta de conexión.

Para establecer comunicación con la base de datos es necesario tener un cliente de


conexión, estos clientes son proveídos por los manejadores de bases de datos. Estos clientes
pueden estar orientados a mecanismos de conexión estándar, como ODBC, ADO, OLEDB,
SQLLinks u otro que el mismo manejador provea.

Ahora bien, para conectarnos a la base de datos necesitamos crear un alias que
permita a través de uno de los mecanismos estándar establecer la conexión a la BD. Para
esto utilizaremos la herramienta que provee C++ Builder que entre otras cosas nos permite
generar el alias de conexión a la BD, esta herramienta es “SQLExplorer”.
6. Pulse en el menú la secuencia de opciones <Database> <Explorer> como se muestra
en la figura 35.

FIG. 35.

Inmediatamente aparecerá el siguiente diálogo:


FIG. 36.

7. En el menú Object del Explorer pulse la opción <New>, para crear un nuevo alias.
Aparecerá el diálogo de la Fig. 37.

FIG. 37.

8. Del combo box seleccione la opción “STANDARD” la cual se presenta por defecto,
y pulse OK, esto iniciará la creación del alias.

FIG. 38.
FIG. 39.

9. Renombre el alias generado de “STANDART” a “Pers” FIG. 39.


10. Coloque el ratón en el recuadro que está al lado del PATH, parte derecha del
diálogo y pulse el botón derecho. FIG. 40.

FIG. 40.
11. Utilice el botón que se ubica a la esquina derecha que posee tres puntos y pulse en
él para escribir la ruta física donde se encuentra la base de datos, o escríbala. FIG.
41.

FIG. 41.

12. Ubíquese sobre el alias y pulse botón derecho del ratón luego del POPUP menú
emergente pulse sobre Apply para aplicar los cambios, luego salve aceptando. Ver
FIG 42.

FIG. 42.
13. El siguiente diálogo aparece para aceptar los cambios, pulse Ok.

FIG.43.

Hasta ahora hemos creado la base de datos y el alias de conexión. Ahora viene lo
bueno, crearemos una aplicación visual que interactúe con la BD creada.

Bien, cierre el Data Base Explorer y ubique el ratón en la pestaña Data Access de la
paleta de componentes, tal como se ilustra en la FIG. 44.

FIG. 44.

Para seleccionar un componente, pulse sobre el mismo con el botón derecho del
ratón, y para ubicarlo en la forma, ubique el ratón en la posición deseada y pulse botón
derecho nuevamente, así el componente seleccionado es asignado a la forma.

Bien, ahora siga los siguientes pasos:

1. Seleccione secuencialmente los componentes “DataSource” y “Table” y en la misma


secuencia ubíquelos en la forma, esto se verá como en la FIG. 45.

2. En el Inspector de Objetos Coloque la propiedad DataSet del DataSource en “Table1”, y


al componente Table1 defínale el alias y la tabla en sus propiedades, utilizando el alias y la
tabla creada para el ejemplo, luego coloque la propiedad active a true. Esto se debe ver
como en las FIG. 46 y 47.
FIG. 45.

FIG. 46.
FIG. 47.

3. Desde la pestaña Data control seleccione los componentes DBGrid y DBNavigator,


luego en cada uno de ellos coloque la propiedad DataSource con DataSource1, que
es el componente que anteriormente colocó en la forma, en este momento, si todos
los componentes tienen sus propiedades de conexión bien definidas, es decir, que no
nos hallamos equivocado en ningún paso, se deben poder visualizar los campos de
la tabla en el DBGrid, esto ocurre en tiempo de diseño, interesante. La FIG. 48
muestra como se vería la forma al llegar a este punto.

FIG. 48.

4. Ejecute el programa pulsando con el ratón el botón RUN, tal como lo indica la FIG.
49, o ejecute la opción RUN desde el menú <RUN>. Después de esto note que ya
puede incluir, modificar y eliminar registros en la base de datos de prueba.

Este ejemplo demuestra lo fácil y RAPIDO que se realizan las aplicaciones con C++
Builder. Este ejemplo es una aplicación de 2 capas, modelo tradicional de desarrollo para
aplicaciones con acceso a las BD.

Una de las cosas más interesantes que presenta este entorno es el tener todo en uno,
es decir, no se requiere recurrir a otras herramientas para desarrollar una aplicación
completa.
EJEMPLO 5 Acceso a puertos: (Assembler en línea)

Este ejemplo demuestra lo fácil que es el acceso al hardware con C++ Builder.
Implementaremos una aplicación que escriba un byte por el puerto paralelo y luego lea el
byte escrito, esto se puede hacer ya que el puerto paralelo presenta la característica de
poseer un Latch de salida lo que obliga a mantener en sus pines la última palabra enviada.

Para el desarrollo de esta aplicación nos apoyaremos en instrucciones escritas en


lenguaje ensamblador como código nativo de C++, lo que permite darle al desarrollo un
toque más encantador.

La forma poseerá 2 botones y 2 editores de texto, un botón para escribir en el puerto


el byte escrito en el edit1, y el otro botón para leer el puerto y escribir la lectura en el edit2.
La FIG. 49. muestra como se verá la aplicación. Utilice de la paleta de componentes 2
editores, 2 labels y 2 botones desde la pestaña Standard. En la propiedad Caption de los
Labels escriba los títulos para cada editor, igual para los botones, tal como lo muestra la
figura.

FIG. 49.

Haga doble click sobre el botón Escribir para tipear el código que se ejecutará al
pulsar el botón, el código a escribir se presenta a continuación:

byte b;
b = byte(StrToInt(Edit1->Text));//se obtiene el contenido del editor y se convierte
asm
{
mov dx,378h;
mov al,b;
out dx,ax;
}
Para el segundo botón se realizará la misma labor, con el siguiente código:
byte b;
asm
{
mov dx,378h;
in ax,dx;
mov b,al;
}
Edit2->Text=IntToStr(b);

El primer bloque de código define la dirección del puerto paralelo, (378h), luego
mueve a la parte baja del registro acumulador del CPU (al) el valor capturado desde el
editor, que a su vez fue convertido a byte, finalmente ejecuta un “out” en la dirección de
puerto cargada en dx (378h) con el valor guardado en el registro acumulador del CPU, esto
escribe en el puerto paralelo el byte escrito en el edit1. Recuerde que el valor a colocar en
el Edit1 debe estar entre 0 y 255, ni mayor ni menor, ya que lo se escribirá por el puerto
será un byte.

En el botón de lectura el código es similar, sólo que se ejecuta un “in” en la


dirección del puerto especificado para leer el contenido del Latch, luego se mueve ese valor
capturado en el acumulador a una variable byte la cual es convertida a cadena para ser
colocada en el edit2. Lo lógico será que se escriba en el puerto se es lo que se lee, por lo
tanto el edit2 debe mostrar el mismo valor del edit1 cuando se pulse el botón leer.

La salida de este programa la podemos observar en la FIG. 50.


FIG. 50.

EJEMPLO 6 (COM en acción, Módulo remoto de datos)

En este ejemplo realizaremos la aplicación de BD del ejemplo 5 pero en tres capas, la


capa central será un objeto COM Out Procces (Automation Server). La aplicación se
realizará basada en 2 aspectos:

1. El Query es enviado desde el cliente al servidor para ser ejecutado en el servidor


2. El cliente llamará a una función en el servidor que tendrá el Query diseñado y lo
ejecutará, devolviendo al cliente a través de parámetros OLE los datos
solicitados.

Sigamos pues los siguientes pasos:

1. Cierre todas las aplicaciones desde el menú <File> opción <close all>
2. Cree una nueva aplicación desde el menú <File> opción <New Application>. Una
nueva forma aparecerá en blanco.
3. Ahora pulse desde el menú <File> la opción <New>, aparecerá un diálogo (New
Items), con varias pestañas, seleccione la pestaña “Multitier” y pulse sobre el Icono
“Remote Data Module”, tal como se muestra en la FIG. 51.

pestaña
Multitier

Icono Remote
Data Module

FIG. 51.
4. Aparecerá un diálogo (New Remote Data Module), que solicita información
referente al objeto que se creará, el CoClass Name, que es el nombre que se le dará
al objeto COM, el Threading Model, que es el modelo de hilo a seleccionar, en este
caso lo dejaremos aparment, ya que este modo serializa las conexiones hacia la BD.
En el editor de descripción escribiremos la descripción de nuestro objeto. La FIG.
52. nos muestra como se verá esta pantalla una vez llenada sus opciones.

FIG. 52.

5. Pulse OK para que aparezca el contenedor de objetos. Incluya un componente


“Query1” de la pestaña Data access, y un componen Data “Set Provider“ de la
pestaña Midas. VER FIG. 53.
FIG. 53.
6. Defina las propiedades de cada componente a través del inspector de objeto tal
como se señala en las figuras 54 y 55.

Define el
alias de la
BD

Define el
Data Set
Activa las para el
propiedades proveedor
autorefresh,
Propagación de
data, permitir
comandos de
texto (Query’s),
y resolver al
cliente de datos

FIG. 54. FIG. 55

El componente “Query1”, se encargará de realizar las sentencias SQL al manejador de BD


y el componente “DataSetProvider” se encargará de proveer la data al Cliente que la
solicite.

7. Desde el menú “View” pulse la opción “Type Library” para llamar al Type Library
Editor, el cual nos permitirá incluir métodos al objeto con sus parámetros OLE.
Incluir nuevo Exporta IDL
método a la interface Refrescar, genera el código
seleccionada y actualiza las
modificaciones

Registra el Type
Library

Interface

Objet
o

FIG. 56. (Type Library)

8. Seleccione el Icono de interface, debajo de project1 y pulse el Icono de incluir


nuevo método, de esta forma se añade un método al objeto.
9. Renombre el método y colóquele “buscar” como nuevo nombre.
10. Observe que las pestañas del panel derecho cambiaron, seleccione la pestaña
parameters para añadir los parámetros que utilizará el método y añada 3 parámetros,
el primero será “ced” de entrada que manejará la cédula, el segundo “nom” de
salida, el cual devolverá el nombre de la persona y el tercero será “ape “, también de
salida, el cual devolverá el apellido. Ver FIG. 57.
11. Pulse el Icono refrescar “Implementation” para generar el esqueleto del método.
12. En el diálogo de código ubique la pestaña “TDataComImpl”, y haga click, luego
ubique el código del método. Ver FIG. 58.
13. Escriba el código que se muestra en la FIG. 59. para el método buscar.
14. Ejecute desde el menú <Project> la opción <Build RDataMod> para compilar el
Objeto y generar el archivo ejecutable.
15. Ejecute el programa una sola vez
16. Ejecute desde la opción “ejecutar” de Windows <RegEdit> y pulse aceptar.
pulse aquípara
Pestaña para Elimina el Cambia el RefrescarCambia
Implementación
Define
el el tipo de
añadir nuevo
crear los parámetro orden, sube el respuesta
orden, baja el del
parámetro
parámetros seleccionado seleccionado y método
seleccionado y
del método baja el sube el
contiguo contiguo

FIG. 57.

Código
generado para
el método

FIG. 58.
FIG. 59.

FIG. 60.

17. Desde el menú de opciones del RegEdit ejecutar <Edición> <Buscar>, luego
colocar el nombre del objeto, “DataMod” y pulse Ok para comenzar la búsqueda.
18. copie el número Guid en un archivo de texto con el nombre guids.txt. Ver FIG. 61.
FIG. 61.

En este momento la aplicación del servidor está culminada, solo resta hacer la
aplicación cliente para probar el servidor.

Para la aplicación cliente siga los siguientes pasos:

1. Cierre todo utilizando <File> <Close All>


2. Cree una nueva aplicación a través de <File> <New Application>
3. De la pestaña de componentes Midas coloque los componentes “DComConnection”
y “ClienDataSet”.
4. De la pestaña de componentes Data Controls coloque los componentes “DBGrid” y
“DBNavigator”.
5. De la pestaña de componentes Data Access coloque el componente “DataSource”.

En este momento la forma se verá como en la figura 62.


DataSource

ClientDataSet
DComConnection

DBGrid

DBNavigator

FIG. 62.

6. Configure las propiedades de cada componente como sigue:

FIG. 63. (Propiedades de DComConnection)

FIG. 64. (ClientDataSet)


FIG. 65.

FIG. 67.

FIG. 66.

Las propiedades resaltadas en óvalos rojos son las modificadas.


7. Añada un botón desde la pestaña standard y configure la propiedad caption en
“Buscar”. Esto configura el nombre del botón.
8. Añada un Editor de texto con un label, el caption del label será “respuesta:”.
9. Haga doble click sobre el botón y escriba el siguiente código:

void __fastcall TForm1::Button1Click(TObject *Sender)


{
TVariant v;
DCOMConnection1->Connected=true;
IDispatch* disp=(IDispatch*)( DCOMConnection1->AppServer);
IDataComDisp TempInterface( (IDataCom*)disp);
TempInterface.buscar(&v);
Edit1->Text=v;
}

Para este entonces el cliente se verá como sigue:

FIG. 68.

10. Ahora Añadiremos un botón con el caption: “Query”, adicional para conectar al
cliente con el provider1 del servidor.
11. El código del botón será como sigue:

DCOMConnection1->Connected=true;
ClientDataSet1->Close();
ClientDataSet1->CommandText="select * from persona";
ClientDataSet1->Open();

12. Ejecutemos la aplicación y hagamos click en cada botón, el botón buscar retorna el
mensaje en el edit1, y el botón Query se trae la data de la base de datos y la muestra en el
DBGrid, tal como se visualiza en la FIG. 69.

FIG. 69.

Nótese que si nos movemos a través del DBNavigator funciona correctamente, sin
embargo puede existir problemas a la hora de insertar registros a través del DBNavigator ya
que los componentes de conexión están en el servidor y las modificaciones se deberán
realizar sólo a través de los mecanismo que el servidor provee.

C++ y la WEB:
C++ Builder provee a través de su entorno de desarrollo mecanismo para el manejo
de aplicaciones bajo el WEB. El mecanismo utilizado para esto es prácticamente un
estándar adoptado por los diferentes lenguajes que manejan código bajo la WEB. Este tipo
de aplicaciones requiere un servidor de aplicaciones WEB que sirva a los clientes los
servicios solicitados a través del Navegador.

Para suplir aplicaciones de servicios WEB C++ propone 3 mecanismo para la


realización de esta tarea:

1. Fabricación de DLL del tipo ISAPI/NSAPI


2. Fabricación de CGI (Ejecutables)
3. Fabricación de WinCGI

El primer caso sugiere librerías de enlace dinámico que se cargan en memoria y


manejan las solicitudes con instanciamientos dinámicos de los procesos. El segundo es el
estándar CGI, ejecutables que se instancian ejecutándose por cada solicitud de cliente, el
tercero implica la misma filosofía del segundo, solo que involucra ejecutables basados en la
API de Windows.

En cualquiera de los casos el procedimiento es similar. En este taller manejaremos


la opción 1 (DLL), ya que es la que brinda una mayor velocidad de respuesta.

EJEMPLO 7 (DLL de WEB)

1. Cierre el proyecto actual


2. Abra una nueva aplicación
3. Desde el Menú File ejecute New
4. Elija el Icono WEB Server Application, tal como se muestra en la FIG. 70

FIG. 70.
5. Escoja la Opción ISAPI/NSAPI Dinamic Link Library, tal como se muestra en la
FIG. 71.

FIG. 71.

6. En el contenedor (WEBMODULE1), incluya los siguientes componentes:

1. Query (desde la paleta DataAccess)


2. Table (desde la paleta DataAccess)
3. PageProducer (desde la paleta Internet)
4. QueryTableProducer (desde la paleta Internet)
5. DataSetTableProducer (desde la paleta Internet)

En la FIG 72. se observa como se vería el contenedor después de agregar los


componentes.
FIG. 72.
7. Hagamos click con el botón derecho sobre el “WEBDataModule” sin seleccionar
ningún componente. Aparecerá un PopUp Menú como el de la figura 73.

FIG. 73.

8. Seleccione la opción Action Editor. El Action editor es la herramienta que permite


añadir Action a la dll. Un Action es como una función, en este caso de WEB, que
puede ser invocada desde el cliente WEB a través de un URL específico. por
ejemplo, si la dll se llama “DLL1.dll” y el Action se llama “ver”, asumiendo que la
dll está publicada en el servidor WEB “WServer”, en la carpeta compartida
“Script”, la llamada desde el Browser sería:
“HTTP:\\WServer\Script\DLL1.dll\ver”.
9. Desde el Action editor incluir un nuevo Action pulsando el Icono Add New(Ins), tal
como se muestra en la figura 74.

Icono para adicionar


un nuevo Action

FIG. 74.

10. Sobre el Inspector de Objetos, en la propiedad PathInfo, escribir el nombre del


Action, en este caso “OK” y pulsar Enter. La figura 75 muestra como se verá el
inspector de objetos después de esta acción.

FIG. 75.

Observe que el Action Editor incluyó el nuevo Action en su ListBox. Ver Figura 76.
FIG. 76.

11. En el inspector de objetos haga click sobre la pestaña “Events”, esto hará aparecer
el evento OnAction tal como se muestra en la figura 77.

FIG. 77.
12. Haga doble click sobre el ComboBox de la propiedad para escribir el código del
Action. Esto hará emerger la ventana de código como se muestra en la figura 78.
FIG. 78.

Observe que el Action presenta el instanciamiento de 2 Objetos importantes, el


Request y el Response.

El método Request será utilizado para recibir los parámetros desde el cliente y el
método Response será utilizado para enviar la respuesta al cliente. Como este método se
desarrolla sólo para decirle al cliente que la dll está funcionando Ok, la respuesta que
enviará este método será: “La dll está Ok..!”.

13. Escriba el siguiente código: Response->Content="La dll está Ok..!";


14. Salve la Dll como MiDllx, donde x será el número que le asigne el facilitador, para
este ejemplo x será 1, la unidad se salvará como U_Web.
15. Ejecute la opción Build para generar Midll1.dll.
16. Desde el menú Project pulse la última opción:”Options” tal como se muestra en la
figura 78.

FIG. 78.

17. Sobre el diálogo Project Option seleccione la pestaña Directories/Conditionals, tal


como se muestra en la figura 79.
FIG. 79.
18. Coloque la ruta de publicación en la opción que dice: final out:, tal como se muestra
en la figura 80.

FIG. 80.
Esto se puede hacer manualmente o pulsando sobre el Icono que está a la derecha el
cual posee 3 puntos, y buscar a través del explorador de Windows que aparecerá al pulsar el
botón, el directorio de publicación WEB para la dll. De esta forma C++ Builder generará la
dll en el directorio asignado cada vez que se ejecute la opción de reconstrucción “Build”

Ahora escribiremos el código para los demás Actions que se crearán en este
ejemplo.

1. Conecte el componente Query a la base de datos persona


2. Cree un nuevo Action llamado “buscar” y escriba el siguiente código:

{
try
{
Query1->Close();
Query1->SQL->Clear();
Query1->SQL->Add("select * from person");
Query1->Open();
Query1->First();
PageProducer1->HTMLDoc->Add("<HTML>");
while (!Query1->Eof())
{
PageProducer1->HTMLDoc->Add(Query1->Fields->Fields[0]->AsString+
" "+Query1->Fields->Fields[1]->AsString+" "+
Query1->Fields->Fields[2]->AsString);
PageProducer1->HTMLDoc->Add("<BR>");
Query1->Next();
}
PageProducer1->HTMLDoc->Add("</HTML>");
Response->Content=PageProducer1->Content();
PageProducer1->HTMLDoc->Clear();
}
__except(0)
{
Response->Content="Error en la conexión a la BD..!";
}
}

3. Conecte el componente “Table” con la tabla “person” de la base de datos persona y


coloque la propiedad active=true. Ver figura 82. y coloque en el caption=”Tabla de
datos”
4. Conecte el componente DataSetTableProducer1 con el componente Table a través
de la propiedad DataSet como se muestra en la figura 81.
FIG 81
FIG 82.
5. Seleccione el componente DataSetProducer1 y pulse sobre
la propiedad columns, como se muestra en la figura 83.
Pulse aquí para llamar al
editor del DataSetProducer1

FIG. 83.

El editor del DataSetProducer1 aparecerá como se muestra en la figura 84.


FIG. 84.

6. Ajuste las propiedades de las columnas al gusto, la salida de datos se visualiza en la


parte inferior del editor. Ver figura 85.
FIG. 85.

7. Seleccione en el Action Editor el Action “Tabla” y haga click en el inspector de


objeto en la pestaña Events, luego haga doble click en el ComboBox de la
propiedad OnAction para llamar a la pantalla de código.
8. En la pantalla de código mostrada en la figura 86 escribir el siguiente código:

Response->Content = DataSetTableProducer1->Content();

9. Seleccione el componente QueryTableProducer1.


10. Ajuste las propiedades como sigue:

Caption= Resultado del Query


Query = Query1

ver la figura 87.


11. En el Action Editor, Insertar un nuevo Action con nombre Query
12. Seleccione la pestaña Events, luego haga doble click en el ComboBox de la
propiedad OnAction y escriba el siguiente código en la ventana de código para el
nuevo Action:

{
try
{
Query1->Close();
Query1->SQL->Clear();
Query1->SQL->Add("select * from person");
Query1->Open();
Response->Content=QueryTableProducer1->Content();
}
__except(0)
{
Response->Content="Error con conexión a la BD..!";
}
}
FIG. 86.
FIG. 87.

13. Ajuste las propiedades del componente QueryTableProducer1 al gusto, tal como lo
hizo para el componente DataSetTableProducer1.

13. Ejecute el Internet Explorer o el Nestcape para probar los Actions creados.
14. Escriba las siguientes llamadas en el Browser para probar cada Action:

http://sirio/scripts/Midll1.dll/ok
http://sirio/scripts/Midll1.dll/buscar
http://sirio/scripts/Midll1.dll/tabla
http://sirio/scripts/Midll1.dll/query

Cada salida se muestra a continuación en las figuras siguientes:

FIG. 88.
FIG. 89.

FIG. 90.
FIG. 91.

Ahora realizaremos una página HTML con un Form, luego, utilizando el método Post
llamaremos a una Action de la DLL de WEB.

EJEMPLO 8 (Llamada de la DLL desde una página HTML)

1. Seleccione el NotePad de Windows y escriba el siguiente código:

<HTML>
Pulsa el botón Ok para obtener respuesta de la DLL..!
<Form Method="post" action="HTTP:\\sirio\scripts\MiDll1.dll\ok" >
<input type= "submit" value="Ok" name="B1">
</Form>
</HTML>

2. Salve el archivo con extensión .HTML


3. copie el archivo en el directorio C:\WebShare\wwwroot
4. Llame a el Browser de Internet y escriba la ruta para llamar la página creada, en este
caso: http://sirio//web.html

La salida se muestra a continuación:

FIG. 92.

Al pulsar el botón Ok se obtiene:


FIG. 93.

Como puede notar, al pulsar el botón se invoca al método Action “OK” y se ejecuta
el código escrito en el Action. Llamemos al método Buscar, para ello realice el siguiente
cambio a la página:

<HTML>
Pulsa el botón Ok para obtener respuesta de la DLL..!
<Form Method="post" action="HTTP:\\sirio\scripts\MiDll1.dll\buscar" >
<input type= "submit" value="Ok" name="B1">
</Form>
</HTML>
Modificación

Salve la página como WEB2.html y publíquela en el servidor web, luego realice la


llamada a la página y pulse el botón Ok. La respuesta se muestra en la figura 94.
FIG. 94.

Como puede observar, se ha ejecutado el Action buscar, lo que indica que la


llamada al método de la dll fue exitosa.

EJEMPLO 9. (Pase de parámetros)

En este ejemplo manejaremos el pase de parámetros a través de la página hacia la


dll. Para esto crearemos un nuevo Action y lo Llamaremos Query2, el código que se
escribirá en el método es el que sigue:

AnsiString s;
s=Trim(Request->ContentFields->Values["E1"]);
try
{
Query1->Close();
Query1->SQL->Clear();
Query1->SQL->Add("select * from person where ced="+s);
Query1->Open();
Response->Content=Query1->Fields->Fields[1]->AsString+" "+
Query1->Fields->Fields[2]->AsString;
}
__except(0)
{
Response->Content="Error con conexión a la BD..!";
}

Note que a través de la línea “s=Trim(Request->ContentFields->Values["E1"]);”, se


obtiene el valor introducido en el editor del browser, esto es, el valor se traspasa a la dll a
través del método post, luego la dll a través del objeto Request obtiene el valor y lo asigna a
la variable s, la que a su vez se concatena para la realización del query.

Al ejecutar la aplicación se observa:

FIG. 95.
Tipee una cédula conocida, la cual se encuentre en la base de datos, en este caso se tipea 1.
Ver figura 96.
FIG. 96.
Al pulsar Ok se obtiene:

FIG. 97.

...el browser muestra el nombre y el apellido de la cédula introducida, para este caso,
“juan garcia”.

A esto se le llama dinamismo en la WEB.

EJEMPLO 10 (Active Forms)

Los Active Forms son formas activas en la WEB, esto se refiere a tener una forma
tal como se maneja en los lenguajes visuales, con todas las potencialidades de la misma,
pero trabajando dentro del browser.

Para lograr esto, se utiliza la tecnología de ActiveX, creada por Microsoft, esto se
refiere a crear un control activeX (.ocx ), el cual se cargará en el browser como una
aplicación. Esto sólo es posible utilizarlo con el internet explorer ya que esta tecnología
sólo es soportada por los navegadores de Microsoft.

Note que los ActiveX son libres de interactuar con el hardware del equipo, ya que
son aplicaciones independientes, lo que no garantiza la seguridad de que el programa (.ocx)
no pueda realizar estragos en la máquina local, esta ha sido la crítica más fuerte que ha
recibido Microsoft para con esta tecnología, sin embargo las potencialidades de la misma
no dejan de ser atractivas.

1. Cierre todas las aplicaciones.


2. Ejecute desde el menú file de C++ <New>
3. Pulse la pestaña ActiveX y haga doble click en el Icono Active Form. figura 98.

Pestaña de
Icono de
ActiveX
Active Form

FIG. 98.

4. Sobre el diálogo Active Forms Wizard tipee en el editor “New ActiveX Name”, el
nombre del componente, para este caso MiActiveX1. Figura 99.
FIG. 99.

5. pulse Ok
6. Sobre la forma coloque los siguientes componentes:

Table1
DataSource1
DBGrid1
DBNavigator1

tal como se muestra en la figura 100.

FIG. 100.

7. Configure los componentes para accesar la base de datos persona.

Esto es:

Table1.DatabaseName = persona
Table1.TableName = person
Table1.Active = true;
DataSource1.DataSet = Table1
DBGrid1.DataSource = DataSource1
DBNavigator.DataSource = DataSource1

8. Salve la aplicación con los nombres por defecto, añadiendo al final su número
asignado por el facilitador para distinguir su ocx de los de otro participante.
9. Pulse a través del menú project la opción “Web Deployment Option”. Ver figura
101.
FIG. 101.

10. En el diálogo Web Deployment Option llenar las opciones como sigue:

Target dir = C:\Curso de C++;


Target URL = file:\\C:\Curso de C++
HTML Dir = C:\Curso de C++

Seleccione sólo los 2 primeros Checks, tal como se muestra en la figura 102.
FIG. 102.

11. pulse Ok
12. Desde el menú project pulse la opción “Web Deploy”. Esto generará el componente,
así como la página web.
13. Registre el componente ActiveX desde el menú Run pulsando la opción Register
ActiveX Server.
14. Ejecute la página Web creada haciendo doble click sobre el archivo.
15. Disfrute de la versatilidad de un componente ActiveX. Figura 103
FIG. 103.

Note que la funcionalidad de la aplicación es exactamente igual a la de un .exe, con la


diferencia de que está a través de la web. El archivo .html puede editarlo a modo de darle
los toques particulares.
EJEMPLO 11 (Más Objetos COM)

Veamos ahora un tipo de objeto que trabaja con la filosofía ActiveX, esto es un
objeto COM que permite componentes visuales.

1. Cree una nueva aplicación


2. Desde el menú <file> pulse la opción <New>
3. Seleccione la pestaña <ActiveX>
4. Haga doble click sobre el Icono “Automation Object”, tal como se muestra en la
figura 104.

FIG. 104.

5. En el diálogo “New Automation Object”, colocar en el CoClass Name


“MiAutoObjx” donde x es el número asignado por el facilitador. Ver figura 105.

FIG. 105.
6. Coloque un Label, un Memo y un Botón en la forma, tal como se muestra en la
figura 106.

FIG. 106.

7. A través del Type Library añada un método al objeto llamado “Mensaje”. FIG. 107.
8. Añada un parámetro de salida del tipo *Variant, tal como se muestra en la figura
108.
9. Pulse el botón de refrescar en el Type Library para generar la plantilla de código
para el método.
FIG. 107.

Botón
Refrescar

FIG. 108.
10. Para el método escriba el siguiente Código mostrado en la FIG. 109. para el botón
limpiar escribir: Memo1->Clear();

FIG. 109.

Note que se incluyó la librería <stdlib.h> y se anexó la unidad


U_Automation_Server.h, esto para, en el primer caso, manejar las funciones Random, y en
segundo caso poder hacer referencia a la forma1. Si se va a escribir estas definiciones de
librerías es importante que antes salve el proyecto y las unidades, ya que si escribe el
código o lo anexa a través del menú <file> y luego salva las unidades con otro nombre, esto
generará un error para con el nombre de la unidad anexada, y deberá cambiar el mismo al
utilizado para salvar de forma tal de poder eliminar el error.

11. Ejecute el COM para registrarlo en el equipo.


12. Capture el GUID desde el Type Library. Ver Figura 110.

FIG. 110.

13. Cierre todo con la opción Close All del menú <file>
14. Genere una nueva aplicación para el cliente
15. Incluya en la forma, un editor, un botón, un label y un DComConnection, tal como
se muestra en la figura 111.

FIG. 111..

16. Conecte el DCOM al COM creado utilizando el GUID y el nombre del equipo. Ver
figura 112.
FIG. 112.

17. Sobre el botón solicitud de mensaje escribir el siguiente código:

{
TVariant v;
DCOMConnection1->Connected=true;
IDispatch* disp = (IDispatch*)(DCOMConnection1->AppServer);
IMiAutoObjxDisp TempInterface( (IMiAutoObjx*)disp);
TempInterface.mensaje(&v);
Edit1->Text=v;
}

18. Ejecute la aplicación cliente y haga click 3 veces en el botón solicitud de mensaje.

La salida a pantalla completa se muestra en la figura 113.

Nótese que al pulsar el botón se realiza la llamada al objeto COM, el cual muestra la
pantalla al momento de servir al cliente. El mensaje que recibe el cliente también es
enviado al memo del servidor, lo que muestra la versatilidad de este objeto de poder
manejar componentes visuales.
servido
clienter

FIG. 113.

EJEMPLO 12 (Servidores de automatización para Office)

A continuación veamos una de las nuevas características del C++ Builder,


manejando servidores del Office, en este caso el servidor Word.

1.Cierre todas las aplicaciones


2.Genere una nueva aplicación
3.Coloque un botón y los componentes WordApplication y WordDocument desde la
pestaña de componentes Servers. Ver figura 114.

FIG. 114.
5. En el botón Word escriba el siguiente código:

{
OleVariant Template = EmptyParam;
OleVariant NewTemplate = False;
OleVariant ItemIndex = 1;

try
{
try
{
WordApplication1->Connect();
}
catch (Exception &exception)
{
MessageDlg("El Word no debe estar instalado..!", mtError, TMsgDlgButtons() << mbYes, 0);
Abort;
}
WordApplication1->Visible = True;
WordApplication1->Caption = StringToOleStr("Office automation");
//Creando un nuevo document0
WordApplication1->Documents->Add(Template, NewTemplate);
//Assign WordDocument component
WordDocument1->ConnectTo(WordApplication1->Documents->Item(ItemIndex));
//colocando el Spell checking en false, ya que esto toma mucho tiempo si está deshabilitado
WordApplication1->Options->CheckSpellingAsYouType = False;
WordApplication1->Options->CheckGrammarAsYouType = False;
//Insertando data
WordDocument1->Range(EmptyParam, EmptyParam)->InsertAfter(StringToOleStr("Texto de prueba...línea1\n" ));
WordDocument1->Range(EmptyParam, EmptyParam)->InsertAfter(StringToOleStr("Texto de prueba...línea2\n" ));
}
catch (Exception &exception)
{
Application->ShowException(&exception);
WordApplication1->Disconnect();
}
}

La ventana de código se verá como la de la figura 115.

6. Ejecute el programa y pulse el botón word


7. Que maravilla..!, disfrútelo. La salida se observa en la figura 116. a pantalla
completa.
FIG. 115
FIG. 116.
EJEMPLO 13. (Un servidor para Excel)

Esta es otra de las bondades que podemos aprovechar de este entorno. Veamos
como realizar una aplicación de interacción con Excel.

Procedimiento:

1. Cree una forma e incluya los componentes: ExcelApplication, ExcelWorkSheet y


ExcelWorkBook, desde la paleta “Server“.
2. Añada 2 botones a la paleta, tal como se presenta en la figura 117.
3. En el Botón rotulado como “Excel” escriba el siguiente código:

Variant vExcelApp,vExcelWorkbook,vExcelWorksheet;
vExcelApp = CreateOleObject("Excel.Application");
vExcelApp.OlePropertySet("Visible",true);
vExcelApp.OlePropertyGet("Workbooks").OleProcedure("Add");
vExcelWorkbook=vExcelApp.OlePropertyGet("Workbooks").OlePropertyGet("Item",1);
vExcelWorksheet=vExcelWorkbook.OlePropertyGet("ActiveSheet");
vExcelWorksheet.OlePropertySet("Range", "C1", "C1", "=A1+B1");
vExcelWorksheet.OlePropertySet("Range", "A1", "A1", 1);
vExcelWorksheet.OlePropertySet("Range", "B1", "B1", 1);

4. En el botón rotulado como “Salir” escriba el siguiente código:

ExcelApplication1->Quit();
ExcelWorksheet1->Disconnect();
ExcelWorkbook1->Disconnect();
ExcelApplication1->Disconnect();

5. Ejecute el programa y pruebe.

Fig. 117.

Observe que se necesita crear instanciamientos de los objetos utilizados, para ello
utilizamos las variables “vExcelApp ,vExcelWorkbook, vExcelWorksheet”, declaradas como
Variant.

Notemos que es posible enviar datos o fórmulas a través de la instrucción:

vExcelWorksheet.OlePropertySet("Range", "B1", "B1", 1);.


Se recomienda revisar los métodos de los objetos, ya que esto permitirá ampliar la
gama de funcionalidad de estos componentes.

EJEMPLO 14. (Gráficos)

En este ejemplo veremos como se pueden crear gráficos interactivos en C++. Para
esto utilizaremos la componente “Tchar” ubicada en la paleta “Aditional”.

Pasos:

1. Cree una nueva aplicación


2. Coloque la componente TChar en la forma
3. Pulse el botón derecho y ejecute el editor del Tchar. (Fig. 118)
4. Seleccione la pestaña “Series” y adicione una serie tipo Bar3d. La figura 119
muestra como se verá la forma
5. Coloque un botón a la forma
6. Declare 2 variables globales como enteras “int a=0” y “int b=0”
7. Coloque un Timer en la forma y deshabilítelo. La Figura 120 muestra como se verá
la forma en este momento.
8. Escriba el siguiente código para el botón:

Chart1->View3DOptions->Orthogonal=false;
Chart1->Series[0]->Add(100,"Valor1",clBlue);
Chart1->Series[0]->Add(50,"Valor2",clBlue);
Chart1->Series[0]->Add(150,"Valor3",clBlue);
Timer1->Enabled=true;

9. Escribe el siguiente código para el evento del Timer:

a++;
b=a;
if (a>360)
{
a=0;
b=0;
}
Chart1->View3DOptions->Rotation=a;
Chart1->View3DOptions->Elevation=a;
10. Pruebe la aplicación
FIG. 118 (Editor TChar)

FIG. 119.
FIG. 120

Al ejecutar la aplicación no se visualizará el gráfico, al pulsar el botón “Probar”, se


generará un gráfico creado con los valores escritos en el código:

Chart1->Series[0]->Add(100,"Valor1",clBlue);
Chart1->Series[0]->Add(50,"Valor2",clBlue);
Chart1->Series[0]->Add(150,"Valor3",clBlue);

Esto genera un gráfico de 3 barras 3d. Note que al variar los valores para las
propiedades de rotación y elevación, se consigue el efecto de animación. Toda la
animación se hace posible si la propiedad de “Orthogonal” está en “false”. Esto s1e
maneja mediante el código del evento del Timer.

Es posible controlar más propiedades de este componente, Zoom, Tipos de gráfico,


etc. Es importante recalcar el hecho de que todas estas propiedades pueden ser
modificadas dinámicamente, es decir, por código y en tiempo de ejecución.
EJEMPLO 15. (Quick Report)

Este ejemplo nos mostrará la forma como C++ Builder maneja los reportes. Para
esto se manejará el componente de Reportología proveído por C++ “QuickRep”.

Pasos:

1. Cree una nueva aplicación


2. Coloque los siguientes objetos dentro de la forma:

a. QuickRep pestaña (QReport)


b. 2 QRBand pestaña (QReport)
c. Table para la conexión a una BD
d. QRLabel Para el título de la columna pestaña (QReport)
e. QRDBText Para mostrar un campo de datos pestaña (QReport)
3. Configura cada componente como sigue

FIG.121. (Config. del QuickRep) FIG.122. (Config. del Table)


FIG. 123 (Config. De QRBand2) FIG. 124 (Config. de RQBand1)

FIG. 125. (Config. QRDBText)


FIG. 126. (Config. del QRLabel)

4. Coloque un botón rotulado como “Reporte”.


5. Coloque el siguiente código para el botón:

QuickRep1->Preview();

6. Ejecute la aplicación y pulse el botón de Reporte. (Fig. 127 y 128)


FIG. 127. (Aplicación ejecutada)
FIG 128. (Reporte)

Note que el reporte emerge cuando se llama la función Preview(), lo que nos indica
que la forma con el Reporte sin ejecutar no tiene porque mostrarse, esta puede ocultarse
ya que se puede asignar la llamada del reporte a un evento en cualquier otra forma.

También es factible crear reportes con gráficos, ya que el QuickRep soporta


imágenes, hasta un componente Tchar puede ubicarse en el reporte. Este componente
presenta una gran cantidad de bondades que vale la pena investigar, para ello anexo
manual del Quick Report de Borland.

Vale la pena mencionar que Delphi utiliza el mismo componente para generar los
reportes en su entorno, además para cada versión de C++ existe una versión del Quick
Report, las cuales guardan diferencias, esto es, no se puede ir de versiones superiores a
inferiores. Borland también creó el Report Smith, el cual promociona como el paquete
más completo para generación de reportes, este paquete no viene con la versión del
lenguaje, por lo que no se considera en este taller.
ANEXOS
Build Reports
using
QuickReport 3
for Borland Delphi

Distributed Worldwide by QBS Software Ltd


Contents
Realizado por: Ing. Jubert Pérez......................................................................................................................1
Índice..............................................................................................2
Extracto...........................................................................................3
FIG. 25...........................................................................................................................................................38
FIG. 26...........................................................................................................................................................38
FIG. 115.........................................................................................................................................................94
Contents......................................................................................107
What is QuickReport 3?.................................................................108
There’s more................................................................................................................................................108
A first report................................................................................109
The components...........................................................................112
Band components.........................................................................................................................................112
Printable components...................................................................................................................................113
Previews and composite reports...................................................................................................................114
Filters............................................................................................................................................................115
Chart.............................................................................................................................................................116
Creating reports...........................................................................117
TQuickRep in detail.....................................................................................................................................117
Working with bands.....................................................................................................................................121
Groups..........................................................................................................................................................124
Master/detail reports.....................................................................................................................................125
More about printable components.................................................127
Text components..........................................................................................................................................127
Using expressions.........................................................................................................................................128
Creating a default custom preview................................................130
Further resources.........................................................................133
What is QuickReport 3?
QuickReport 3 is a set of Delphi components designed to let you produce database output
quickly and easily. As well as allowing you to fling together printed reports, QuickReport
lets you create print previews where the user can check the result of a printout without
wasting paper, and export data to other file formats, such as plain ASCII, comma separated
values (CSV) and HTML.
QuickReport is itself written in Delphi and knows all about the Delphi model for handling
databases. So you can use it to report on traditional BDE-based databases such as Paradox
and dBase, client datasets used in multi-tier environments, the new Delphi 5 ADO and
Interbase Express components and third party alternatives such as Apollo. You can even
use QuickReport formatting facilities to print out non-database data, if you need to.
This manual is designed to get you up to speed quickly with QuickReport, so that you can
start to use it in your own applications at once.
There’s more
QuickReport is a fine product – but if you need even more versatility, you might consider
upgrading to QuickReport Pro. Naturally, the Pro version is offers everything in the
standard product plus:
• Three extra export filters:
Excel XLS: The XLS filter is compatible with Excel 4 and later, and provides a simple
and robust mechanism for exporting unformatted data into spreadsheets.
Rich Text RTF: The RTF filter, based on Microsoft’s RTF version 1.5 spec, supports
more RTF features than TRichEdit itself.
Windows Metafile WMF: The WMF filter lets you capture report output in a convenient
graphical format.
• Some powerful extra components. Let the user do the work: TQREditor is an end user
report editor that you can ship royalty-free with your app.

TQuickAbstractRep is a descendant of the TCustomQuickRep base class that does not use
TDataset - use it to build your own report systems.
TQRLoopBand prints the number of times set in its PrintCount property - great for
creating blank forms.
TQRListWizard will create an instant report based on the fields of a table.
• Expert technical support via email.
• Full source code. Use the source, Luke! The user can easily modify the code to localise
the language, adopt it to local interface standards, add new features and so on.
• More demos with more depth, including examples of how to make use of all the Pro
edition features, and advanced techniques such as writing custom functions for the
expression evaluator.
You can upgrade to QuickReport Professional by ordering from our web site, that of our
distributor QBS Software Ltd at http://www.qbss.com or from your local Delphi add-on
reseller.
A first report
The best way to get the hang of the QuickReport library is to see it in action. So this section
explains how to set up a very basic report. With the Delphi IDE running, follow these steps:
1 Choose File | New Application.
2 Drop a TTable component onto the main form.
3 Use the Object Inspector to set its DatabaseName property to ‘DBDemos’,
TableName to ‘CUSTOMER.DB’ and Active to True.
4 Drop a TQuickRep component on the main form. Its size and position don’t matter.
5 Set its DataSet property to ‘Table1’. This is a key step. The report object to iterates
through all the records in it DataSet, in this case Table1, whenever it is printed or
previewed.
6 If necessary, expand the Bands property in the Object Inspector by clicking on the +
symbol to its left. Set the HasDetail item to True. You will see the detail band appear
inside the report; changing the property actually creates the DetailBand1 object.
7 Drop a TQRDBText component onto the newly created detail band.
8 Set its DataSet to ‘Table1’ and DataField to ‘Company’.

At this point your form should look something like Figure 1 below.
Figure 1 – Setting up a basic report

To check that you have set up the properties correctly, preview the report by right-clicking
somewhere on the TQuickRep component and selecting the Preview item from the popup
menu. If you did everything right you should now see a preview window containing your
report, as shown in Figure 2.
Figure 2 – The preview window

If all has gone well, you now have a report that works at design time. Of course all may not
have gone well. If you are now mournfully gazing at an entirely blank report, please check
that you have completed all the steps – a likely explanation is that you forgot to set
TTable1’s Active property to True. Similarly, if you are looking at a report with only one line
– ‘Kauai Dive Shoppe’ – the problem is probably that you failed to connect QuickRep1’s
Dataset property to TTable1.
One other problem which may bite you is that the buttons on the toolbar above the report
preview area fail to appear. This is nobody’s fault: you have become a victim of what the
manufacturer of your PC’s operating system is pleased to call, in its technical documents,
‘DLL Hell’. Specifically, your machine’s copy of the common control library
(comctrl32.dll) is before 4.72, and needs updating.
You can download a later version of comctrl32.dll from the Microsoft website at
http://www.microsoft.com. But since this is one of those files that invariably turns up in
new versions of Internet Explorer and Windows Service Packs, you may well find it on one
of those CDs that they give away with PC magazines, and save a download. (In fact, it is
unlikely that this bug will bite you the developer. We describe it here so that you will
recognise the problem if one of your users is caught by it.)
Now lets make the report work as part of a compiled program. You need to write code to
call TQuickRep.Preview:
1 Drop a button to your form and set its Caption property to ‘Preview’
2 Double click on the button to add an OnClick event. Add a line of code, so that it
looks like this:
procedure TForm1.Button1Click(Sender: TObject);
begin
QuickRep1.Preview;
end;
Now run your application and click the Preview button. As before, you should see the
preview window appear. If you want to try printing the report directly to the default printer,
simply change the call to the Preview method to a call to Print, ie
procedure TForm1.Button1Click(Sender: TObject);
begin
QuickRep1.Print;
end;

At this point I must admit to taking a slightly dirty shortcut. Our test application a
TQuickRep component on its main form and, as you can see, this looks pretty odd. In real
applications you never display a form containing a TQuickRep component. Instead you use
them from other forms.
So what we should really do to finish off, if this little example were going to be a real
application, is:
3 Create another form – it will be called Form2
4 Make the new form into the main form of the project by setting Project | Options |
Main form to Form2
5 Drop a button on Form2
6 Write code like this in the button’s event handler
procedure TForm2.Button1Click(Sender: TObject);
begin
Form1.QuickRep1.Preview;
end;
7 Compile the project. The compiler will complain that Unit1 is not in Unit2’s Uses
list, and offer to fix the code. Accept the offer.

The application should now compile and run, and looks prettier and more ‘realistic’. The
end user doesn’t get to see any bewildering TQuickRep components.
But doing this aesthetic polishing doesn’t get us any further with QuickReport. So I am
going to leave out the need to have a second form from all the examples from this point
onwards, and trust you will remember when making real applications.
The components
The QuickReport components are all contained in the QReport tab of the Delphi component
palette. Here is a whistle stop tour of what they are and what they do to help you get your
bearings.
Figure 3 - TQuickRep and band components

TQuickRep. This is the most important component of them all, a container for all the other
printing components. It represents the paper on which your report will be printed. Its Page
property lets you set up the dimensions of the paper you are going to print on, while the
Dataset property specifies a source of data that the report will iterate through.
Note that, instead of dropping a TQuickRep component onto an ordinary form, you can
instead add a TQuickReport module to your project:
8 Choose File | New… to display the New Items dialog box.
9 Choose the New tab
10 Select the Report item (middle of the bottom row)

A TQuickReport is a bit like a TDataModule – it is a specialist type of form, which is never


displayed to the user. If you wish you can use TQuickReport pseudo-forms instead of
TQuickRep components on ordinary forms – there is no difference in their methods,
properties and events. But we recommend, from experience, that you put a TQuickRep
component on a form: it’s the more versatile approach. For example, having the TQuickRep
component on a form lets you use the form’s OnCreate event if you want to create
additional objects to be used by the report programmatically.

Band components
These are also container components, representing horizontal strips across report. Bands
can be associated with a physical position on a page – for example the top – and also reflect
the master/detail relationships in the database that is being displayed. For example, in the
same way that there might be many sales records for a given customer record, so a band
containing data about an individual sale might appear many times for each occurrence of a
band containing customer data.
TQRSubDetail. This is the detail band in a master/detail relationship. You can also make it
the master of another detail band, and so create multiple levels of subdetails.
TQRStringsBand. This band provides one mechanism to report on data without using a
TDataSet. It encapsulates a TStrings container; instead of retrieving a sequence of records
from a database, it retrieves a sequence of strings from its container.
TQRBand. A generic band type, which can act in different roles according to it BandType
property. Usually there is no need to drag a TQRBand onto a report. Instead use the Bands
property of TQuickRep, which creates TQRBand objects and sets their band type in one go.
TQRChildBand. Use TQRChildBand objects when you need to extend an existing band. For
example, suppose you have placed some TQRMemo components in a band, and wish to add,
say, a TQRLabel, which should always appear below. Since TQRMemo objects can expand
themselves according to their contents, it is not sufficient to arrange the label within the
band. Instead add in a TQRChildBand object, and put your label on that. The easiest way to
add a child band, by the way, is to double-click the HasChild property of its parent in the
Object Inspector.
TQRGroup. A band that prints whenever an expression changes, usually a database field.
This band is used to group like records together. For example, given a database table
containing US addresses, one could sort them by a State Code field and add a group band
with it Expression property set to the State Code field. When the report is printed, the
contents of the group band will be printed between records belonging to a given state.
Printable components
Figure 4 - Printable components

The QuickReport printable components are mostly equivalents of standard controls that you
use on forms. These are the controls, which actually get printed on the paper. Position them
within bands to define the layout of your report.
TQRLabel. Place some static text on the page.
TQRDBText. Equivalent of a TDBText control – use it to display the contents of a linked
database field. Unlike ordinary data-aware controls, but in common with all QuickReport
controls, TQRDBText uses a DataSet property to specify its source of data. Normal data-
aware controls use a DataSource property, which requires you to supply an extra
TDataSource component to ‘wire’ controls to a dataset. QuickReport controls have no such
requirement.
TQRExpr. Use this to display an ‘expression’. Typically you use one of these when you
need to massage the appearance of your data before printing it out. The best way to think of
these is as ad hoc calculated fields, used only in the report. For example, you might use it to
concatenate the parts of a customer name, held in a customer table as string fields called
“Title”, “Forename” and “Surname”. To do this simply set the Expression property of
TQRExpr to
Title + " " + Forename + " " + Surname
In real life, you would probably use a more complex expression to cope with blank fields
elegantly, but you get the idea.
TQRSysData. A control to display ‘system data’, by which we mean things like the current
page number within the report, and the current date and/or time.
TQRMemo. Very much like its standard control cousin the TMemo; use this to display
multiple lines of text. As you would expect, the text to be printed is held in a TStrings type
property called Lines.
TQRExprMemo. A composite of TQRExpr and TQRMemo. You can use this to include
{braced} expressions in multi-line blocks. This makes it an absolute natural for doing
addresses, especially since it includes a boolean property RemoveBlankLines. For example:
Company : {CompanyName}
Address : {Address1}
{Address2}
Contact : {Contact + ' ' + Phone number}
TQRRichText. Place some rich text (ie multi-line text with RTF formatting) on the page. One
use of this component is to print the contents of a TRichEdit control – simply assign it to
TQRRichText’s ParentRichEdit property.
TQRDBRichText. As you’d expect, this is a data-aware version of TQRRichText. Use it to
print formatted memos stored in BLOB fields.
TQRShape. A cousin of the little-used TShape control from Delphi’s ‘Additional’ palette.
Actually the QuickReport version is very useful for placing ‘furniture’ into report layouts
such as dividing lines above totals and grouping rectangles.
TQRImage. Display a picture or logo on a report using this control. Supports the same vector
and bitmap image formats as TImage, and can be loaded at design time using the Picture
property.
TQRDBImage. A data-aware image control for displaying images stored in BLOB fields in
the database.
Previews and composite reports
Figure 5 - Filters and miscellaneous components

TQRCompositeReport. Sometimes you need to group together separate reports into a single
print run. For example, maybe you need to print out all the new customers obtained in the
last week, together with a summary of all orders in the last week and also a list of stock that
needs reordering. As far as your customer is concerned these things belong together and
should be printed together. But from the database point of view you will want to use three
separate TQuickRep components to do the job.
The way to handle this situation is to use a TQRCompositeReport component. Drop one on
the form where you want to kick off the printing. First you need to define a handler for its
OnAddReports event, which calls the TQRCompositeReport.Add method to add all the
TQuickRep components you need to print. Suppose the reports you want to print are held on
forms called RepNewCust, RepOrderSummary and RepStockReorder, and in each case the
TQuickRep component on the form is called ‘Report’ (see the section ‘TQuickRep in detail’
below for why you might do this). Then your OnAddReports event handler should look like
this
procedure TForm1.QRCompositeReport1AddReports(
Sender: TObject);
begin
QRCompositeReport1.Reports.Add(RepNewCust.Report);
QRCompositeReport1.Reports.Add(RepOrderSummary.Report);
QRCompositeReport1.Reports.Add(RepStockReorder.Report);
end;

(If you don’t mind using the with statement in your code, you can tidy up this fragment
considerably by wrapping it up in
with QRCompositeReport1.Reports do
begin
...
end;

and knocking out the ugly repetitive QRCompositeReport1.Reports from the middle three
lines.)
Now you can call QRCompositeReport1.Print to print out all three reports in a single batch,
and QRCompositeReport1.Preview to preview them together. There are also TQRCompositeReport
component properties that let you set up paper sizes and set an overall title for the composite report
– basically everything you need to handle the output from the multiple reports in one place.
TQRPreview. To preview a report before it is printed for real, all you need do is call
TQuickRep.Preview and a standard preview window will appear. There are times, however,
when you want to have more control over the exact appearance of the preview.
The TQRPreview control lets you do this. Drop it on one of your own forms and, after you
have added a line of code to the TQuickRep.OnPreview event, the control will act as a frame
for the previewed report. If you are more ambitious, or you want to change the preview of a
composite report, you can register your own preview form as the default. See the section
‘Error: Reference source not found’ later on for details.
Filters
Sometimes, instead of printing or displaying it directly, you need to export data from your
database to another format. QuickReport comes complete with three filter components that
let you do this quickly and easily for their respective formats. Simply drop the export filter
onto the same form as the report, and the file format appears in the drop-down list of the
Save To file dialog in the preview. Registration is automatic, and you don’t need to code a
thing! (Don’t worry - you can export a report programmatically too if you wish – see
below.)
Note that not all printable components are exported by filters. Specifically, only the
contents of the following text-producing components appear in exported data: TQRLabel,
TQRDBText, TQRExpr, TQRMemo, TQRSysdata and TQRExprMemo.
TQRTextFilter. ‘Text’ format: exports the contents of the report in plain ASCII, using spaces
to separate fields.
TQRCSVFilter. CSV format: exports the report as ‘Comma Separated Variables’. As well as
using a comma to separate fields, this filter places “double quotes” around them, which
allows you to have commas within the fields themselves. This format is easily imported
into spreadsheets such as Microsoft Excel. By the way, the component has a Separator
property that specifies the character used to separate the fields. By default this value is set
to ‘,’ comma, but it can be changed to match your requirements.
TQRHTMLFilter. HTML format: exports the report to a HyperText Markup Language file,
as used in web browsers, some emailers, help systems and many other places.
It is also possible to call filters explicitly from code. This fragment uses the HTML filter.
quickrep1.ExportToFilter(
TQRHTMLDocumentFilter.Create('c:\report.txt'));

To use the Text or CSV filters in this way, use the same ExportToFilter call but instantiate a
TQRAsciiExportFilter or TQRCommaSeparatedFilter object as appropriate.
Chart
TQRChart is a version of TChart adapted to work with QuickReport. This allows you to add
complex charts to your reports – the combination is very powerful indeed. TQRChart is used
in the same way as the ordinary TChart control – double click it to bring up its extensive
property editor. For details of how to accomplish tasks such as setting up series and
adjusting the look of a chart, please see the TeeChart documentation.
Version incompatibility
Because of dependency issues beyond our control, certain versions of TeeChart are
incompatible with newer versions of QuickReport, and the TQRChart control and the whole
of TeeChart can be unloaded when you upgrade QuickReport. For example, at time of
writing the Delphi 3 version of QuickReport 3 (or higher) will not work with TeeChart,
because the version of TeeChart that is shipped with Delphi 3 is coded to depend on the
QuickReport 2 package. A workaround is to download the (free) TeeChart 4 evaluation
version from the TeeMach site at http://www.teemach.com/.
This issue extends to the Decision Cube components found in Client/Sever and Enterprise
Editions of Delphi – these depend on TeeChart, and get unloaded when it does. At present,
there is no way to use the Delphi 3 Decision Cube with both QuickReport 3 and TeeChart.
We do apologise for this unsatisfactory situation. Since it is caused by design decisions
made by other parties in code we cannot access, so that we are not able to fix matters
autonomously. If you run into trouble when upgrading QuickReport, please check our
website http://www.qusoft.no/ and TeeMach’s for the latest information.
Creating reports
The first step when creating a QuickReport is to create a form to store your TQuickRep
component. We refer to this form as a ‘report form’ since it’s just a container for a report
component and is not shown to the end user at runtime. It’s a good idea to adopt a naming
convention for such reports so that they are easily identifiable in the project manager and in
directory listings. For example, you could prefix all report form names with ‘rep’ or ‘rp’ to
make them stand out. You might want to use a similar scheme with form and data module
unit names.
TQuickRep in detail
The next step is to drop a TQuickRep component onto the form. Another useful convention
you may like to adopt: by naming all TQuickRep components ‘Report’, you can reference
them as repCustomerListing.Report, repSalesListing.Report and so on.
Units and Zoom properties
When dropping the TQuickRep component on a form you will se a grid to act as a guide for
positioning components. The grid is shown in the current QuickReport units. Select the
currently active unit by changing the TQuickRep.Units property in the property inspector.
The grid will be updated when you change this property.
Figure 6 - Adjusting the Units property to alter grid spacing

With Units set to ‘MM’, the grid displays at 10mm intervals; if it is set to ‘Inches’ then the
grid displays at 1" intervals. Using the grid you can produce very accurate report layouts,
positioning and sizing QuickReport components to 0.01" or 0.01mm.
Usually your screen is too small to display an entire TQuickRep component, since it sizes
itself based on the actual paper size selected. To get a clearer picture of the whole report,
change the Zoom property to 50% or less. Changing the zoom causes the TQuickRep
component and all the printable controls it contains to be redrawn at once to the requested
scale. This feature can also be used to enlarge important details for accurate positioning and
sizing.
Paper size and margins
You can set up page layout accurately by expanding the Page property of the TQuickRep
component. Double click on the + sign to the left of ‘Page’ in the Object Inspector to
expand the sub properties. You will now see all the settings controlling the page layout.
Figure 7 - Page sub properties

The values given are in the currently selected Units, in this case inches. The margin settings
can be seen as blue dotted lines on the TQuickRep component. All bands are sized to fit
inside the margins.
The sub properties are described in Table 1 below:
Table 1 - Sub properties of Page

Property Type/Values Notes


BottomMargin Extended Units property determines
interpretation.
Columns Integer Number of columns when
printing multi-column detail
bands.
ColumnSpace Extended Space inserted between each
column in a multi column
report. Units property
determines interpretation.
LeftMargin Extended Units property determines
interpretation.
Length Extended Read-only, unless PaperSize
is set to Custom. Units
property determines
interpretation.
Orientation TPrinterOrientation =
(poPortrait, poLandscape)
PaperSize TQRPaperSize = These are all the default paper
(Default, Letter, LetterSmall, sizes supported by Windows.
Tabloid, Ledger, Legal, To use another paper size, set
Statement, Executive, A3, A4, this property to Custom and
A4Small, A5, B4, B5, Folio, set Length and Width
Quarto, qr10X14, qr11X17, appropriately – but see also
Note, Env9, Env10, Env11, note below.
Env12, Env14, Sheet, DSheet,
ESheet, Custom)
RightMargin Extended Units property determines
interpretation.
Ruler Boolean Enables display of grid.
TopMargin Extended Units property determines
interpretation.
Width Extended Units property determines
interpretation.

Not all printer drivers support setting custom paper sizes through the Custom setting of
Papersize. In these cases you must select ‘Custom paper size’ in the printer driver’s own
dialog (accessed from the Windows Control Panel) and define the paper’s dimensions
there. Set this custom paper size to be the default paper size for that printer and finally set
the TQuickRep.Page.PaperSize property to Default. Your custom size will now be picked
up at runtime.
Alternatively, and perhaps more robustly, use the next largest standard paper size, and set
the margins to keep the printing within the custom area.
Selecting a font
As you would expect, you can set the default font for your report in the TQuickRep.Font
property. Double click on the property to get the standard Delphi font dialog.
The fonts listed are the Windows system fonts, True Type fonts and any PostScript fonts (if
Adobe TypeManager is installed). You can use any combination of fonts in your reports but
we advise the use of TrueType or PostScript fonts if you intend to allow the user to preview
the report. The system fonts do not scale very well in preview.
Some dot matrix printers print much faster if you select a font already build into the printer
hardware, called a ‘printer font’. Such fonts are not listed by the font dialog, but can be set
programmatically:
repCustomerListing.Report.Font.Name := 'CG TIMES';

The readability of your report depends very much on your font selection. You should
consider this carefully when selecting fonts. Using many different fonts, colours and styles
in a report can easily make it look cluttered and difficult to read.
Title and Description
The TQuickRep component has Title and Description string properties to identify and
describe the report. These are provided for your convenience, so you can make report
selection a data-driven procedure. For example, you might have generate a menu that lists
all your reports by title and shows the description when the user selects a report. An
example of this can be seen in the QuickReport example project.
The Title property can be printed on the report itself using a TQRSysData component.
Functions
The Functions property of a TQuickRep allows you to set up constants and functions that can
be used by QuickReport expressions contained in any TQRExpr, TQRExprMemo and
TQRGroup components that you drop on the report. Double-click the property the ‘…’
button in the object inspector to bring up the special property editor:
Figure 8 - Functions property editor

Use this dialog, and the expression builder that underlies it, to define constants that you
expect to require in multiple expressions. For example, you can see that in Figure 8 above I
have defined, with a regrettable lack of originality, the constant PI as 3.14159265358979.
The other functions you see, PAGENUMBER, COLUMNNUMBER and REPORTTITLE, are
automatically predefined.
Working with bands
QuickReport is a banded report generator. If you are unfamiliar with banded report
generators you can think of them as small paper templates, which are arranged horizontally
on a page and filled with data. Different templates are copied into different parts of the
page/report. The printable components, TQRLabel, TQRDBText and so on, are designed to be
placed on these bands. Placing these components directly on the report is not supported.
The easiest way to add bands is via the TQuickRep.Bands property in the Property Inspector.
Click the ‘+’ sign to the left of the word ‘Bands’ to expand the list of common bands:
Figure 9 - Bands sub properties

The Object Inspector shows if a given band type exists in the report or not, and you can add
or delete a band simply by changing the relevant property. Bands created this way get
names that describe their function: DetailBand1, PageHeaderBand1 and so on. The BandType
property of each band is also set automatically.
You can also add bands by selecting the TQRBand component on the component palette and
dropping it on the report. Note that if you do it this way you must take care to set the
BandType property to the desired band type, and you should also give the band a descriptive
name. The Bands property of the container TQuickRep will update itself to reflect bands
added to the report this way.
Here are the simple band types you can add to a report:

While it is possible to add a band manually and set its BandType to rbSubDetail or rbGroupHeader,
this is not recommended. These band types are intended for use only with TQRSubDetail and
TQRGroup components. Using them elsewhere may cause unexpected and undesirable effects
when the report is printed.

Table 2 - Simple band types

Band type Purpose


Page Header The first band usually printed on all pages. Whether
it is printed on the first page printing is governed by
the report’s Options.FirstPageHeader property. The
default is to print the first page header.
Title A title band is the first band printed to a report (after
the very first page header, if any). It’s useful for
printing the report title, data selection criteria,
creation date and time and so on.
Column Header The column header band is printed on top of each
report column. In a regular single column report, this
band is printed once per page, following the page
header (and the title band for the first page). In a
multi column report it’s printed once for each
column. It’s most useful for printing field names.
Detail One detail band is printed for each record (row) of
data in your dataset. This is perhaps the most
important band in your report and is usually what
takes most of the space on the final output. You
would typically put data-aware printable controls
such as TQRDBText on this band.
Summary After all detail bands has been printed you can print a
summary band. This is often used for printing totals
of numeric fields.
Page Footer The last band printed on all pages. Last page printing
is governed by the report’s Options.LastPageFooter
property. The default is to print the last page footer.

As you add new bands to a report, you will notice that they automatically position
themselves in the actual printing order. You will see that the Page Header band is on top,
followed by the Title band, column header band and so on, as shown in Figure 10 below.
Figure 10 - Simple band types

Each band has its band type printed in small letters in its lower left corner. This allows you
to identify the bands while designing the report. This text is not printed on the final report.
Bands appear on the TQuickRep component in the order in which they are printed. It is
helpful to understand why the bands line up the way they do. Generally bands will print in
at the frequency shown in Figure 10, although things become more complicated when you
start to add sub details and group bands.
Sizing the bands
Bands derive their horizontal size from the containing TQuickRep object. Their Size.Width
properties should be considered read only; values written to them are ignored. For a single
column report, the width of all bands is set to the page width minus the left and right
margins. In multi-column reports, the width of certain band types (Column Header, Detail,
Sub Detail, Group Header and Group Footer) is adjusted to reflect the width available for a
single column.
However you can adjust the vertical size of the bands. Select a band and resize it with the
mouse in the usual way or, if you want more accurate control, setting an exact value in the
Size.Height property.
Turning bands on and off
You might sometimes want to disable printing of a certain band. This can be done, either at
design time or at run time, by setting the TQRBand.Enabled property to False.
During report generation you can also temporarily disable printing of a band by creating an
event handler for the band’s BeforePrint event. This event handler takes a boolean parameter
PrintBand that can be set to False to disable band printing – but just for that single instance.
This feature can be used to perform simple filtering:
procedure TrepCusList.RepDetailBeforePrint
(Sender: TQRCustomBand;
var PrintBand: Boolean);
begin
PrintBand := CustTableTotalSales > 3000000;
end;

Note: When PrintBand is set to False for a detail band, the values for that record are not
included in any aggregate TQRExr function, for example the SUM function. This is a
behaviour change between QuickReport 2 and QuickReport 3.
If you turn off a Page Footer band, it will have the effect of leaving a blank space at the
bottom of each page – the Detail Bands will not expand to fill the space. To optimise
performance, QuickReport doesn’t check the length of the page footers all the time. So after
you change the Enabled property of your Page Footer, call the report object’s
ResetPageFooterSize method to force QuickReport to update its page footer information.
Groups
Groups allow you to generate extra bands between groups of records. For example, if you
were listing an address book, you might wish to group all the contacts whose name began
with the same capital letter, and to print that letter in large type above each group – in fact
this is what we do in the example.
To create a group:
11 Create a simple report as described in ‘A first report’ above.
12 Set the IndexName property of the TTable component to ‘ByCompany’.
13 Drop a TQRGroup component onto an existing TQuickRep object, where it appears
as a new band. This band will be the group header. Every time the group ‘breaks’, this
band will be printed.
14 Set the Expression property to

COPY(Table1.Company, 1, 1)

This extracts the first character from the ‘Company’ field.


15 Drop a TQRExpr control onto the header band. Set its Expression property to the
same value:

COPY(Table1.Company, 1, 1)

In addition you can also add a group footer band. Although we don’t really need one here,
we’ll make one for practice.
16 Select the TQRBand component on the palette and drop it on the report. Rename it
to FooterBand1.
17 Click on the group header band once more. Set the TQRGroup.FooterBand
property to FooterBand1.
18 Drop a TQRLabel onto the footer band. Set its Caption property to ‘FOOTER’.

If all has gone to plan, you should be looking at something like Figure 11:
Figure 11 - Creating a group

Now preview the report, either by running the program, or simply right-clicking on the
report object and choosing Preview:
Figure 12 - Preview of a grouped report

As expected, the resulting report shows a list of all the companies grouped in alphabetical
order, with each group headed by a line showing the current letter.
Master/detail reports
You will very often wish to create a master/detail report – that is one where you are
extracting data from two datasets connected by a master/detail relationship. QuickReport
allows you to include one or more such relationships in a report using TQRSubDetail
components.
An obvious example of a master/detail report is to list out all the orders associated with
each customer in a database. Here is a quick example:
19 Start with the group report as created in the previous section.
20 Drop a TDataSource component on the form, and make its DataSet property
‘Table1’.
21 Drop a new TTable component on the form. Set its DatabaseName property to
‘DBDemos’, TableName to ‘ORDERS.DB’, IndexName to ‘CustNo’, MasterSource to
‘DataSource1’, MasterFields to ‘CustNo’ and Active to True. The two TTable
components are now set up in a master/detail relationship.
22 Drop a TQRSubDetail component onto the existing TQuickRep object, where it
appears as a new band. Notice that its Master property is automatically set to QuickRep1.
The master/detail relationship between the two TTable objects is mirrored between the
report object and its sub detail band.
23 Set the TQRSubDetail component DataSet property to ‘Table2’. The TQRSubDetail
component iterates all through its DataSet for each change in the Dataset of its Master.
24 Drop three TQRDBText components on the sub detail band. Set their DataSet
properties to ‘Table2’, and set the DataField properties to ‘OrderNo’, ‘SaleDate’ and
‘ItemsTotal’ respectively.

If you have done all that correctly, you should now be looking at something like Figure 13
below.
Figure 13 - Creating a report with sub detail

Now preview the report. The result will look like Figure 14, with each customer’s orders
listed below the customer name. Note that the format of the date and currency fields
depends on Windows’ international settings. Mine are set to British, your mileage will
obviously vary.
Figure 14 - Preview of a master/detail report
More about printable components
By now, you will have a feel for QuickReport’s printable components – use them like
ordinary controls to define you layout. However, there are a few QuickReport-specific
things to learn about them.
Text components
QuickReport’s printable text components – TQRLabel, TQRDBText, TQRExpr, TQRSysData,
TQRMemo, TQRExprMemo, TQRRichText and TQRDBRichText – share some common
properties, which they inherit from a parent, class:
Table 3 - Text component properties

Property Purpose
AlignToBand By default components will print/align at the position
set in the designer. But sometimes it is more practical
to align components to the vertical edges of the band
that it is placed on. When AlignToBand is True, a
text components will align itself relative to its parent
band instead of its own text rectangle.
AutoSize Set this property to True and a component sizes itself
horizontally to fit whatever text is put into it.
AutoStretch If AutoStretch and WordWrap are both True, a
component can expand vertically to accommodate its
text. When a component expands in this way it also
expands its parent band, provided that band’s
CanExpand property is set to True. A band can
expand over multiple pages if necessary.
Note that if a component expands it will not move
other components on the same band down. If you
have components whose desired position should
depend on the length of a stretching text, you should
place these in a child band.
Note also that this property cannot be used for
components on any band that prints at the bottom of
the page. This is typically the page footer, but also
applies to any band that has had its AlignToBottom
property set to True.
Frame All text components can display a visible frame
around them. This property controls the appearance
of the frame, which sides it is drawn on and so on.
Size All printable components share the Size property. If
AutoSize is False you can use this property to set the
exact size of the component. This property also
contains the position of the component relative to its
parent band.
WordWrap If WordWrap is set to True text can span multiple
lines.

Formatting fields
TQRDBText components use any formatting options defined for the field to which they are
connected. Sometimes, however, you need to customise the display of a particular value;
this can be achieved using TQRDBText’s Mask property. This takes the same values as
Delphi’s own FormatFloat function (for numeric fields) and FormatDateTime function (for
date and time fields) – in fact, QuickReport itself calls these functions to do the work. To
give you an example, suppose you wished to print out a numeric value to two decimal
places, with the thousands separated by a comma, and negative values shown (in
parentheses) in the style favoured by accountants. Then you could use a Mask like this
#,##0.00;(#,##0.00)
which would cause the values
1234 and -1234.5
to be printed as
1,234.00 and (1,234.50)
respectively.
Check out the Delphi help for FormatFloat and FormatDateTime for details and more
examples.
To specifically set a formatting of a field use the Mask property. The mask works
differently for different field types.

Using expressions
QuickReport includes an advanced expression evaluator, used by the TQRExpr,
TQRExprMemo and TQRGroup components. Expressions can be used to combine and
manipulate database fields, and perform advance formatting. Their syntax is rather like that
of Object Pascal: the expressions can be of boolean, float, integer or string type. Note that
date and time fields are converted into strings, and BLOB and memo fields are not
supported in expressions.
The evaluator supports the usual set of operators:
Table 4 - Operators supported by the expression evaluator

Operators Function
+ Addition, string concatenation
- * / Subtraction, multiplication, division
() Parentheses
And Or Not Logical operators
= < > Comparison operators
<= >= <>

and a set of standard functions:


Table 5 - Functions supported by the expression evaluator

Function Description
AVERAGE(EXPR) Aggregate function. Averages the EXPR
COPY(STR,S,L) Returns a sub string of STR starting at
character S length L
COUNT Aggregate function. Returns the number of
iterations of the Master band.
DATE Return current date as a string
DIV(X, Y) Integer division of X by Y
FALSE Logical value False
FORMATNUMERIC(F, N) Format numeric N using string mask F. The
mask takes the values as Delphi’s
FormatFloat function.
FRAC(NUM) Returns the fractional part of a NUM
IF(EXPR, R1, R2) Returns R1 or R2 depending on the boolean
EXPR
INT(NUM) Returns the integer part of NUM
LOWER(STR) Returns STR in lowercase
MAX(EXPR) Aggregate function. Returns the highest
value of EXPR
MIN(EXPR) Aggregate function. Returns the lowest
value of EXPR
PRETTY(STR) Returns STR in ‘pretty’ case, ie first latter
in uppercase, the remainder lowercase
SQRT(NUM) Returns the square root of NUM
STR(NUM) Converts NUM to a string
SUM(EXPR) Aggregate function. Returns the sum of
EXPR
TIME Return current time as a string
TRUE Logical value True
TYPEOF(EXPR) Returns the data type of EXPR as a string,
eg ‘BOOLEAN’
UPPER(STR) Returns STR in uppercase

If your expression includes aggregate functions like SUM or COUNT you must link the
Master property to the component, TQuickRep or TQRSubDetail that will be used to update
the expression. For a simple report this is your TQuickRep component, but in a complicated
report with many datasets you must take care to link to the correct TQRSubDetail. The
expression is recalculated each time the record pointer of the linked master is advanced.
The ResetAfterPrint property is also useful when working with aggregation functions, and
allows you to create, for example, group totals as well as running totals.
The expression builder
To make it easier to create expressions for your reports, QuickReport includes a special
property editor, which appears when you click the ‘…’ button. This is shown in Figure 15.
Figure 15 - Expression builder dialog

The expression builder lets you design your expression by selecting functions and field
names from lists – so it makes it a lot easier to avoid typos in identifier names. It also
brings up special dialogs to prompt for function arguments.
Figure 16 - Setting function arguments in the expression builder

Creating a default custom preview


We mentioned back in the ‘Previews and composite reports’ section that it was possible to
change the default preview mechanism. It is time to look at how this is done.
The first step when creating a custom default preview is to derive a new class from
TQRPreviewInterface, like this:
// use QRPrntr to get TQRPreviewInterface

TQRCustomPreviewInterface = class(TQRPreviewInterface)
public
function Show(AQRPrinter : TQRPrinter)
: TWinControl; override;
function ShowModal(AQRPrinter : TQRPrinter)
: TWinControl; override;
end;

Notice that this is an interface1 class – it serves only to define a couple of functions, and has
no data of its own. These two functions are implemented to construct and display your
custom preview in non-modal and modal forms.

1
We have not used Delphi’s interface keyword to define these classes because this is not currently common practice, and many
Delphi programmers are unfamiliar with the syntax. However, the concepts are very similar.
Lets suppose that the preview form is going to be called TCustPreview. Then the
implementation of the TQRCustomPreviewInterface methods might look like this:
function TQRCustomPreviewInterface.Show(
AQRPrinter: TQRPrinter): TWinControl;
var
frm : TCustPreview;
begin
frm := TCustPreview.Create(Application, AQRPrinter);
frm.Show;
Result := frm;
end;

function TQRCustomPreviewInterface.ShowModal(
AQRPrinter: TQRPrinter): TWinControl;
var
frm : TCustPreview;
begin
frm := TCustPreview.Create(Application, AQRPrinter);
frm.ShowModal;
Result := frm;
end;

To register our alternative previewer, we need to call the RegisterPreviewClass function,


which is in the QRPrntr unit. The call looks like this:
RegisterPreviewClass(TQRCustomPreviewInterface);

Now we are done with the glue code, and can build the actual previewer form. Mine is
minimal; just a single TQRPreview control stuck onto a form:
Figure 17 - Simple preview form

When you do real previews in your applications, you will probably want to add buttons to
call TQRPreview’s Zoom method and other facilities.
To support the previewing mechanism, I had to write a little more code. Here is the
declaration of TCustPreview. Notice I have added a new constructor, which expects to
receive the TQRPrinter argument passed in by the Show and ShowModal methods of the
interface class. Delphi generates a warning message that the new constructor hides the
original. In this case it is deliberate, so I have wrapped the class in
{$WARNINGS ON} ... {$WARNINGS OFF}
compiler directives to make it shut up.
{$WARNINGS OFF}
TCustPreview = class(TForm)
QRPreview1: TQRPreview;
procedure CustPreviewClose(Sender: TObject;
var Action: TCloseAction);
private
{ Private declarations }
fQRPrinter : TQRPrinter;
public
{ Public declarations }
constructor Create(AOwner : TComponent;
AQRPrinter : TQRPrinter); virtual;
end;
{$WARNINGS ON}

Finally, here is the implementation of the class. Notice in particular the cleanup code held
in the form’s OnClose event. If you don’t call ClosePreview here, you will get a nasty
memory leak. (QuickReport 2 users should note that this is a new requirement. You must
modify your existing preview forms when porting them to QuickReport 3 and later.)
constructor TCustPreview.Create(AOwner: TComponent;
AQRPrinter: TQRPrinter);
begin
inherited Create(AOwner);
fQRPrinter := AQRPrinter;
QRPreview1.QRPrinter := AQRPrinter;
end;

procedure TCustPreview.CustPreviewClose(Sender: TObject;


var Action: TCloseAction);
begin
fQRPrinter.ClosePreview(Self);
Action := caFree;
end;
Further resources
There are many other resources available to you, to help you make the most of QuickReport
in your Delphi applications.
Help files. The QuickReport help files are installed and integrated with Delphi’s own help.
As well as context-sensitive Reference for components and properties, there are also
extensive User Guide and Knowledge Base sections. Since they don’t appear in the main
Help contents, it’s easy to overlook these, so if you get stuck or need to know more,
remember to fire up QuickReport help from its Start menu shortcut.
Demo applications. You’ll find these in the
Program Files\Borland\Delphi5\Demos
directory. The project Quickrpt\Qr3\qr3demo.dpr contains lots of examples of
different kinds of report. Start here if you want to exploit QuickReport’s fancier features,
like export filters. Also see the project Db\Mastapp\mastapp.dpr contains a good
example of QuickReport being integrated into a larger application.
Templates and wizards. Again often overlooked – the standard Delphi repository includes
templates for Master/detail, Labels and List reports, plus a report building wizard. Take File
| New in the Delphi IDE and have a look at the Forms and Business tabs.
Website. Our website is http://www.qusoft.com Please come and check it out to find more
examples, updates, tips and add-ons.

Potrebbero piacerti anche