Agregando reporteador a Delphi 10.2 Starter

Hola amigos,

Como hemos visto en los artículos anteriores, la Edición Delphi 10.2 Starter no cuenta con algunos componentes importantes para el desarrollo de aplicaciones y una de estas limitaciones es que no dispone de la posibilidad de generar reportes, por tal razón, comencé a investigar si existía algún componente que nos permitiera obtener reportes en nuestras aplicaciones y que además se pudiera instalar en ésta Edición de Delphi 10.2 Starter.

Intenté instalar algunos reporteadores conocidos sin éxito ya que éstos no tenían compatibilidad con Delphi 10.2 Starter, finalmente encontré una biblioteca llamada Virtual Print Engine (VPE) en su edición Community la cual instalé sin problemas ya que no tiene dependencia con componentes de Delphi y además sigue la misma filosofía ya que ésta biblioteca tiene el mismo concepto de Delphi Starter que es el principo de equidad el cual menciona que si utilizas la biblioteca para generar ganancias, les gustaría que se comprara la versión de pago lo cual me parece por demás aceptable.

La edición Community de VPE al ser gratuita también tiene sus limitaciones pero después de instalarlo y hacer algunas pruebas de concepto puedo asegurarles que es mas que suficiente para crear cualquier tipo de documento y exportarlo a PDF.

Para éste artículo requerimos de descargar el instalador de Report Engine and PDF Library, la versión que encontré disponible para éste tutorial es para Delphi XE2, sin embargo, no tuve problemas para instalarlo y utilizarlo en Delphi 10.2 Starter.

Al terminar la descarga procederemos a instalar la versión de 32 bits, recuerden que Delphi Starter solo tiene soporte para la arquitectura de 32bits y no para arquitectura de 64bits.

Ejecutamos el programa vpec32.exe el cual instalará el motor de impresión en nuestra maquina.

Agregar el componente a Delphi es muy fácil, solo cargamos el proyecto VpevclXe2.dproj en nuestro IDE lo compilamos y finalmente lo instalamos. El componente se instalará en el grupo System con el nombre TVPEngine como pueden observar en la siguiente imagen.

Nota 1: Antes de compilar deberá agregar el Path del componente en las opciones de Delphi en Tools –> Options — Delphi Options –> Library  –> Library Path como se observa en la siguiente imagen.

Nota 2: Si al compilar les genera el siguiente error:

[MakeDir Error] Unable to create directory «.\Win32\Debug\». Access to the path ‘.\Win32\Debug\’ is denied.
Failed

Deberán ejecutar Delphi con permisos de Administrador.

Ya estamos listos para comenzar a experimentar con éste nuevo componente, para ello vamos a abrir el proyecto que hemos estado desarrollando en ésta serie y vamos a hacer algunos cambios a la interfáz gráfica que me parecen adecuados.

Vamos a eliminar los componentes TDBGrid y TDataSurce de nuestra forma ya que no serán necesarios y agregamos un TButton y el nuevo componente TVPEngine.

Usted decida como quiere ver su interfáz gráfica, en mi caso se verá de la siguiente forma:

Antes de continuar les diré que el concepto del Virtual Printer Engine hace que no solo sea un simple reporteador sino un motor de informes para crear dinámicamente cualquier tipo de documento ya sea simple o complejo. La disposición de objetos me recordó viejos tiempos donde todo lo hacíamos a mano (me ha traido gratos recuerdos), sin embargo, a pesar de que en apariencia no se vea «tan profesional» nos proporciona el control total de como queremos mostrar la información .

El proceso para generar un informe es muy simple,

  • Se abre el TPVEngine
  • Se colocan los objetos (texto, imagen, lineas, etc) en las coordenadas deseadas,
  • Se muestra y se imprime o se genera un archivo PDF
  • Se cierra elTPVEngine.

Nota importante: En la edición Community la cual es gratuita, no se tiene la posibilidad de imprimir los documentos desde código, primero se tiene que visualizar en pantalla y después se podrá mandar a imprimir desde su visor, las ediciones de pago si que tienen mayores caracterìsticas.

Ya estamos listos para escribir código. Nuestra ventana tiene dos botones nuevos, uno para generar el documento en pantalla (Vista Previa) y el otro para exportar la información en un archivo PDF (Exporta a PDF).

