Migrer de QuickReport vers sgcReports

sgcReports est le moteur d'états à bandes de sgcUI : TsgcReport contient la mise en page, TsgcReportEngine lie les données, TsgcReportPreviewVCL affiche les pages, et l'export PDF écrit du PDF/UA balisé. Ce kit associe les bandes et les contrôles QuickReport que vous utilisez à leurs équivalents sgcReports, montre le code d'une démo compilée et indique honnêtement ce qui ne correspond pas.

Des états Delphi VCL construits avec QuickReport

Un TQuickRep sur une fiche, des bandes, des contrôles QR sur les bandes, et un bouton d'aperçu, d'impression ou de PDF dans l'application.

QuickReport est de nouveau maintenu. Dans « QuickReport is back » (blog Embarcadero, Ian Barker, 14 novembre 2024), Embarcadero explique que le produit a connu une crise lorsque son développeur principal est décédé, qu'il a été relancé avec le partenaire d'Embarcadero Barnsten, et qu'il prend désormais en charge toutes les versions de RAD Studio avec Delphi et C++Builder à partir de Delphi 7. La page QuickReport de Barnsten (consultée le 2026-10-20) liste un filtre PDF avec polices TrueType incorporées, la prise en charge de PDF/A, et des filtres d'export HTML, XML/XSLT, XLS et XLSX, et affiche QuickReport Pro 5 développeurs à 2.155,00 EUR hors TVA. Cette page ne parle donc pas d'un produit mort ni d'un bouton PDF manquant. Elle s'adresse aux équipes qui veulent ce que cette liste de fonctions ne mentionne pas.

Ce qu'apporte sgcReports

Chaque affirmation sur sgcReports ci-dessous figure dans le code source livré. Du côté de QuickReport, on lit « Non listé » lorsque la page de l'éditeur ne dit rien, pas « Non pris en charge ».

PDF/UA accessible

TsgcReportPDFExport écrit du PDF/UA balisé par défaut (PDFUA vaut True, PDFUAPart choisit la partie 1 ou 2), avec un ordre de lecture, des rôles de titre issus du TagRole de l'élément, des textes alternatifs issus de AltText, ainsi que la Language et le Title du document. PDFA ajoute PDF/A-3b, PDF/A-3a ou PDF/A-4 pour l'archivage. Il est présent dans toutes les éditions, Community comprise. PDF/UA et le PDF balisé ne figurent pas sur la page des fonctions de Barnsten. Les documents accessibles comptent davantage depuis l'Acte européen sur l'accessibilité, directive (UE) 2019/882, qui couvre des produits et services comme les livres numériques, le commerce électronique et les services bancaires.

Un concepteur pour l'utilisateur final, VCL et FireMonkey

Vos utilisateurs peuvent modifier un état sans nouvelle compilation : sgcShowReportDesigner(Engine) ouvre le concepteur VCL, ou intégrez le panneau TsgcVCLReportDesigner ; sgcShowReportDesignerFMX(Engine) fait de même dans FireMonkey (Delphi XE6 et suivants, bureau). Le concepteur VCL suit les changements de DPI de la fiche (son inspecteur, ses icônes et sa surface de conception se redimensionnent dans ChangeScale). Éditions Registered uniquement. La page des fonctions de Barnsten ne liste pas de concepteur pour l'utilisateur final ; historiquement, c'était un produit tiers distinct, QRDesign. Sur le High DPI, une réponse de Delphi-PRAXiS du 4 avril 2022 disait que QuickReport 6 se compile avec Delphi 11.1 mais ne prend pas en charge le High-DPI ; vérifiez la version actuelle auprès de l'éditeur.

Un seul moteur pour toute la suite

Les tableaux croisés, les codes-barres, les sous-états et le texte enrichi sont des types d'éléments du même moteur de bandes. Avec les unités de pont, un état imprime aussi un graphique sgcCharts et un tableau croisé dynamique sgcPivotGrid comme éléments, dessinés en contenu vectoriel dans le PDF (éditions Registered). Exports : PDF, XLSX, CSV, HTML et PNG dans toutes les éditions, DOCX dans les éditions Registered.

