Migre do QuickReport para o sgcReports

O sgcReports é o motor de relatórios por bandas do sgcUI: o TsgcReport guarda o layout, o TsgcReportEngine liga os dados, o TsgcReportPreviewVCL mostra as páginas e a exportação para PDF grava PDF/UA com tags. Este kit mapeia as bandas e os controles do QuickReport que você usa para os seus equivalentes no sgcReports, mostra o código de uma demo compilada e lista com honestidade o que não tem correspondência.

Relatórios Delphi VCL feitos com QuickReport

Um TQuickRep em um formulário, bandas, controles QR nas bandas e um botão de visualizar, imprimir ou gerar PDF na aplicação.

O QuickReport voltou a ter manutenção. Em "QuickReport is back" (blog da Embarcadero, Ian Barker, 14 de novembro de 2024), a Embarcadero explica que o produto entrou em crise quando o seu desenvolvedor principal faleceu, que foi retomado com a parceira da Embarcadero, a Barnsten, e que hoje suporta todas as versões do RAD Studio com Delphi e C++Builder a partir do Delphi 7. A página do QuickReport na Barnsten (lida em 20/10/2026) lista um filtro de PDF com fontes TrueType incorporadas, suporte a PDF/A e filtros de exportação para HTML, XML/XSLT, XLS e XLSX, e cobra pelo QuickReport Pro para 5 desenvolvedores EUR 2.155,00 sem IVA. Portanto esta página não trata de um produto morto nem de um botão de PDF que falta. É para as equipes que querem o que essa lista de recursos não menciona.

O que o sgcReports acrescenta

Toda afirmação sobre o sgcReports abaixo está no código-fonte distribuído. Do lado do QuickReport, diz "não consta" onde a página do fornecedor é omissa, e não "não suportado".

PDF/UA acessível

O TsgcReportPDFExport grava PDF/UA com tags por padrão (PDFUA é True, PDFUAPart escolhe a parte 1 ou 2), com ordem de leitura, papéis de título a partir do TagRole do item, textos alternativos de AltText e o Language e o Title do documento. PDFA acrescenta PDF/A-3b, PDF/A-3a ou PDF/A-4 para arquivamento. Está em todas as edições, inclusive na Community. PDF/UA e PDF com tags não constam na página de recursos da Barnsten. Os documentos acessíveis importam mais desde o Ato Europeu de Acessibilidade, a Diretiva (UE) 2019/882, que abrange produtos e serviços como e-books, comércio eletrônico e serviços bancários.

Um designer para o usuário final, VCL e FireMonkey

Os seus usuários podem alterar um relatório sem uma nova compilação: sgcShowReportDesigner(Engine) abre o designer VCL, ou incorpore o painel TsgcVCLReportDesigner; sgcShowReportDesignerFMX(Engine) faz o mesmo no FireMonkey (Delphi XE6 e posteriores, desktop). O designer VCL acompanha as mudanças de DPI do formulário (o inspetor, os ícones e a superfície de desenho se reescalam em ChangeScale). Somente nas edições Registradas. A página de recursos da Barnsten não lista um designer para o usuário final; historicamente era um produto de terceiros à parte, o QRDesign. Sobre High DPI, uma resposta no Delphi-PRAXiS de 4 de abril de 2022 dizia que o QuickReport 6 compila com o Delphi 11.1 mas não suporta High-DPI; confirme a versão atual com o fornecedor.

Um motor para toda a suíte

Tabelas de referência cruzada, códigos de barras, subrelatórios e texto rico são tipos de item do mesmo motor de bandas. Com as units de ponte, um relatório também imprime um gráfico do sgcCharts e uma tabela dinâmica do sgcPivotGrid como itens, desenhados como conteúdo vetorial no PDF (edições Registradas). Exportações: PDF, XLSX, CSV, HTML e PNG em todas as edições, DOCX nas edições Registradas.

Definições em JSON e uma contrapartida em .NET

Um relatório é salvo e carregado em JSON (TsgcReport.SaveToFile, LoadFromFile), de modo que os layouts podem ficar em um banco de dados ou no controle de versão. A mesma definição carrega no sgcReports para .NET (NuGet esegece.sgcReports, .NET Standard 2.0, .NET Framework 4.7.2 e .NET 6 em diante), então um relatório Delphi pode ser reutilizado por um serviço .NET.