Como ya les comenté el proceso es muy sencillo y lo vamos a hacer por separado para cada uno de los botónes con el objeto de que se tenga más comprensión del mismo.

Generamos la consulta de los tipos de cambio en un rango de fechas presionando el botón Vista Previa:

Se ejecuta el siguiente proceso:

  • Abrimos la consulta pasando el rango de fechas donde deseamos obtener.
  • Si se encuentra información, se genera el reporte.
    • Se genera el encabezado
    • Se genera el detalle de la información
  • Se muestra la Vista Previa del reporte
  ZQuery1.Close;
  ZQuery1.ParamByName('ini').asString := FormatDateTime('yyyy-mm-dd',dtpInicial.Date);
  ZQuery1.ParamByName('fin').AsString := FormatDateTime('yyyy-mm-dd',dtpFinal.Date);
  ZQuery1.Open;

  if not ZQuery1.IsEmpty then
  begin
    generaReporte;
    Report.Preview;
  end;

  ZQuery1.Close;
end;

En el procedimiento generaReporte se encuentra el código para la impresión de la información enmcabezado y detalle de la información.

procedure TForm1.GroupHeader(Fecha: String);
var
   y: double;
begin
  Report.TextAlignment := ALIGN_LEFT;
  y := Report.Print(1.5, Report.nBottom + 0.2, Format('[N S 14 C Blue]%s', [Fecha]));
  y := y + 0.1;
  Report.Print(1.5, y, '[S 10 C Purple]Clave');
  Report.Write(3.5, y, 6, VFREE, '[R]Tipo de Cambio');
  Report.Write(6.5, y, 19.5, VFREE, '[L]Descripción');
end;

procedure TForm1.DetailLine(color: TColor; Clave: String; TC:Real; Descrip: String);
var
  y: double;
begin
  y := Report.nBottom;
  Report.BkgMode := VBKG_SOLID;
  Report.BkgColor := color;
  Report.PenColor := color;
  Report.Box(1.5, y, 19.5, LineHeight+0.3);
  Report.BkgMode := VBKG_TRANSPARENT;

  Report.WriteBox(1.5, y, -4, LineHeight+0.3, Format('[S 7 C Black L]%s', [Clave]));
  Report.TextAlignment := ALIGN_RIGHT;
  Report.WriteBox(3.5, y, 6, LineHeight+0.3, Format('%4.5n', [TC]));
  Report.TextAlignment := ALIGN_LEFT;
  Report.WriteBox(6.5, y, 19.5, LineHeight+0.3, Format('%s', [Descrip]));
end;

procedure TForm1.generaReporte;
var
  I: integer;
  y: double;
  color: TColor;
  FechaCorte: TDateTime;
begin
  if Report.IsOpen then Report.CloseDoc;
  Report.OpenDoc;
  Report.RenderPrintBox(0, 0, '[S 14 C Black]x');
  LineHeight := -Report.nRenderHeight;
  Report.AutoBreakMode := AUTO_BREAK_NO_LIMITS;
  Report.SetPen(0.05, PS_SOLID, COLOR_BLACK);
  Report.Picture(1.5, 1.0, 8.5, 3.0, 'Imagenes\DenM.bmp');
  Report.WriteBox(9.5, 2.0, 19.5, 3, '[N S 9 CE I C Black BC Gray TO]Tipos de Cambio del ' +
                   FormatDateTime('dd "de" mmmm "de" yyyy',ZQuery1.ParamByName('INI').AsDate) + ' al ' +
                   FormatDateTime('dd "de" mmmm "de" yyyy',ZQuery1.ParamByName('FIN').AsDate) );
  y := Report.nBottom + 1;
  Report.Line(1.5, y, 19.5, y);
  Report.nBottom := y + 0.1;
  GroupHeader(FormatDateTime('d "de" mmmm "de" yyyy', ZQuery1.FieldByName('FECHA').AsDateTime));
  FechaCorte := ZQuery1.FieldByName('FECHA').AsDateTime;

  for I := 0 to ZQuery1.RecordCount-1 do
  begin
    if FechaCorte <> ZQuery1.FieldByName('FECHA').AsDateTime then
    begin
      GroupHeader(FormatDateTime('d "de" mmmm "de" yyyy', ZQuery1.FieldByName('FECHA').AsDateTime));
      FechaCorte := ZQuery1.FieldByName('FECHA').AsDateTime;
    end;
    if I mod 2 = 0 then
       color := COLOR_GRAY
    else
       color := COLOR_LTGRAY;
    DetailLine(color, ZQuery1.FieldByName('Clave').AsString,
	                  ZQuery1.FieldByName('TipCamb').AsFloat,
					  ZQuery1.FieldByName('Descripcion').AsString);
    ZQuery1.Next;
  end;

  Report.PageBreak;
  Report.SetFont('Arial', 10);
  Report.BkgMode := VBKG_SOLID;
  Report.BkgColor := clRed;