Définitions JSON et équivalent .NET

Un état s'enregistre et se charge en JSON (TsgcReport.SaveToFile, LoadFromFile), de sorte que les mises en page peuvent vivre dans une base de données ou sous gestion de versions. La même définition se charge dans sgcReports pour .NET (NuGet esegece.sgcReports, .NET Standard 2.0, .NET Framework 4.7.2 et .NET 6 et suivants), un état Delphi peut donc être réutilisé par un service .NET.

Les états sont reconstruits, pas importés. sgcReports ne peut pas ouvrir un .dfm QuickReport : il n'existe pas d'importateur QuickReport. Chaque état est recréé, dans le code comme le fait la démo ci-dessous, ou dans le concepteur sgcReports (éditions Registered). La correspondance et les étapes de cette page font de cette tâche un travail mécanique, bande par bande. sgcReports est licencié par développeur à partir de €199 avec le code source complet et un an de mises à jour, et il fait aussi partie de sgcUI.

Classes QuickReport, équivalents sgcReports

Chaque nom sgcReports ci-dessous figure dans le code source livré, et ceux que la démo utilise y compilent. Les noms QuickReport sont donnés à titre indicatif ; QuickReport n'était pas installé lors de la vérification de cette page.

QuickReport sgcReports Édition
TQuickRepTsgcReport (Pages, Styles, Units, Title) et TsgcReportEngine (Report, AddDataSource, Prepare, Variables, OnGetVariable)Toutes
TQuickRep.DataSetTsgcReportDataSetSource (SourceName, DataSet) enregistré avec AddDataSource ; le DataSourceName de la bande le nommeToutes
TQuickRep.Page (papier, marges)TsgcReportPage.PaperSize (rpsA3, rpsA4, rpsA5, rpsLetter, rpsLegal, rpsCustom), Margins.Left, Top, Right, BottomToutes
TQuickRep.ReportTitleTsgcReport.Title, et TsgcReportPDFExport.Title pour les métadonnées du PDFToutes
TQRBand avec BandType rbTitle, rbPageHeader, rbColumnHeaderTsgcReportBand avec BandType rbtReportTitle, rbtPageHeader, rbtColumnHeaderToutes
rbDetailrbtMasterData avec DataSourceName réglé sur la source maîtreToutes
rbGroupHeader, rbGroupFooterrbtGroupHeader, rbtGroupFooterToutes
rbSummary, rbPageFooterrbtReportSummary, rbtPageFooterToutes
TQRChildBandrbtChild avec TsgcReportBand.ChildBandNameToutes
TQRSubDetailUne bande rbtDetailData (DataSourceName = source détail) et MasterSource, MasterFields, DetailFields sur le TsgcReportDataSetSource détailToutes
TQRGroup.ExpressionrbtGroupHeader avec GroupExpressionToutes
TQRGroup.ReprintOnNewPageTsgcReportBand.RepeatOnEveryPageToutes
TQRGroup.FooterBandLa bande rbtGroupFooter suivante ; le premier pied de page ferme le groupe le plus interneToutes
TQRBand.ForceNewPageTsgcReportBand.StartNewPageToutes
TQRLabel (Caption)Un élément avec Kind = rikText et un Text.Text littéralToutes
TQRDBText (DataField, Mask)rikText avec Text.Text = '[Source.Field]' ; Mask devient Text.DisplayFormatToutes
TQRExpr (Expression)rikText avec '[expression]', par exemple '[Lines.Qty * Lines.Price]' ; fonctions comme IIF, FormatFloat, FormatDateTime, Round, UpperToutes
TQRExpr avec SUM, COUNT, AVERAGE, MIN, MAX[Sum(x)], [Count()], [Avg(x)], [Min(x)], [Max(x)] ; remise à zéro par groupe dans les pieds de groupe, portée page dans les pieds de pageToutes
TQRSysData qrsPageNumber[Page], et [TotalPages] pour Page X sur YToutes
TQRSysData qrsDate, qrsTime, qrsDetailNo[Date], [Time] avec Text.DisplayFormat ; [Line] ou [RecNo]Toutes
TQRShape (qrsRectangle, qrsCircle, qrsRoundRect)rikShape avec Shape.ShapeKind rskRectangle, rskEllipse, rskRoundRect ; Shape.PenColor, FillColor, PenWidthToutes
TQRShape qrsHorLinerikLine avec Height = 0Toutes
TQRImage, TQRDBImagerikImage avec Image.FileName ou Image.Picture, ou Image.DataField ; Stretch, KeepAspectRatioToutes
TQRRichText, TQRDBRichTextrikRichText avec RichText.Markup : balisage de type HTML, pas du RTF, pouvant contenir des [expressions]Toutes
Enabled réglé à l'exécution, événements BeforePrintVisibleExpression sur les bandes et les éléments ; TsgcReportEngine.OnBeforePrintBandToutes
Prepare, PreviewTsgcReportEngine.Prepare renvoie TsgcReportPreparedPages ; TsgcReportPreviewVCL.Prepare les affiche dans un contrôle de la ficheToutes
Print, PrinterSetupTsgcReportPreviewVCL.Print(aTitle), après un TPrintDialog standardToutes
ExportToFilter avec un filtre PDFTsgcReportPDFExport.SaveToFile(aPages, aFileName) ou SaveToStreamToutes
PDF/ATsgcReportPDFExport.PDFA = rpaA3b, rpaA3a ou rpaA4Toutes
Non listéPDF/UA : TsgcReportPDFExport.PDFUA (True par défaut), PDFUAPart, Language, Title ; TagRole et AltText de l'élémentToutes
Non listé (QRDesign était un module complémentaire tiers)Concepteur pour l'utilisateur final : sgcShowReportDesigner, TsgcVCLReportDesigner ; sgcShowReportDesignerFMX dans FireMonkeyRegistered