Os relatórios são refeitos, não importados. O sgcReports não abre um .dfm do QuickReport: não existe importador do QuickReport. Cada relatório é recriado, em código como faz a demo abaixo, ou no designer do sgcReports (edições Registradas). O mapeamento e os passos desta página tornam isso um trabalho mecânico, banda a banda. O sgcReports é licenciado por desenvolvedor a partir de €199 com o código-fonte completo e um ano de atualizações, e também faz parte do sgcUI.

Classes do QuickReport, equivalentes no sgcReports

Todo nome do sgcReports abaixo está no código-fonte distribuído, e os que a demo usa compilam nela. Os nomes do QuickReport são dados como referência; o QuickReport não estava instalado quando esta página foi verificada.

QuickReport sgcReports Edição
TQuickRepTsgcReport (Pages, Styles, Units, Title) e TsgcReportEngine (Report, AddDataSource, Prepare, Variables, OnGetVariable)Todas
TQuickRep.DataSetTsgcReportDataSetSource (SourceName, DataSet) registrado com AddDataSource; o DataSourceName da banda o nomeiaTodas
TQuickRep.Page (papel, margens)TsgcReportPage.PaperSize (rpsA3, rpsA4, rpsA5, rpsLetter, rpsLegal, rpsCustom), Margins.Left, Top, Right, BottomTodas
TQuickRep.ReportTitleTsgcReport.Title, e TsgcReportPDFExport.Title para os metadados do PDFTodas
TQRBand com BandType rbTitle, rbPageHeader, rbColumnHeaderTsgcReportBand com BandType rbtReportTitle, rbtPageHeader, rbtColumnHeaderTodas
rbDetailrbtMasterData com DataSourceName definido como a fonte mestreTodas
rbGroupHeader, rbGroupFooterrbtGroupHeader, rbtGroupFooterTodas
rbSummary, rbPageFooterrbtReportSummary, rbtPageFooterTodas
TQRChildBandrbtChild com TsgcReportBand.ChildBandNameTodas
TQRSubDetailUma banda rbtDetailData (DataSourceName = fonte de detalhe) e MasterSource, MasterFields, DetailFields no TsgcReportDataSetSource de detalheTodas
TQRGroup.ExpressionrbtGroupHeader com GroupExpressionTodas
TQRGroup.ReprintOnNewPageTsgcReportBand.RepeatOnEveryPageTodas
TQRGroup.FooterBandA próxima banda rbtGroupFooter; o primeiro rodapé fecha o grupo mais internoTodas
TQRBand.ForceNewPageTsgcReportBand.StartNewPageTodas
TQRLabel (Caption)Um item com Kind = rikText e Text.Text literalTodas
TQRDBText (DataField, Mask)rikText com Text.Text = '[Source.Field]'; Mask vira Text.DisplayFormatTodas
TQRExpr (Expression)rikText com '[expression]', por exemplo '[Lines.Qty * Lines.Price]'; funções como IIF, FormatFloat, FormatDateTime, Round, UpperTodas
TQRExpr com SUM, COUNT, AVERAGE, MIN, MAX[Sum(x)], [Count()], [Avg(x)], [Min(x)], [Max(x)]; zerados por grupo nos rodapés de grupo, escopo de página nos rodapés de páginaTodas
TQRSysData qrsPageNumber[Page], e [TotalPages] para Página X de YTodas
TQRSysData qrsDate, qrsTime, qrsDetailNo[Date], [Time] com Text.DisplayFormat; [Line] ou [RecNo]Todas
TQRShape (qrsRectangle, qrsCircle, qrsRoundRect)rikShape com Shape.ShapeKind rskRectangle, rskEllipse, rskRoundRect; Shape.PenColor, FillColor, PenWidthTodas
TQRShape qrsHorLinerikLine com Height = 0Todas
TQRImage, TQRDBImagerikImage com Image.FileName ou Image.Picture, ou Image.DataField; Stretch, KeepAspectRatioTodas
TQRRichText, TQRDBRichTextrikRichText com RichText.Markup: marcação parecida com HTML, não RTF, e pode conter [expressions]Todas
Enabled definido em tempo de execução, eventos BeforePrintVisibleExpression em bandas e itens; TsgcReportEngine.OnBeforePrintBandTodas
Prepare, PreviewTsgcReportEngine.Prepare devolve TsgcReportPreparedPages; TsgcReportPreviewVCL.Prepare as mostra em um controle no formulárioTodas
Print, PrinterSetupTsgcReportPreviewVCL.Print(aTitle), depois de um TPrintDialog padrãoTodas
ExportToFilter com um filtro de PDFTsgcReportPDFExport.SaveToFile(aPages, aFileName) ou SaveToStreamTodas
PDF/ATsgcReportPDFExport.PDFA = rpaA3b, rpaA3a ou rpaA4Todas
Não constaPDF/UA: TsgcReportPDFExport.PDFUA (padrão True), PDFUAPart, Language, Title; TagRole e AltText do itemTodas
Não consta (o QRDesign era um complemento de terceiros)Designer para o usuário final: sgcShowReportDesigner, TsgcVCLReportDesigner; sgcShowReportDesignerFMX no FireMonkeyRegistrada