end;

Las funciones que se utilizan cuentan con toda la información necesaria para «pintar» la información, a continuación estudiaremos algunas.

Report.RenderPrintBox(0, 0, ‘[S 14 C Black]x’);

Se genera el espacio de trabajo desde el punto [0,0] , (S)tamaño de letra 14 y0(C)olor Negro.

Report.SetPen(0.05, PS_SOLID, COLOR_BLACK);

Asignamos el estilo de la pluma con espesor de 0.5, (PS)estilo sólido y (C)olor Negro.

Report.Picture(1.5, 1.0, 8.5, 3.0, ‘Imagenes\DenM.bmp’);

Con éste método se inserta la imagen DenM.bmp en la posición [1.5,1.0] [8.5,3.0].

Report.WriteBox(9.5, 2.0, 19.5, 3, ‘[N S 9 CE I C Black BC Gray TO]TEXTO’);

Se imprime un texto libre a partir de las cordenadas [9.5,2.0] [19.5,3.0] pero además se le indica las propiedades con las que será mostrado, (N) le indica que no guarde ésta configuración para los demás textos, (S) tamaño de letra 9, (CE)ntrado, fuente (I)talica, (C)olor Negro y (BC)Fondo Gris (TO)Sólido

Al dar clic al botón de Vista Previa el programa nos mostrará el reporte como se ve en la siguiente imagen:

Una vez que tenemos la Vista Previa podremos imprimir el documento y es que la edición Community de VPE no permite enviar a impresión desde código y solo puede hacerse desde la Vista Previa, eso y mucho mas se podrá hacer si se adquiere una de las versiones de pago.

Ahora vamos a crear un archivo PDF con el código asignado al botón Exporta a PDF.

En éste botón se ejecuta el siguiente proceso:

  • Abrimos la consulta pasando el rango de fechas donde deseamos obtener.
  • Si se encuentra información, se genera el reporte.
    • Se genera el encabezado
    • Se genera el detalle de la información
  • Se exporta la información a un archivo PDF
procedure TForm1.Button4Click(Sender: TObject);
begin
  ZQuery1.Close;
  ZQuery1.ParamByName('ini').asString := FormatDateTime('yyyy-mm-dd',dtpInicial.Date);
  ZQuery1.ParamByName('fin').AsString := FormatDateTime('yyyy-mm-dd',dtpFinal.Date);
  ZQuery1.Open;

  if not ZQuery1.IsEmpty then
  begin
    generaReporte;
    ExportDocumentNoAsk(Report, ExtractFilePath(Application.ExeName) + 'Report_' +
                                FormatDateTime('yyyymmdd_hhnnss', now) + '.pdf');
  end;

  ZQuery1.Close;
end;

Éste proceso creará el archivo PDF y posteriormente nos lo mostrará, ésto se genera en el procedimiento ExportDocumentNoAsk(). Éste procedimiento sustituye al Visor de reportes del botón anterior.

procedure TForm1.ExportDocumentNoAsk(Doc: TVPEngine; FileName: String);
begin
   if Doc.WriteDoc(FileName) then
   begin
     MessageDlg('Archivo PDF "' + FileName + '" creado satisfactoriamente.',
                 mtInformation, [mbOk], 0);
     ShellExecute(0, nil, PCHAR(Filename), nil, nil, SW_SHOWMAXIMIZED);
   end
   else begin
          MessageDlg('Error creating PDF file "' + FileName + '"!' + #10 +
                     'Possible reasons:' + #10 +
                     ' - the file is open in Acrobat Reader' + #10 +
                     ' - hard disk full' + #10 +
                     ' - no access rights to the folder' + #10 +
                     ' - out of memory' + #10 +
                     ' - export module missing', mtInformation, [mbOk], 0);
   end;
end;

Al terminar nos mostrará el archivo PDF creado como se ve en la imagen siguienre:

Hay muchas otras funciones, procedimientos que pueden estudiarse en el manual de control de referencia

Hasta aquí llegamos con la tercera entrega de la serie en la cual hemos abarcado solo tres características de uso común en cualquier aplicación (Consumo de webService, Acceso a Base de Datos y Generación de Reportes) y que la edición Starter de Delphi 10.2 no tiene disponibles.

Como siempre, espero que ésta información sea de su agrado pero sobre todo de utilidad. Por supuesto que el código presentado en todos mis artículos son hechos de la forma más básica posible con la intención de que sea fácil de entender por aquellos que están dando sus primeros pasos y nutrida por los grandes maestros que nos visitan.

Solo me resta decir que sigo investigando que mas se puede hacer, si alguien tiene alguna idea que quieran que se realice, con gusto estudiaremos si es posible desarrollarla con Delphi 10.2 Starter.

Hasta la próxima


Todo el código escrito aquí es de libre descarga y utilización solo te pido, si te parece correcto, que menciones su origen y claro cualquier mejora que le hagas publicala que se agradecerá enormemente.

Muchas gracias.

20 comentarios en «Agregando reporteador a Delphi 10.2 Starter»

  1. Excelente Eliseo, al parecer VPE es multiplataforma también, así que creo podría ser posible crear un servidor de reportes PDF para Linux con Delphi usando DMVC o DataSnap, o no?, también veo que podría ser muy caro en versiones pro.

    Gracias

    Responder
  2. Es posible que hagas un tutorial de fortesreport. Creo que es un buen reporteador, pero tiene diferencias con quickreport al usar grupos y subdetalles anidados. Hay muy poca información sobre él y tambien se puede instalar en las versiones starter de delphi.
    Gracias de antemano y saludos.

    Responder
  3. Perdona, no había visto que ya me respondiste.
    Quedo a la espera del tutorial, creo que valdrá la pena. Es gratuíto y creo que bastante completo.
    Saludos y gracias de nuevo.

    Responder
      • Bien, espero que te guste. Para los que aprendimos con QuickReport trasladar listados a otros reporteadores es bastante lioso, sobre todo en reportes con gran cantidad de subdetalles anidados, me refiero a balances, listados de materiales dependientes de proyectos, etc.
        Saludos.

        Responder
      • Hola Eliseo, cómo va tu experiencia con FortesReport?.
        He estado haciendo pruebas con él y he conseguido crear una ventana de reportes personalizada al estilo de QR.
        Asímismo, navegando he encontrado algunas referencias sobre el uso de grupos y subdetails, (pocas, muy pocas), y parece ser que las consultas deben ordenarse por los campos que agrupan los datos. Además, a diferencia de QR hay que anidar los subdetails dentro de los grupos a modo de Grupo, (master) y Subdetails, (hijo, hijo del hijo, …) y así sucesivamente, pudiendo insertar bandas para cabeceras y pies de subgrupos y enlazando los distintos datasets. Por lo demás parece funcionar muy parecido a QR.
        Verdaderamente las filosofía del componente difiere de QR.
        Saludos.

        Responder
        • Que tal Jaume, solo he hecho cosas básicas, lo veo bien aunque no creo tener el nivel para hacer un tutorial que se agradezca.

          Me alegra que ya tengas un gran avance, ojalá y nos pudieras compartir tu experiencias con ese reporteador, si no tienes donde hacerlo con gusto y si te parece bien, te puedo agregar como colaborador de ésta bitácora.

          Saludos

          Responder
    • Hola Eliseo, ya tengo algo coherente con FortesReport.
      Te agradecería me indicaras un correo para mandártelo, es una pequeña aplicación donde muestro el uso del componente.
      Me ha dado la impresión que los subdetails hay que hacerlos pensando que son subinformes dentro de un informe u otro subdetail que los embebe.
      Te mando una dirección donde se explica bastante al detalle el uso del componente.
      http://delphiprogrammingdiary.blogspot.com/2018/06/fortes-report.html
      Además, tu que estás al día con las versiones de Delphi, podrías decirme si pueden coexistir en la misma pc la versión comunity y delphi 7.
      Esta demo de FortesReport la he hecho con la versión Starter de Delphi Berlín,Zeos y Firebird. Pero todavía hago cosillas con mi querido Delphi7.
      Saludos.

      Responder

Deja un comentario