Le code, issu de la démo compilée

Chaque extrait est copié de la démo MigrateFromQuickReport, qui compile avec Delphi 7 et Delphi 13 (Win32 et Win64) et dans l'édition Community. Les commentaires nomment le code QuickReport qu'il remplace.

TQuickRep devient un état et un moteur

Avant : un TQuickRep sur la fiche, avec l'état et ses données dans un seul composant. Après : la mise en page, le moteur et l'aperçu sont des composants séparés.

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 et TQRSubDetail deviennent des sources de données

Avant : TQuickRep.DataSet pour les factures et un TQRSubDetail avec son propre DataSet pour les lignes. Après : une source par jeu de données, le détail lié au maître par des champs. FormCreate enregistre les deux avec 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

Une méthode d'aide qui remplace TQRLabel, TQRDBText et TQRExpr

La démo ajoute chaque texte avec cette petite méthode de sa fiche, afin que les extraits ci-dessous restent courts.

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;

Mise en page, bande de titre et TQRSysData

Avant : TQuickRep.Page, une bande de titre et un TQRSysData avec la date. Après : TagRole marque le titre comme un titre dans l'arbre de balises 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, bande de détail et TQRSubDetail

Avant : un TQRGroup sur le client, une bande de détail de contrôles TQRDBText, et un TQRSubDetail avec un TQRExpr pour le montant de la ligne. Après :

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';

Agrégats du pied de groupe

Avant : des composants TQRExpr avec COUNT et SUM dans la bande de pied de groupe. Après :

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';

La bande de synthèse, TQRShape et TQRRichText

Avant : une bande de synthèse avec un TQRShape, des totaux généraux et un TQRRichText. Après : le texte enrichi est un balisage de type 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>.';

Pied de page avec Page X sur 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');

Aperçu et impression

Avant : QuickRep1.Preview, PrinterSetup et Print. Après :

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 devient TsgcReportPDFExport

Avant : ExportToFilter avec un filtre PDF. Après : un seul commutateur écrit un PDF simple ou un fichier PDF/UA balisé.

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;

Huit étapes par état

Les jeux de données restent tels quels. L'état est reconstruit bande par bande.