O código, da demo compilada

Cada trecho é copiado da demo MigrateFromQuickReport, que compila no Delphi 7 e no Delphi 13 (Win32 e Win64) e na edição Community. Os comentários indicam o código do QuickReport que ele substitui.

O TQuickRep vira um relatório e um motor

Antes: um TQuickRep no formulário, com o relatório e os seus dados em um só componente. Depois: o layout, o motor e a visualização são componentes separados.

frmMain.dfm
object sgcPreview: TsgcReportPreviewVCL
  Left = 0
  Top = 44
  Width = 900
  Height = 676
  Align = alClient
  TabOrder = 1
  Engine = sgcEngine
end
object sgcReport: TsgcReport
  Left = 40
  Top = 80
end
object sgcEngine: TsgcReportEngine
  Report = sgcReport
  Left = 120
  Top = 80
end

TQuickRep.DataSet e TQRSubDetail viram fontes de dados

Antes: TQuickRep.DataSet para as notas e um TQRSubDetail com o seu próprio DataSet para as linhas. Depois: uma fonte por dataset, com o detalhe ligado ao mestre por campos. O FormCreate registra as duas com sgcEngine.AddDataSource.

frmMain.dfm
object srcInvoices: TsgcReportDataSetSource
  SourceName = 'Invoices'
  DataSet = cdsInvoices
  Left = 40
  Top = 208
end
object srcLines: TsgcReportDataSetSource
  SourceName = 'Lines'
  MasterSource = srcInvoices
  MasterFields = 'Number'
  DetailFields = 'Invoice'
  DataSet = cdsLines
  Left = 120
  Top = 208
end

Um auxiliar que substitui TQRLabel, TQRDBText e TQRExpr

A demo adiciona cada texto com este pequeno método do seu formulário, para que os trechos abaixo fiquem curtos.

frmMain.pas
function TformMain.AddText(aBand: TsgcReportBand; const aText: string;
  aLeft, aTop, aWidth: Double; const aStyle: string): TsgcReportItem;
var
  oStyle: TsgcReportStyle;
begin
  // one item replaces TQRLabel (literal text), TQRDBText ([Source.Field])
  // and TQRExpr ([expression]); literal text and [expressions] can be mixed
  Result := aBand.Items.Add;
  Result.Kind := rikText;
  Result.Name := aBand.Name + IntToStr(aBand.Items.Count);
  Result.Text.Text := aText;
  Result.Left := aLeft;
  Result.Top := aTop;
  Result.Width := aWidth;
  Result.Height := 14;
  Result.StyleName := aStyle;
  oStyle := sgcReport.Styles.FindStyle(aStyle);
  if Assigned(oStyle) and (oStyle.Font.Size * 1.25 > Result.Height) then
    Result.Height := oStyle.Font.Size * 1.25;
end;

Configuração da página, a banda de título e o TQRSysData

Antes: TQuickRep.Page, uma banda de título e um TQRSysData com a data. Depois: TagRole marca o título como cabeçalho na árvore de tags do PDF/UA.

