09 enero 2009

Creación de informes con QuickReport (II)

Después de crear nuestro primer informe con QuickReport vamos a hacer otro a dos bandas el cual va a ser un listado de clientes. En un listado cualquiera necesitamos que la banda superior se mantenga fija en todas las hojas que se impriman y que la banda que va a imprimir lo datos se adapte al folio según los mismos.

CREANDO UN LISTADO SIMPLE A DOS BANDAS

Para cumplir nuestro cometido vamos a crear un nuevo formulario llamado FListadoClientes y dentro del mismo volvemos a añadir el objeto de la clase TQuickRep que llamaremos Informe.

Como necesito imprimir columnas bien anchas entonces debemos imprimir el folio de manera apaisado. Esto se hace pinchando el objeto QuickRep con el botón derecho del ratón y seleccionando Report Settings:


Y aparecerá este cuadro de diálogo:


Como puede verse en la imagen no sólo podemos seleccionar el tipo de folio (A4, A5, B4, etc.) sino que además se puede configurar el folio a un ancho y alto determinado en milímetros que viene muy bien para formatos de documentos que se imprimen en impresoras matriciales con papel continuo (lo más asqueroso para un programador).

En la parte derecha de esta ventana tenemos un ComboBox que por defecto tiene seleccionada la opción Portrait. Esto significa que va a imprimir el folio verticalmente. Como lo vamos a imprimir apaisado seleccionamos LandScape.

Ahora añadimos al objeto TQuickRep un par de bandas (TQRBand) y a la segunda banda le podemos mediante el inspector de objetos a su propiedad BandType el valor rbDetail:


También es buena costumbre ponerle nombre a las bandas para luego poder modificar sus acciones mediante código. A la primera banda le ponemos en su propiedad Name el nombre Cabecera y a la segunda banda la llamamos Detalle.

Insertamos etiquetas en la cabecera mediante objetos TQRLabel y los campos en el detalle mediante TQRDBText:


Al igual que hicimos en el artículo anterior debemos vincular este formulario a la unidad donde están los dados (uses Unit1) y añadir en la propiedad DataSet del objeto TQuickReport la tabla Clientes.

Hay que procurar que la banda de Detalle tenga la altura ajustada a los campos a imprimir, para que la separación de las líneas no sea muy grande y no se desperdicien folios (algunos jefes de empresas son muy tacaños).

Creamos el formulario del informe y lo ejecutamos desde la ventana principal:

Application.CreateForm( TFListadoClientes, FListadoClientes );
FListadoClientes.Informe.Preview;

Al ejecutar nuestro informe ya lo tendremos apaisado:


INFORMES MAESTRO/DETALLE A TRES BANDAS

El siguiente ejemplo que vamos a ver es la impresión de una factura que tiene cabecera, detalle y pie así como los datos de un cliente que viene de otra tabla, es decir, vamos a imprimir datos de tres tablas a la vez.

Como en los casos anteriores creamos un nuevo formulario llamado FImprimirFactura e insertamos el objeto TQuickRep y lo llamamos Informe.

Para este ejemplo voy a añadir al formulario principal un nuevo objeto TClientDataSet llamado Facturas con los siguientes campos:


Esta sería la cabecera de la factura. Ahora creamos otro ClientDataSet para el Detalle de la factura con estos campos:


Introducimos una factura en la tabla con un par de líneas de detalle:

Facturas.Append;
Facturas['ID'] := 1;
Facturas['FECHA'] := Date;
Facturas['IDCLIENTE'] := 1;
Facturas['BASEIMPONIBLE'] := 300;
Facturas['IVA'] := 48;
Facturas['TOTAL'] := 348;
Facturas.Post;

Detalle.Append;
Detalle['IDFACTURA'] := 1;
Detalle['UNIDADES'] := 1;
Detalle['ARTICULO'] := 'MOVIL SAMSUNG';
Detalle['PRECIO'] := 100;
Detalle['TOTALLINEA'] := 100;
Detalle.Post;