1

Remplacer le TQuickRep

Placez un TsgcReport, un TsgcReportEngine (Report = l'état) et un TsgcReportPreviewVCL (Engine = le moteur) sur une fiche normale.

2

Enregistrer les données

Ajoutez un TsgcReportDataSetSource par jeu de données (SourceName, DataSet) et appelez AddDataSource. Pour chaque TQRSubDetail, réglez MasterSource, MasterFields et DetailFields.

3

Régler la page

Ajoutez un TsgcReportPage avec le format de papier et les marges de TQuickRep.Page, et réglez TsgcReport.Units (ruPoints dans la démo) afin que les coordonnées soient prévisibles.

4

Recréer les bandes

Une TsgcReportBand par TQRBand, dans l'ordre de l'état, avec le type de bande rbt correspondant ; DataSourceName sur les bandes maître et détail, GroupExpression sur les en-têtes de groupe.

5

Recréer les contrôles

TQRLabel, TQRDBText et TQRExpr deviennent des éléments rikText qui mélangent texte littéral et [expressions]. Mask devient Text.DisplayFormat, les polices deviennent des styles nommés.

6

Traduire les expressions

Les agrégats deviennent [Sum(x)], [Count()], [Avg(x)], [Min(x)] et [Max(x)] ; TQRSysData devient [Page], [TotalPages], [Date] et [Time].

7

Aperçu, impression, export

Preview devient TsgcReportPreviewVCL.Prepare, Print devient Print, et le filtre PDF devient TsgcReportPDFExport.SaveToFile. Réglez PDFUA, Title et Language pour obtenir un PDF accessible.

8

Le remettre à vos utilisateurs

Facultatif, éditions Registered : enregistrez l'état reconstruit en JSON avec TsgcReport.SaveToFile et laissez les utilisateurs le modifier avec sgcShowReportDesigner.

Ce qui ne correspond pas un pour un

Lisez ceci avant de planifier la migration.

MigrateFromQuickReport

Une liste de factures maître-détail typique de QuickReport, groupée par client : 18 factures de 4 clients et leurs lignes, à partir de deux TClientDataSet remplis dans le code.

Où la trouver

Le programme d'installation sgcUI la place dans Demos\Reports\Delphi\MigrateFromQuickReport : sgcReports_Demo_MigrateFromQuickReport.dpr, frmMain.pas, frmMain.dfm et un readme.html. Elle figure aussi dans l'édition Community.

Comment l'exécuter

Ouvrez le .dpr dans n'importe quel Delphi de 7 à 13 avec sgcReports et sgcPDF installés, compilez en Win32 ou Win64 et lancez. L'état est préparé au démarrage, trois pages avec Page X sur Y.

Que tester

Print... affiche une boîte de dialogue d'impression et imprime. Save PDF écrit invoices.pdf et Save PDF/UA écrit le fichier balisé invoices_pdfua.pdf à côté de l'exe, prêt pour une vérification avec un validateur PDF/UA.

Pour être juste envers les deux moteurs : QuickReport est de nouveau maintenu, prend en charge Delphi 7 et les versions suivantes, et ses états se conçoivent dans le concepteur de fiches Delphi. Sa page de fonctions liste des filtres d'export, comme XML/XSLT, que sgcReports n'a pas, et le conserver évite de reconstruire le moindre état. sgcReports est la voie à suivre lorsque vous avez besoin d'une sortie PDF/UA accessible, d'un concepteur pour vos utilisateurs, d'états partagés avec sgcCharts, sgcPivotGrid ou un service .NET, et que vous acceptez de reconstruire chaque état une fois. Pour la liste complète des fonctions, consultez la page produit sgcReports.

Meilleur rapport qualité-prix : All-AccessTous les produits eSeGeCe, Support Premium inclus, à partir de €1,059/an.
Voir les tarifs All-Access

Reconstruisez votre premier état dès aujourd'hui

Téléchargez l'essai sgcUI avec sgcReports et la démo MigrateFromQuickReport, puis portez votre premier état.