frmMain.pas
// QuickReport: TQuickRep.Page (PaperSize, LeftMargin, TopMargin, ...)
oPage := sgcReport.Pages.Add;
oPage.Name := 'Invoices';
oPage.PaperSize := rpsA4;
oPage.Margins.Left := 40;
oPage.Margins.Top := 40;
oPage.Margins.Right := 40;
oPage.Margins.Bottom := 40;

// TQRBand BandType = rbTitle: printed once, on the first page
oBand := AddBand(oPage, rbtReportTitle, 'Title', 40);
AddText(oBand, 'Invoices by customer', 0, 0, 350, 'Title').TagRole :=
  rtrHeading1;
AddText(oBand, 'Printed on', 315, 6, 120, 'Right');
// TQRSysData Data = qrsDate
oItem := AddText(oBand, '[Date]', 440, 6, 75, 'Right');
oItem.Text.DisplayFormat := 'yyyy-mm-dd';

TQRGroup, a banda de detalhe e o TQRSubDetail

Antes: um TQRGroup no cliente, uma banda de detalhe de controles TQRDBText e um TQRSubDetail com um TQRExpr para o valor da linha. Depois:

frmMain.pas
// TQRGroup Expression = 'Invoices.Customer', ReprintOnNewPage = True.
// The column titles are TQRLabel components in QuickReport
oBand := AddBand(oPage, rbtGroupHeader, 'CustomerHeader', 42);
oBand.GroupExpression := 'Invoices.Customer';
oBand.RepeatOnEveryPage := True;
AddText(oBand, '[Invoices.Customer]', 0, 4, 515, 'Group').TagRole :=
  rtrHeading2;
AddText(oBand, 'Invoice / product', 0, 24, 200, 'Bold');
AddText(oBand, 'Date / qty', 210, 24, 120, 'Bold');
AddText(oBand, 'Price', 345, 24, 70, 'BoldRight');
AddText(oBand, 'Amount', 425, 24, 90, 'BoldRight');
AddLine(oBand, 40);

// TQRBand BandType = rbDetail: one band per record of TQuickRep.DataSet.
// Each [Source.Field] text item replaces a TQRDBText with DataField set
oBand := AddBand(oPage, rbtMasterData, 'Invoice', 18);
oBand.DataSourceName := 'Invoices';
AddText(oBand, '[Invoices.Number]', 0, 3, 200, 'Bold');
oItem := AddText(oBand, '[Invoices.InvoiceDate]', 210, 3, 120, 'Bold');
oItem.Text.DisplayFormat := 'yyyy-mm-dd';
oItem := AddText(oBand, '[Invoices.Amount]', 425, 3, 90, 'BoldRight');
// TQRDBText.Mask
oItem.Text.DisplayFormat := '#,##0.00';

// TQRSubDetail DataSet = Lines, linked to the invoice: the link is
// MasterSource / MasterFields / DetailFields of srcLines (see the form)
oBand := AddBand(oPage, rbtDetailData, 'Line', 14);
oBand.DataSourceName := 'Lines';
AddText(oBand, '[Lines.Product]', 15, 1, 195);
AddText(oBand, '[Lines.Qty]', 210, 1, 40, 'Right');
oItem := AddText(oBand, '[Lines.Price]', 345, 1, 70, 'Right');
oItem.Text.DisplayFormat := '#,##0.00';
// TQRExpr Expression = 'Lines.Qty * Lines.Price'
oItem := AddText(oBand, '[Lines.Qty * Lines.Price]', 425, 1, 90, 'Right');
oItem.Text.DisplayFormat := '#,##0.00';

Agregados do rodapé de grupo

Antes: componentes TQRExpr com COUNT e SUM na banda de rodapé do grupo. Depois:

frmMain.pas
// TQRBand BandType = rbGroupFooter (TQRGroup.FooterBand). Aggregates are
// reset for every group, like TQRExpr with ResetAfterPrint = True
oBand := AddBand(oPage, rbtGroupFooter, 'CustomerFooter', 30);
AddLine(oBand, 2);
// TQRExpr Expression = 'COUNT' and 'SUM(Lines.Qty)'
AddText(oBand, '[Count()] invoices, [Sum(Lines.Qty)] items', 0, 8,
  250, 'Bold');