Detalle.Append;
Detalle['IDFACTURA'] := 1;
Detalle['UNIDADES'] := 1;
Detalle['ARTICULO'] := 'MOVIL NOKIA';
Detalle['PRECIO'] := 200;
Detalle['TOTALLINEA'] := 200;
Detalle.Post;

A continuación creamos un nuevo formulario llamado FImprimirFactura e insertamos un objeto TQuickRep con tres bandas:


A las bandas las vamos a llamar Cabecera, Detalle, Pie y serán del tipo (BandType) rbTitle, rbDetail y rbPageFooter respectivamente.

Como hicimos en ejemplos anteriores, vinculamos a formulario con el formulario principal para poder traernos los datos de las tablas (uses Unit1). Seleccionamos el objeto TQuickRep y vinculamos mediante la propiedad DataSet la tabla Detalle.

Aunque pueda parecer extraño, cuando vamos a imprimir un documento maestro/detalle debemos vincular a la propiedad DataSet del objeto TQuickRep la tabla Detalle y no la del maestro. Esto se debe a que es el detalle la banda que se va a repetir en la factura, es decir, el centro de la misma. La cabecera y el pie son sólo datos adicionales. Eso no quita que luego cada campo se vincule con una tabla distinta. No hay limitaciones a la hora de vincular campos con tablas.

Pero vayamos por partes. Primero implementamos la cabecera de la factura en la primera banda:


Los campos ID y FECHA están vinculados con la tabla FACTURAS. En cambio todos los campos encerrados en el rectángulo están vinculados con la tabla CLIENTES (sólo hay que procurar tener filtrado que FACTURA.IDCLIENTE = CLIENTES.ID).

Lo demás son todo etiquetas TQRLabel. El rectángulo y las líneas que he puesto debajo de los títulos de los campos del detalle lo he hecho con un objeto TQRShape que en su propiedad Shape soporta estos formatos:

qrsRectangle: Un rectángulo.
qrsCircle: Un círculo.
qrsHorLine: Línea horizontal.
qrsVerLine: Línea vertical.
qrsRoundRect: Rectángulo con las esquinas redondeadas.
qrsRightAndLeft: dos líneas verticales (un rectángulo sin techo ni suelo).
qrsTopAndBottom: dos líneas horizontales (un rectángulo sin paredes).

En mi formato de factura sólo he utilizado líneas horizontales y un rectángulo.

Vamos ahora con el detalle de la factura en la segunda banda:


Esta banda sólo va a contener campos TQRDBText vinculados a la tabla DETALLE. Es importante quitar en este tipo de campos el valor Autosize y ajustar el ancho manualmente para que por ejemplo el nombre del artículo no chafe el precio en el caso de que el nombre sea demasiado largo.

También es importante que todos los campos de tipo float estén alineados a la derecha mediante su propiedad Alingment = taRightJustify.

Hay que procurar que la altura de la banda de detalle sea un poco más grande que la altura de los campos para que el espacio entre líneas no sea ni muy ancho ni muy estrecho.

Vamos con la última banda, el pie:


Esta banda sólo contiene los tres campos que totalizan la factura y que están vinculados con la tabla FACTURAS. Un detalle que hay que tener presente es que la posición vertical a la que van a salir estos totales es inversamente proporcional a la altura de la banda de tipo rbPageFooter, es decir, si queremos que los totales salgan más arriba hay que ampliar verticalmente la altura de esta banda. Y si queremos que los totales salgan pegados en la parte inferior del folio entonces hay que procurar que esta banda sea lo más estrecha posible (verticalmente).

Este seria nuestro diseño de la factura:



Llamamos a la vista previa como siempre:

Application.CreateForm( TFImprimirFactura, FImprimirFactura );
FImprimirFactura.Informe.Preview;

