Impresion en Delphi
Impresion en Delphi
Impresion en Delphi
Hay dos formas principales de imprimir en Delphi: utilizando un motor de impresin -generalmente orientado a reportes de bases de datos, como Report Smith, Quick Report o Crystal Reports- o enviando los datos directamente al driver de la impresora. Veremos aqu los dos mtodos. Es tarea del programador determinar cuando es conveniente usar un reporte o generarlo a mano. Los dos mtodos tienen puntos a favor y en contra. En general, podemos decir que para reportes simples o sobre pocos datos es preferible el enfoque directo por la velocidad de respuesta -es simplemente irritante cuando para obtener tres lneas impresas debemos esperar que se cargue el Report Smith, y despus seguir esperando a que se descargue. En cambio, cuando la consulta sea complicada, implique grficos, muchos datos, un formato especial de la pgina o cosas as, valdr la pena la espera.
NOTA: en las versiones de 32 bits, Delphi provee un paso intermedio al Report Smith llamado Quick Report (en Delphi 3 ni siquiera viene incluido el Report Smith). Compuesto de varios componentes VCL, se integra en el ejecutable proveyendo facilidad de programacin de reportes complejos con poca sobrecarga. Incluso hay una versin para Delphi 1, que se puede conseguir en el sitio WEB de QuSoft: http://www.qusoft.com.
Por supuesto, el ltimo y definitivo determinante del mtodo a utilizar ser... el usuario final.
Tengamos en cuenta que si no utilizamos un motor, cualquier subida parece ms alta. Entonces por qu no utilizar uno? Principalmente, por la sobrecarga que imponemos al sistema. Al momento de comenzar a imprimir, Delphi debe cargar en memoria los mdulos que componen el reportero; esto no slo limita los recursos disponibles sino que tambin demora ms. Y a veces el resultado no justifica la espera. Cualquiera que haya utilizado Report Smith para hacer reportes sabe bien lo que estamos diciendo.
La impresin en Windows se hace a travs de funciones de la GDI (Graphics Device Interface), que se encarga de ejecutar los comandos correspondientes al dispositivo especfico que producir la salida. Es como tener un subordinado a quien le decimos lo que queremos que haga, y que lo haga como pueda. Asi que pueden sentirse un poco jefes... hasta que empiecen los problemas, que nunca faltan. Es parte del trabajo.
Cuando enviamos algo a la impresora, Windows se encarga de arrancar el Administrador de Impresin. Delphi define una clase para tratar con la impresin, otro intermediario ms para hacer las cosas an ms fciles. Esta clase se denomina TPrinter y est definida en la unit Printers, que debemos agregar manualmente a la clusula uses.
Hay una forma fcil de enviar texto a la impresora: crear un archivo de texto y redireccionarlo al puerto de la impresora. A partir de entonces se puede escribir directamente utilizando los procedimientos estndar Write y Writeln; el tipo de letra, tamao, espaciado, etc. son los seleccionados en la propiedad font del canvas de Printer. Slo debemos escribir como hacamos en DOS (que poca...). Para asociar un archivo de texto a la salida de impresora se utiliza el procedimiento AssignPrn1. Notemos que debemos crear el archivo con rewrite antes de empezar a imprimir, y cerrarlo al terminar. Ejemplo 1: imprimir el contenido de un memo en la impresora con el mismo tipo de letra de pantalla.
Se debe agregar la unit Printers a la clusula uses para tener acceso al procedimiento AssignPrn. 2
procedure TForm1.Button1Click(Sender: TObject); var t:TextFile; i: integer; begin AssignPrn(t); rewrite(t); try Printer.Canvas.Font:= Memo1.Font; for i:= 0 to Memo1.Lines.Count-1 do writeln(t,memo1.lines[i]); finally CloseFile(t); end; end;
Creamos una aplicacin muy sencilla; el form principal puede verse en la fig. 1 y el listado del evento OnClick del botn Imprimir en el listado 1. Note la utilizacin de un bloque de proteccin de cdigo try..finally para asegurarnos que se libere la salida estndar aunque se produzcan errores en la impresin. El tema de los errores se tratar en el captulo de Excepciones. De esta manera se puede imprimir fcilmente un texto.
Delphi provee una clase para facilitar el acceso directo a la impresora. En las primeras versiones se define una variable global, instancia de la clase Tprinter; en la versin 3 esta variable se hace local a la unit printers y se define en cambio una funcin llamada Printer. De esta manera se puede seguir usando la misma sintaxis. Tambin en esta ltima versin se agrega una funcin llamada SetPrinter que sirve para cambiar el objeto de impresora global, pudindose definir varias instancias con diferentes parmetros. Bueno, entonces la situacin es la siguiente: tenemos una tarea que llevar a cabo -la impresin propiamente dicha- un brazo ejecutor de nuestras rdenes -la GDI- y un intrprete que traduce nuestro idioma de Delphinianos al lenguaje de funciones que entiende Windows -la instancia de la clase TPrinter. Por lo tanto, slo tenemos que aprender las capacidades de esta ltima clase para lograr los resultados apetecidos. Y esto implica, como con cualquier clase, hablar de Propiedades y Mtodos.
Propiedades de Tprinter
La propiedad principal de la clase tPrinter es el Canvas. Se utiliza de la misma manera que el canvas que contienen los objetos grficos de la VCL -de hecho, es una instancia de la misma clase. Por lo tanto podemos utilizar las mismas rutinas grficas (mtodos de Tcanvas). No obstante, hay algunas diferencias con la salida de pantalla:
1. El plano sobre el que se miden las coordenadas de impresin es mucho ms variable que el de un dispositivo de video; se hace necesario contar con alguna forma de interrogar a la impresora sobre su resolucin, tamao de pgina, en general sobre sus capacidades. Esto puede lograrse a travs de una funcin de la API denominada GetDeviceCaps .
2. No hay garanta de que la impresora pueda recibir grficos; los mtodos de impresin de grficos como Draw, StretchDraw o CopyRect pueden fallar.
Otras propiedades de inters son las que indican las dimensiones de la pgina: PageHeight (altura en pixels) y PageWidth (ancho en pixels). Un resumen de las propiedades de la clase Tprinter se da en la tabla siguiente:
Propiedad Aborted Canvas Capabilities (slo 32 bits) Copies (slo 32 bits) Fonts Handle Orientation PageHeight PageNumber PageWidth PrinterIndex
Significado TRUE cuando el usuario ha cortado la impresin antes de terminar Superficie de graficacin de la pgina Indica capacidades de la impresora seleccionada: orientacin, nmero de copias, intercalar copias. Permite indicar o consultar el nmero de copias.
Lista de las fuentes soportadas por la impresora Manejador del contexto de dispositivo. Orientacin del papel:
poPortrait, poLandscape
Altura del canvas en pixels Nmero de pgina actual Ancho del canvas en pixels Indice de la impresora seleccionada en la propiedad Printers 4
Significado Lista de las impresoras instaladas en Windows (Strings) Indica cuando un trabajo de impresin est en curso. Es puesta a True por el mtodo BeginDoc y a False por EndDoc. El ttulo del trabajo de impresin en el Administrador de Impresin
Mtodos de Tprinter
Funcin Llamando a este procedimiento se detiene un trabajo de impresin en curso Este mtodo debe ser llamado siempre antes de comenzar a imprimir. Este mtodo termina un proceso de impresin. Devuelve la impresora actualmente en uso. No es necesario llamar a este mtodo directamente, es ms fcil acceder a la propiedad Printers. Inicia una nueva pgina. Incrementa el contador de pginas, pone la pluma en las coordenadas (0,0) y enva un cdigo Form Feed a la impresora. Especifica la impresora a usar. No es necesario llamar a este mtodo directamente, es ms fcil acceder a travs de las propiedades Printers y PrinterIndex.
Podemos esquematizar el proceso de imprimir usando este objeto en los siguientes pasos:
1) Iniciar el proceso de impresin llamando a Printer.BeginDoc 2) Dibujar el texto (TextOut) o grficos (Rectangle, Ellipse, LineTo, etc) en el canvas de Printer teniendo cuidado de las coordenadas; posiblemente sea necesario utilizar las propiedades PageHeight y PageWidth. 3) Cuando termina una pgina (por ejemplo, cuando la lnea siguiente se imprimira en una coordenada Y mayor que PageHeight) llamar a Printer.NewPage para comenzar una nueva pgina en blanco. 5
Nota: normalmente, cuando se est imprimiendo se muestra una ventana con un botn que permite la cancelacin del trabajo; se debe llamar al mtodo Printer.Abort. Veamos el trabajo con el objeto Printer en un ejemplo: imprimir los datos de un registro de una tabla, incluida una foto. Utilizaremos la tabla CLIENTS.DBF que viene con los ejemplos de Delphi y colocaremos algunos de los campos en un form como el de la figura 2. La foto necesita un tratamiento especial: el campo Picture de la tabla contiene el nombre del archivo .BMP, que se encuentra en el mismo directorio que la tabla. Para mostrarlo utilizamos un componente tImage comn, al cual tenemos que decirle que cargue la imagen correspondiente cada vez que nos paramos en un registro nuevo. Para ello utilizaremos el evento OnDataChange del DataSource, que se produce cada vez que cambian los datos que accede. El cdigo se ve en el listado 2.
Cuando vamos a imprimir, necesitamos algunos clculos para posicionar los textos y la foto; una forma simple sera la indicada en el listado 3, que hace uso de la funcin GetTextHeight del canvas para determinar la altura de una lnea de texto y le agrega 5 pixels para conseguir una separacin entre lneas adyacentes. La imagen se redimensiona para que ocupe 1000x1000 pixels en una quinta lnea.
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField); begin Image1.Picture.LoadFromFile(Table1.DatabaseNa me+ '\'+Table1Picture.AsString); end;
procedure TForm1.Button1Click(Sender: TObject); var i,tg:integer; begin Printer.BeginDoc; try Table1.First; tg:= Printer.Canvas.TextHeight('tg')+5; //5 pixels de separacion entre lineas for i:= 0 to 0 do begin with Printer.Canvas do begin TextOut(10,tg*i*6,table1Last_Name.DisplayLabel); TextOut(600,tg*i*6,Table1Last_Name.AsString); TextOut(10,tg*(i*6+1),table1First_Name.DisplayLabel); TextOut(600,tg*(i*6+1),Table1First_Name.AsString); TextOut(10,tg*(i*6+2),table1Address_1.DisplayLabel); TextOut(600,tg*(i*6+2),Table1Address_1.AsString); TextOut(10,tg*(i*6+3),table1City.DisplayLabel); TextOut(600,tg*(i*6+3),Table1City.AsString); TextOut(10,tg*(i*6+4),table1ZIP.DisplayLabel); TextOut(600,tg*(i*6+4),Table1ZIP.AsString); StretchDraw(Rect(600,tg*(i*6+5),1600,tg*(i*6+5)+1000),Image1.Picture.Graphic); end; end; Printer.EndDoc;
Quick Report esta compuesto de una serie de componentes VCL que se deben instalar en Delphi 1; en las versiones de 32 bits viene incluido con el programa (no son hechos por Borland, estn licenciados a QuSoft). En febrero de 1998, la versin existente es la 2.0. El hecho que Borland lo entregue integrado con Delphi ya habla en favor de la calidad de estos componentes. Son realmente muy buenos y poderosos; casi se dira que no necesitaremos ms el Report Smith, y de hecho aqu ni siquiera hablaremos de este ltimo.
Los reportes creados con Quick Report se integran por supuesto con el ejecutable -despus de todo son componentes, no?, es decir que no necesitamos instalar nada extra en el equipo del cliente. Podemos hacer desde reportes muy simples hasta muy complicados, utilizando varias tablas, grficos y memos. Adems se puede mostrar una vista previa antes de imprimir. Y se rumorea que una prxima versin 7
Algunos componentes se encargan de manejar el reporte completo (de manera similar a los componentes de acceso de datos, que se encargan de las tablas o bases de datos completas) mientras otros son los controles imprimibles, los que ponen la informacin en la impresora (equivalentes de los Controles de Datos).
Los componentes de acceso que tenemos disponibles son los siguientes: Componente QuickRep Funcin Representa el reporte en s. Es el componente principal e indispensable. Contiene propiedades que controlan el tamao de pgina a imprimir, los mrgenes, etc. Banda de Sub Detalle, utilizada en reportes con tablas master/detail Banda del reporte. Las bandas ms comunes en un reporte se pueden colocar automticamente con la propiedad Bands del reporte. Banda de detalle que se estira en forma acorde con el contenido. Banda de agrupacin. Banda que permite combinar reportes. Componente que permite crear vistas previas especiales. Banda que toma los datos de una lista de Strings (Tstrings) en lugar de una Tabla.
Los componentes imprimibles son los siguientes: Componente QRLabel QRDBText Funcin imprime el texto que tenga en la propiedad Caption. Es equivalente al Label pero slo se ve en un QuickRep. imprime el contenido de un campo de una tabla, equivalente al DBText. Sirve tambin para imprimir campos Memo. El formato de la salida se toma del formato ya definido para el campo, o de la propiedad Mask de este componente. imprime el resultado de una expresin, ingresada en la propiedad expr. imprime informacin del sistema, como el nro de pgina o la fecha. imprime texto fijo que puede ocupar varias lneas. Equivalente al Memo.
Componente QRExprMemo QRShape QRImage QRDBImage QRRichText (slo 32 bits) QRDBRichText (slo 32 bits)
Funcin un memo con expresiones insertadas, que se evalan al momento de imprimir. imprime una figura geomtrica. Equivalente al Shape. imprime una imagen BMP, WMF o ICO. Equivalente a Image. imprime el contenido de un campo grfico de una tabla. Equivalente al DBImage. imprime texto con formato (Rich Text). Equivalente al RichEdit, se puede enlazar con un componente de stos para imprimir su contenido. imprime el contenido de un campo de texto con formato (Rich Text) de una tabla. Equivalente a DBRichEdit.
Existen adems, a partir de la versin 3 de QR, los llamados filtros de exportacin. Aunque se pueden crear otros, los ms comunes vienen incluidos y son los siguientes: Componente QRTextFilter QRCSVFilter QRHTMLFilter Funcin Permite exportar a un archivo de texto (.TXT) Permite exportar a un archivo delimitado por comas (.CSV) Permite exportar a un archivo HTML (.HTM)
Al agregar cualquiera de estos ltimos componentes a una ficha, aparecer la opcin correspondiente en el comando de grabacin de la vista previa. Veremos un ejemplo de exportacin por programa un poco ms abajo.
Para hacer un reporte con Quick Report necesitamos como mnimo los siguientes componentes: * una ficha que servir como soporte del reporte * un componente QuickRep * algn componente imprimible de Quick Report, como un QRLabel.
En nuestro pequeo ejemplo vamos a crear un form principal muy simple con dos botones, uno para cerrar la aplicacin y otro para mostrar la vista previa del reporte. Una posible versin de esta ventana se ve en la fig. 3:
En el evento OnClick del botn Salir hacemos que se cierre la aplicacin. No hacen falta ms explicaciones para esto, o si?. En el otro botn debemos pedir que se muestre la vista previa del reporte bsico.
Para aquellos de Uds. que lo hayan adivinado, tenemos que crear el reporte antes de usarlo. Y para ello necesitamos como ya dijimos un form y un componente QuickRep. Entonces vamos a agregar otra ventana a la aplicacin, en la cual pondremos solamente un componente QuickRep. En la fig. 4 se ve la ficha en tiempo de diseo.
Normalmente, no mostraremos en tiempo de ejecucin la ventana de un reporte en la pantalla; slo sirve como soporte para el diseo. En cambio debemos llamar a un mtodo del componente QuickRep: Preview para mostrar una vista previa en la pantalla o Print para imprimir directamente en la impresora. (Si alguno de Uds. quiere probar cmo se ve un form con un reporte en ejecucin, puede mostrarlo poniendo su propiedad visible en true. No es una vista muy edificante). Figura 4El form del reporte en diseo Veamos. En la ventana principal, asignamos el cdigo del listado 4 al evento OnClick del botn que nos permitir ver la vista previa. Al presionar este botn se nos presentar la ventana de vista previa que incluye por defecto el Quick Report (fig. 5). Desde 10
La verdad que imprimir una hoja vaca no era nuestro objetivo, no?. Agregamos entonces al reporte un componente QRLabel con el texto deseado en la propiedad caption del mismo. Ahora s, la vista previa nos muestra el texto y si enviamos esto a la impresora, saldr tal cual como se ve en pantalla.
Esta tcnica es una alternativa al acceso directo al dispositivo a travs de la clase tPrinter. No obstante, tenga en cuenta que el solo hecho de utilizar el Quick Report nos agrega una sobrecarga de cerca de 400 Kb. al ejecutable. Para imprimir una frase o algo relativamente simple, tal vez sea ms conveniente utilizar el mtodo anterior.
componente Memo o mejor an, de un archivo de texto. La banda de Cadenas se comporta como una banda de detalle, imprimindose una por cada lnea de texto. Estas lneas se almacenan en una propiedad llamada Items, de tipo Tstrings. Ahora bien, con qu componente mostramos el texto? La respuesta viene de la mano del componente QRExpr. Con l se puede acceder a las lneas individuales de texto de la banda de Cadenas: basta poner el nombre de la banda en la propiedad Expression del componente. Entonces, se nos prende la lamparita para resolver un viejo problema de una forma nueva: la impresin de un archivo de texto. Basndose en lo que dijimos anteriormente, trate de crear una aplicacin que lea un archivo de texto y lo imprima usando un reporte... antes de leer la solucin siguiente!
Usaremos una ventana como la de la figura ??? para seleccionar el archivo a imprimir. En otra ficha colocamos el reporte, con la banda de cadenas y un componente QRExpr para acceder a las cadenas del archivo. El botn de imprimir debe abrir el archivo de texto en la propiedad Items de la Figura 6la ficha principal del ejemplo banda de cadenas, y luego llamar al mtodo Preview del reporte. En la figura ??? se ve la ficha del reporte y en la figura ??? la vista previa del archivo WIN.INI.
Figura 8impresin del archivo WIN.INI NOTA: en las imgenes del ejemplo anterior se ve la banda de cadenas con un color distinto para resaltarla
Por ltimo, recordemos que tambin podemos poner a mano las lneas de texto que queremos escribir; simplemente agregamos (utilizando el mtodo Add) las lneas a la propiedad Items de la banda de cadenas. Se escribir una banda por cada lnea de texto. 12
Ahora comenzamos con el reporte. Agreguemos a la ventana principal un botn para hacer una vista previa, y en otro form ponemos un componente QuickRep, un label y un QRDBText enlazado con el campo nombre de la tabla (ser necesario indicar a Delphi que vamos a usar el DataModule con la opcin File|Use Unit). Fig. 7. Figura 10Ventana del reporte con los componentes ya colocados Pruebe la aplicacin. 13
No es lo que desebamos, no? Podemos ver que se muestra un solo valor -el ltimo de la tabla 2. Lo que es peor, la tabla queda en el ltimo registro como podemos ver en el form principal3. Para ver todos los registros ser necesario agregar bandas a nuestro reporte.
La divisin de un reporte en bandas no es algo nuevo; Access lo viene haciendo desde sus comienzos. El concepto es simple: una banda es una parte del reporte, que se imprime slo en un momento determinado. Por ejemplo, tenemos una banda de ttulo que se imprimir una sola vez al principio del reporte, bandas de encabezado de pgina que se imprimen al comienzo de cada nueva pgina, y asi. Los tipos de bandas disponibles y el momento en que se imprimen se ven en la tabla siguiente:
Tipo de banda Ttulo Page Header (encabezado de pgina) Page Footer (pie de pgina) Detail (detalle)
Momento de impresin Principio del reporte, despus del primer encabezado de pgina si est activa la opcin FirstPageHeader en Options del reporte. Al principio de cada pgina nueva. La opcin FirstPageHeader de la propiedad Options del reporte indica si se imprimir esta banda en la primera pgina del reporte. Al final de cada pgina. La opcin LastPageFooter de la propiedad Options del reporte indica si se imprime esta banda en la ltima pgina del reporte. Una vez por cada registro. Para que se imprima debe haber un enlace entre el reporte y un componente de acceso a datos como un Table, Query o StoredProc a travs de la propiedad DataSet del reporte. Se imprime al principio de cada columna. Es el lugar ideal para poner los ttulos de las columnas del detalle. Al final del reporte, antes del ltimo pie de pgina si est permitido (ver Page Footer) Al principio de un grupo. En la propiedad Expression se escribe la expresin que define el grupo; cada vez que cambia el valor de la expresin se inicia un nuevo grupo y se imprime esta banda. Al final de un grupo.
Column header (cabecera de columna) Summary (sumario, resumen) GroupHeader (cabecera de grupo) Group footer (pie de grupo)
Cuando se especifica una tabla en la propiedad DataSet del Reporte, ste siempre recorrer todos los registros de esa tabla. Si no usamos bandas, imprime el ltimo. Este ltimo problema tiene una solucin sencilla: utilizar otro componente Table o Query apuntando a la misma tabla 14
3
Ahora podemos crear nuestro reporte de la tabla, utilizando bandas. El objetivo es lograr un reporte como el de la fig. 8
Agregamos entonces un componente Query al form del reporte -usaremos uno diferente al que utilizamos para el form principal que muestra los datos en la pantalla. La instruccin SQL utilizada en este ejemplo es la siguiente:
Debemos enlazar la propiedad DataSet del reporte con este componente y activarlo para que funcione.
Ahora agregamos las bandas para lograr el resultado deseado. Necesitamos una banda para los ttulos y otra para los datos. Segn consta en la tabla, pondremos una banda tipo Column header para los Figura 11vista previa de un reporte utilizando una consulta SQL ttulos y una tipo Detail para los datos. Seleccionamos estas bandas en la propiedad Bands del reporte (fig. 9)
Figura 12el reporte en modo de diseo, con las bandas y componentes imprimibles ya situados.
Note que ya hemos ubicado un par de etiquetas -QRLabels- y una lnea horizontal -QRShape- en la banda de encabezados de columna, y los correspondientes QRDBText en la banda de detalle, para
15
mostrar el contenido de los campos indicados. En los componentes QRDBText debemos indicar el origen de los datos en la propiedad DataSet (al igual que en el reporte) y el campo que queremos mostrar en la propiedad DataField. Y ya est, ya tenemos el reporte de todos los registros de la tabla. Pueden probarlo. Como ejercicio, dejamos al lector la tarea de hacer que el form del reporte se cree en el momento en que lo vamos a usar -en otras palabras, que no se cree automticamente al inicio del programa, que no es necesario- y hacer que slo se impriman los registros de los animales que pesan menos de 10 kg. Asimismo, convendra que agreguen bandas de ttulo, de encabezado y pie de pgina y de resumen para ver el comportamiento de las mismas.
C Si el reporte se basa en una tabla, debemos filtrar la tabla aplicando un rango a los datos (SetRange) que seleccione slo el registro deseado. En la tabla Animals.dbf:
SetRange(['ocelot'],['ocelot']);
Claro que habr que seleccionar antes el ndice Name para la tabla!
El valor que identifica al registro deseado (en nuestro ejemplo, el nombre del animal) puede venir de un editor o algn otro medio de interaccin con el usuario.
16
Desarrollo del ejemplo paso por paso Usaremos las tablas de ejemplo que vienen con Delphi Orders (master) e Items (detail). Primero hacemos un form principal con las tablas relacionadas y un navegador para ver los datos antes de imprimir. Fig. 10.
17
El navegador permite moverse en la tabla principal. Ahora veamos el reporte que, como habrn adivinado, se activa al presionar el botn. Los pasos son los siguientes: 1. Agregar un nuevo form al proyecto. Todas las acciones siguientes se refieren a este form. 2. Poner un componente QuickRep 3. Agregar un componente Table y asociar a la tabla Orders (Table1). 4. Agregar un componente DataSource (DataSource1) y asociar a la tabla anterior 5. Agregar otro componente Table, asociarlo a la tabla Items y relacionar con Table1 a travs de la propiedad MasterSource por el campo OrderNo 6. Indicar al reporte que obtenga los datos para el detalle de la tabla principal, seleccionando Table1 en la propiedad DataSet Figura 13la ficha principal del ejemplo de reporte de tablas relacionadas.
Tenemos situados ya los componentes de acceso a los datos con los enlaces correspondientes. Vamos ahora a colocar las bandas.
1) Banda de detalle de la tabla principal Aqu se mostrarn los registros de la tabla principal, es decir, los datos de las rdenes. En la propiedad Bands del reporte, ponemos en True la banda detail. Se agrega una banda al reporte. Coloquemos los componentes imprimibles: dos QRDBText para mostrar los campos OrderNo y ShipDate; se pueden poner adems etiquetas para indicar qu valores estamos viendo.
Ahora ya podemos hacer una vista previa; se muestran los datos de la tabla principal.
2) Banda de detalle de la tabla secundaria (sub detail) Agregue un componente QRSubDetail desde la paleta de componentes. La propiedad DataSet debe apuntar a la tabla secundaria. Agregamos ahora los componentes imprimibles: QRDBText para mostrar los campos PartNo (nmero de parte, cdigo), Qty (cantidad) y Discount. (descuento). Se puede hacer ya una vista previa y tendremos todos los datos. No obstante, faltara un lugar para poner los ttulos de las columnas del detalle secundario. Estos ttulos se deben imprimir una vez antes del comienzo de cada grupo de registros secundarios: necesitamos una banda de cabecera de grupo. Agregamos entonces al reporte una banda (QRBand) y ponemos su propiedad BandType en rbGroupHeader. Llamemos a esta banda TitulosDeGrupo1. Ahora seleccionamos la banda de detalle secundario (SubDetail) que pusimos antes y seleccionamos la banda de ttulo recin creada en la propiedad HeaderBand. Las bandas se reacomodan. Agregamos etiquetas para ttulos de las columnas y 18
El reporte est casi terminado; pueden admirar su obra en la vista previa. Agregaremos un toquecito de cosmtica que lo har lucir ms profesional: agregaremos un pie de pgina con el nmero de pgina.
En la propiedad Bands del reporte ponemos en True la opcin HasPageFooter. Aparece la banda de pi de pgina, en la cual agregamos un componente QRLabel con el caption igual a Pgina y a su derecha un componente QRSysData con la propiedad Data en qrsPageNumber. Llevamos estos componentes a la derecha de la banda y Voil! Ya tenemos el nmero de pgina al pie de cada una.
De la misma manera podramos agregar un encabezado de pgina con la fecha o algn otro dato de inters. Es as de simple... La vista previa resultante de este programa se ve en la fig. 12.
19
20
Como vemos, la impresin se simplifica mucho con el uso del Quick Report. Hay mucho ms todava por descubrir: la jerarqua de componentes de Quick Report es bastante rica y nos ofrece la oportunidad de crear nuestros propios componentes imprimibles. Un ejemplo de extensin de las capacidades bsicas es la serie de artculos de Keith Wood [Extending Quick Report-Delphi Informant Agosto/Septiembre 1997], donde se crea una grilla del estilo del DBGrid que se puede imprimir y adems se modifica la ventana de vista previa agregando otras capacidades como diferentes grados de acercamiento (zoom).
Problemas
Asimismo, segn podemos ver en los grupos de discusin especializados en Internet, el producto an adolece de ciertas falencias -por ejemplo, varios usuarios han reportado una prdida irremediable de recursos del sistema al hacer vistas previas en tiempo de diseo... con ciertas impresoras, en ciertos equipos, en determinadas situaciones. Es de esperar que pronto quSoft libere una correccin a ese y otros problemas que se han presentado. Hay otro problema grave que se presenta en Delphi 4 (Quick Report 3) al usar bases de datos de Access 97: si la consulta que entrega los datos a QR involucra ms de una tabla, la aplicacin se cae... generalmente arrastrando en la caida a todo el sistema! Este problema ha sido reconocido por QuSoft, pero no ha sido solucionado. Segn he visto en grupos de discusin en Internet, una posible solucin viene de la mano de otro producto -que hay que pagar, por supuesto- que agrega capacidades de editar los reportes en tiempo de ejecucin, incluso para el usuario final. Este producto se instala sobre QR y parece solucionar los problemas. Se llama QRDesign y se puede bajar una versin de prueba del sitio www.thsd.de. Aunque no tengamos el problema, vale la pena echar una ojeada al QRDesign; la capacidad de dar al usuario un generador de reportes es muchas veces importante. A Mayo/1999, la ltima versin de Quick Report es la 3.04; la actualizacin se puede obtener de Internet.
21
Algunas Observaciones
C Cuando se muestra en ejecucin una ventana que contiene un reporte, se ve lo mismo que en tiempo de diseo. C Generalmente, se utilizan componentes de acceso a los datos independientes para los reportes, dado que el reporte debe navegar las tablas y si el usuario est trabajando con el mismo componente, se producir un post automtico y el cursor quedar en el ltimo registro impreso. C Cuando se produce un reporte, se crea un componente llamado QRPrinter. Es un componente no visual que da acceso a la impresora directamente, por ejemplo para enviar un fin de pgina. Es equivalente al objeto Printer. C La grilla del QuickRep es exacta y depende de la propiedad Units si est en Pulgadas o MM. C La propiedad Fonts define la fuente por defecto para el reporte; NO SE LISTAN LAS FUENTES ESPECFICAS DEL DISPOSITIVO, como las fuentes comunes de las impresoras de agujas; hay que ponerlas "a mano" asignando el valor a la propiedad Name de Fonts. C Una banda se puede estirar para que entre el contenido de alguno de los componentes imprimibles (por ejemplo un QRDBMemo) siempre que la propiedad CanExpand de la banda est en True y la propiedad AutoStretch (AutoAjuste) del componente est en True tambin. C La posicin y el tamao de un componente imprimible se pueden especificar con precisin a travs de la propiedad Size. Las unidades son las de la propiedad Units del reporte.
22
Con esto terminamos el tema de Impresin desde Delphi. Slo hemos tocado la superficie, dado que es posible crear reportes mucho ms complejos. A continuacin ofrecemos una referencia de artculos relacionados para aquellos que deseen ahondar un poco en el tema.
QuickReport: an introduction to Delphi 2's alternative report generator. Cary Jensen, Delphi Informant Vol 2, Nro 8 (Agosto 1996). Una introduccin simple como la que hemos dado aqu. Trata del Quick Report versin 1 que vena con Delphi 2; algunas cosas han cambiado en la versin 2.
QuickReport 2.0: Part I. Cary Jensen, Delphi Informant Vol 3, Nro 8 (Agosto 1997). Primera parte de la construccin de un programa de ejemplo de varios tipos de reportes. Utiliza Child Bands en uno de los reportes.
Creating Mailing Labels (Quick Report 2, Part II). Cary Jensen, Delphi Informant Vol 3, Nro 9 (Septiembre 1997). Tcnicas avanzadas: reportes Master/Detail, etiquetas postales, ventanas de vista previa definidas por nosotros, y generacin de reportes en tiempo de ejecucin.
Extending QuickReport: Part I. Keith Wood, Delphi Informant Vol 3 Nro 8 (Agosto 1997). Tcnicas avanzadas: creacin de una vista previa propia con ms posibilidades, y creacin de un componente nuevo que muestra una grilla de base de datos (como el DBGrid) en el reporte.
Extending QuickReport: Part II. Keith Wood, Delphi Informant Vol 3 Nro 9 (Septiembre 1997). Agregados al componente de grilla creado en el artculo anterior.
Building a Master/Detail Report . En el sitio de QuSoft (www.qusoft.com), es un artculo con los fuentes correspondientes que explica cmo crear paso a paso un reporte master/detail. Va un poco ms all de lo presentado aqu, utiliza tres tablas y una consulta para presentar ms datos.
QRDesign y QRPowerPack. En el sitio de Timo Hartmann Software Development (www.thsd.de) podemos encontrar estos dos productos; el primero es un editor de reportes para el usuario final (en tiempo de ejecucin). Es pago. El PowerPack es un conjunto de componentes imprimibles gratis, que se instalan sobre QR y dan posibilidades avanzadas como reportes directos de grillas, etiquetas con ngulo, etc.
En el sitio WEB de QuSoft se pueden encontrar varios ejemplos, componentes shareware y freeware y algunos artculos sobre temas especficos, adems de parches para las versiones actuales del producto. Conviene darse una vueltita de vez en cuando.
23