AddText(oBand, 'Customer total', 260, 8, 155, 'BoldRight');
// TQRExpr Expression = 'SUM(Invoices.Amount)'
oItem := AddText(oBand, '[Sum(Invoices.Amount)]', 425, 8, 90, 'BoldRight');
oItem.Text.DisplayFormat := '#,##0.00';

A banda de resumo, o TQRShape e o TQRRichText

Antes: uma banda de resumo com um TQRShape, totais gerais e um TQRRichText. Depois: o texto rico é marcação parecida com HTML.

frmMain.pas
// TQRBand BandType = rbSummary: printed once, after the last record
oBand := AddBand(oPage, rbtReportSummary, 'Summary', 90);
oBand.KeepTogether := True;
// TQRShape Shape = qrsRectangle, Brush.Color and Pen.Color
oItem := oBand.Items.Add;
oItem.Kind := rikShape;
oItem.Name := 'SummaryBox';
oItem.Top := 10;
oItem.Width := 515;
oItem.Height := 30;
oItem.Shape.ShapeKind := rskRectangle;
oItem.Shape.PenColor := $00A0A0A0;
oItem.Shape.FillColor := $00EEF3FA;
// TQRExpr Expression = 'COUNT' and 'SUM(Invoices.Amount)' in the summary
AddText(oBand, 'Grand total, [Count()] invoices', 10, 17, 300, 'Group');
oItem := AddText(oBand, '[Sum(Invoices.Amount)]', 315, 17, 190,
  'GroupRight');
oItem.Text.DisplayFormat := '#,##0.00';
// TQRRichText: the text is HTML-like markup instead of RTF
oItem := oBand.Items.Add;
oItem.Kind := rikRichText;
oItem.Name := 'SummaryNote';
oItem.Top := 50;
oItem.Width := 515;
oItem.Height := 36;
oItem.StyleName := 'Base';
oItem.RichText.Markup := '<b>Migrated from QuickReport.</b> Each band of ' +
  'this report replaces a <i>TQRBand</i>, each text item a <i>TQRLabel</i>, '
  + '<i>TQRDBText</i> or <i>TQRExpr</i>.';

Rodapé de página com Página X de Y

frmMain.pas
// TQRBand BandType = rbPageFooter
oBand := AddBand(oPage, rbtPageFooter, 'PageFooter', 20);
AddLine(oBand, 2);
// TQRLabel with a literal caption
AddText(oBand, 'Invoices by customer', 0, 6, 300);
// TQRSysData Data = qrsPageNumber; [TotalPages] is resolved after the
// last page is laid out
AddText(oBand, 'Page [Page] of [TotalPages]', 315, 6, 200, 'Right');

Visualizar e imprimir

Antes: QuickRep1.Preview, PrinterSetup e Print. Depois:

frmMain.pas
procedure TformMain.btnPreviewClick(Sender: TObject);
begin
  // QuickReport: QuickRep1.Preview (or Prepare + a TQRPreview). sgcReports:
  // the preview control on the form runs the engine and shows the pages
  sgcPreview.Prepare;
  lblStatus.Caption := Format('%d pages prepared', [sgcPreview.PageCount]);
end;

procedure TformMain.btnPrintClick(Sender: TObject);
begin
  // QuickReport: QuickRep1.PrinterSetup + QuickRep1.Print. The print dialog
  // selects the printer, Print sends the prepared pages to it
  if dlgPrint.Execute then
    sgcPreview.Print(sgcReport.Title);
end;

ExportToFilter vira TsgcReportPDFExport

Antes: ExportToFilter com um filtro de PDF. Depois: uma chave grava um PDF comum ou um arquivo PDF/UA com tags.

frmMain.pas
procedure TformMain.SavePDF(aPDFUA: Boolean; const aFileName: string);
var
  oPages: TsgcReportPreparedPages;
  vFileName: string;
begin
  // QuickReport: QuickRep1.ExportToFilter(TQRPDFDocumentFilter.Create(...))
  vFileName := ExtractFilePath(ParamStr(0)) + aFileName;
  // PDF/UA: a tagged PDF (headings, reading order, alternate texts); Title
  // and Language are set on pdfExport in the form
  pdfExport.PDFUA := aPDFUA;
  oPages := sgcEngine.Prepare;
  try
    pdfExport.SaveToFile(oPages, vFileName);
  finally
    oPages.Free;
  end;
  lblStatus.Caption := Format('Saved %s (%d warnings)',
    [vFileName, pdfExport.Warnings.Count]);