Y esta sería la vista previa al imprimirla:


Esta sería la parte superior:


Y la parte inferior:


También sería recomendable que los campos que vamos a imprimir de tipo moneda tengan definida su máscara a dos decimales para evitar problemas de redondeo. Esto se hace en el diseño de la tabla original a través de la propiedad DisplayFormat:


De modo que al imprimir aparezcan los dos decimales:

Estos tres ejemplos que hemos visto son los tres típicos informes que nos suelen pedir: un formulario, un listado o un documento maestro/detalle (y pie). Aunque aquí no se acaban nuestras pesadillas ya que esto solo son juguetes comparado con lo que los clientes suelen pedir de verdad.

En el próximo artículo veremos casos más complejos y algunos truquillos para modificar el aspecto del informe en tiempo real.

Pruebas realizadas en RAD Studio 2007.

9 comentarios:

estrellita dijo...

Hola, soy nueva con esto de delphi...
Me ha gustado mucho la explicacion en las dos publicaciones y me han sido de gran ayuda, estare esperando con mucho entusiasmo el proximo articulo que Creo que va hacer muy interesante...

Saludos,
Lilo

Anónimo dijo...

Hola, soy nueva con esto de delphi...
Me ha gustado mucho la explicacion en las dos publicaciones y me han sido de gran ayuda, estare esperando con mucho entusiasmo el proximo articulo que Creo que va hacer muy interesante...

Saludos,
Lilo

Anónimo dijo...

hola, yo estoy usando c++builder6 pero la explicacion en delphi es estupenda y me ha servido de gran ayuda, sin embargo, aunque relleno un componente del tipo TClientDataSet con diferentes datos, cuando intento visualizarlo en el QuickReport (version 3.0.9) solo me aparece una fila de la tabla y no la tabla entera usando una capa del tipo detail.
Muchas gracias y
enhorabuena por por esta pagina que es muy interesante.

Administrador dijo...

Eso que te pasa con la tabla es porque no tienes vinculada esa tabla al objeto TQuickRep.

Tienes que vincular a la propiedad DataSet del objeto TQuickRep la tabla cuyos datos van a mostrar muchos registros.

También acuerdate de poner la banda de tipo detalle.

Saludos.

Anónimo dijo...

fantastica su explicacion me fue de suma ayuda aplrendi bastange muchas gracias

Tech Underground News dijo...

hola Maestro, yo de nuevo por estos lugares. te agradezco por la ayuda prestada hace ya algunos años y felicidades por haber continuado entregando tan buen material de forma gratuita.

tengo problemas usando quickreport con ado y una database en dbf. lo del linkeo y las querys lo tengo listo (al momento de poner en el dataset me reconoce mi adoquery1 y en datafield aparecen los campos que quiero mostrar. pero al momento de compilar me aparece, la operacion no esta permitida en este contecto, (error leyendo adoconnection1). seguire intentando por ahora.

pd: el adoconnection1 esta bien , lo e usado para llenar db grids, agregar y quitar datos. no se que pueda ser en realidad. e echo todo desde 0 4 veces.

haber si me puedes echar un cable.
gracias :D

Administrador dijo...

Siento no poder ayudarte, pero por mi parte considero el protocolo ADO y los archivos de bases de datos DBF como algo obsoletos.

Lo más que hice en los comienzos del Delphi fue una base de datos Paradox con DBE y en cada corte de electrícidad se rompían los índices.

Deberias pensar en mejorar tu acceso a datos. Te recomiendo como motor de bases de datos Firebird y como componentes de acceso IBX o DBX.

Saludos.

Tech Underground News dijo...

muchas gracias por tu respuesta. migraré a firebird o MySQL. :)

Unknown dijo...

Hola uso delphi 7 y al crear el reporte quiero mostrar cinco campos y solo me muestra un solo campo y abarca gran parte de la hoja.....Gracias

Publicidad