end;

Oito passos por relatório

Os datasets continuam como estão. O relatório é refeito banda a banda.

1

Substitua o TQuickRep

Coloque um TsgcReport, um TsgcReportEngine (Report = o relatório) e um TsgcReportPreviewVCL (Engine = o motor) em um formulário comum.

2

Registre os dados

Adicione um TsgcReportDataSetSource por dataset (SourceName, DataSet) e chame AddDataSource. Para cada TQRSubDetail defina MasterSource, MasterFields e DetailFields.

3

Configure a página

Adicione um TsgcReportPage com o tamanho do papel e as margens de TQuickRep.Page e defina TsgcReport.Units (ruPoints na demo) para que as coordenadas sejam previsíveis.

4

Recrie as bandas

Um TsgcReportBand por TQRBand, na ordem do relatório, com o tipo de banda rbt correspondente; DataSourceName nas bandas mestre e detalhe, GroupExpression nos cabeçalhos de grupo.

5

Recrie os controles

TQRLabel, TQRDBText e TQRExpr viram itens rikText que misturam texto literal e [expressions]. Mask vira Text.DisplayFormat, as fontes viram estilos nomeados.

6

Traduza as expressões

Os agregados viram [Sum(x)], [Count()], [Avg(x)], [Min(x)] e [Max(x)]; o TQRSysData vira [Page], [TotalPages], [Date] e [Time].

7

Visualizar, imprimir, exportar

Preview vira TsgcReportPreviewVCL.Prepare, Print vira Print, e o filtro de PDF vira TsgcReportPDFExport.SaveToFile. Defina PDFUA, Title e Language para obter um PDF acessível.

8

Entregue aos seus usuários

Opcional, edições Registradas: salve o relatório refeito como JSON com TsgcReport.SaveToFile e deixe os usuários editá-lo com sgcShowReportDesigner.

O que não tem correspondência um a um

Leia isto antes de planejar a mudança.

MigrateFromQuickReport

Uma lista típica de notas em mestre-detalhe do QuickReport, agrupada por cliente: 18 notas de 4 clientes e as suas linhas, a partir de dois TClientDataSet preenchidos em código.

Onde está

O instalador do sgcUI a coloca em Demos\Reports\Delphi\MigrateFromQuickReport: sgcReports_Demo_MigrateFromQuickReport.dpr, frmMain.pas, frmMain.dfm e um readme.html. Ela está também na edição Community.

Como executá-la

Abra o .dpr em qualquer Delphi do 7 ao 13 com o sgcReports e o sgcPDF instalados, compile para Win32 ou Win64 e execute. O relatório é preparado ao iniciar, três páginas com Página X de Y.

O que experimentar

Print... mostra um diálogo de impressão e imprime. Save PDF grava invoices.pdf e Save PDF/UA grava o invoices_pdfua.pdf com tags ao lado do exe, pronto para uma verificação com um validador de PDF/UA.

Para ser justo com os dois motores: o QuickReport voltou a ter manutenção, suporta o Delphi 7 em diante e os seus relatórios são desenhados no designer de formulários do Delphi. A sua página de recursos lista filtros de exportação, como XML/XSLT, que o sgcReports não tem, e mantê-lo significa que nenhum relatório precisa ser refeito. O sgcReports é o caminho quando você precisa de saída PDF/UA acessível, de um designer para os seus usuários, de relatórios compartilhados com o sgcCharts, o sgcPivotGrid ou um serviço .NET, e aceita refazer cada relatório uma vez. Para a lista completa de recursos veja a página do produto sgcReports.

Melhor custo-benefício: All-AccessTodos os produtos da eSeGeCe, com Suporte Premium incluído, a partir de €1,059/ano.
Ver preços do All-Access

Refaça o seu primeiro relatório hoje

Baixe a versão de avaliação do sgcUI com o sgcReports e a demo MigrateFromQuickReport, e porte o seu primeiro relatório.