В составе генератора отчетов FastReport, который интегрирован в среду разработки My Visual Database, имеется компонент для отображения QR-кодов, что позволяет создавать в разрабатываемых программах стикеры, платежные документы, рекламные объявления, которые могут содержать QR-коды. Но иногда такой код необходимо отобразить непосредственно на форме.
В демонстрационный проект ClearApp давно пора добавить универсальную процедуру программного вызова отчетов, которая на практике дает больше возможностей, чем стандартная кнопка с Action = [Отчет]. Для этого я создал отдельный модуль Report.pas, в который поместил мою процедуру Report_Open(), ранее известную под именем OpenReport(). Новое название соответствует концепции именования процедур и функций, которая подразумевает, что название должно начинаться с имени модуля.
procedure Report_Open(ADataSets: array of TDataSet; ADSNames: array of string; AStrParam: array of string;
AStrParamName: array of string; AReportMode: integer; AReportFileName: string; AReportDir: string = '';
AFileName: string = ''; AResolution: integer = 300; AJPEGQuality: integer = 100);
// программно открыть отчет
//
// параметры:
// ADataSets - датасеты
// ADSNames - названия датасетов
// AStrParam - значения параметров
// AReportMode - режим открытия
// AStrParamName - названия параметров
// AReportFileName - название отчета
// AReportDir - папка с отчетами
// AFileName - имя файла для экспорта
// AResolution - разрешение изображения
// AJPEGQuality - степень сжатия JPEG
var
i: integer;
frxDBDatasets: array of TfrxDBDataset;
procedure SetParam;
var
i: integer;
begin
// передача параметров как переменных - после загрузки отчета!
Report.Variables.Clear;
for i := 0 to Length(AStrParam) - 1 do
Report.Variables[AStrParamName[i]] := '''' + AStrParam[i] + '''';
end;
procedure CloseDS;
var
i: integer;
begin
for i := 0 to Length(ADataSets) - 1 do
begin
frxDBDatasets[i].DataSet.Close;
end;
end;
procedure FreeDS;
var
i: integer;
begin
for i := 0 to Length(ADataSets) - 1 do
begin
frxDBDatasets[i].Free;
end;
end;
begin
try
// папка с отчетами по умолчанию
if AReportDir = '' then
AReportDir := ExtractFileDir(Application.ExeName) + '\Report\';
// создаём датасеты
SetLength(frxDBDatasets, Length(ADataSets));
for i := 0 to Length(ADataSets) - 1 do
begin
frxDBDatasets[i] := TfrxDBDataset.Create(Report.Owner);
frxDBDatasets[i].UserName := ADSNames[i];
frxDBDatasets[i].CloseDataSource := True;
frxDBDatasets[i].OpenDataSource := True;
frxDBDatasets[i].DataSet := ADataSets[i];
end;
// подготовка отчета
Report.Clear;
Report.DataSets.Clear;
for i := 0 to Length(ADataSets) - 1 do
begin
Report.DataSets.Add(frxDBDatasets[i]);
end;
// в зависимости от настройки глобальной переменной, выбираем режим
case AReportMode of
RM_DESIGN:
begin
Report.LoadFromFile(AReportDir + AReportFileName);
SetParam;
Report.DesignReport;
end;
RM_PREVIEW:
begin
CloseDS;
Report.LoadFromFile(AReportDir + AReportFileName);
SetParam;
Report.ShowReport;
end;
RM_PDF:
begin
CloseDS;
Report.LoadFromFile(AReportDir + AReportFileName);
SetParam;
// подготовить отчёт к экспорту
Report.PrepareReport;
// не отображать диалог экспорта
PDFExport.ShowDialog := False;
// если имя файла не указано, то
if AFileName = '' then
AFileName := GetTmpFilename('.pdf');
// файл с отчетом будет создан во временной папке со случайным именем
PDFExport.FileName := AFileName;
// опции, встраивающие шрифты в документ
PDFExport.EmbeddedFonts := True;
PDFExport.PrintOptimized := True;
PDFExport.Background := True; // сохранять фон
PDFExport.OpenAfterExport := False; // не открывать после экспорта
PDFExport.ShowProgress := False; // не показывать прогресс
// PDFExport.Transparency := True; // экспорт прозрачного
// экспортировать в PDF
Report.Export(PDFExport);
end;
RM_EXCEL:
begin
CloseDS;
Report.LoadFromFile(AReportDir + AReportFileName);
SetParam;
// подготовить отчёт к экспорту
Report.PrepareReport;
// не отображать диалог экспорта
XLSExport.ShowDialog := False;
// если имя файла не указано, то
if AFileName = '' then
AFileName := GetTmpFilename('.xlsx');
// файл с отчетом будет создан во временной папке со случайным именем
XLSExport.FileName := AFileName;
// экспортировать в PDF
Report.Export(XLSExport);
end;
RM_JPEG:
begin
CloseDS;
Report.LoadFromFile(AReportDir + AReportFileName);
SetParam;
// подготовить отчёт к экспорту
Report.PrepareReport;
//
JPEGExport.JPEGQuality := AJPEGQuality;
JPEGExport.Resolution := AResolution;
JPEGExport.SeparateFiles := False;
JPEGExport.ShowDialog := False;
// если имя файла не указано, то
if AFileName = '' then
AFileName := GetTmpFilename('.jpg');
JPEGExport.FileName := AFileName;
// экспортировать
Report.Export(JPEGExport);
end;
end;
// зачистка
FreeDS;
except
RaiseException('procedure Report_Open(): '+ExceptionMessage );
end;
end;
Code language: Delphi (delphi)
Процедура позволяет запускать генератор в различных режимах: редактирование макета, просмотр, в также экспорт в различные форматы: PDF, Excel, JPEG. Последний режим мы и будем использовать для решения поставленной задачи – отображения QR-кода на форме приложения. Для этого нам потребуется вспомогательная процедура Report_QR_Make() , которая необходима для создания файла с изображением QR-кода, а также небольшой отчет, содержащий компонент для его генерации.
function Report_QR_Make ( AText:string; AReportFileName:string = ''; AReportMode:integer = -1 ):string;
// создает jPEG файл с QR-кодом
// для работы процедуры нужен специальный отчет QR.fr3 или его аналог
var
tmpDataSets : array of TDataSet;
tmpDSNames: array of string;
tmpStrParam: array of string;
tmpStrParamName: array of string;
tmpFileName: string;
i: integer;
begin
try
// контроль допустимых значений для режима отчета
case AReportMode of
-1: AReportMode := RM_JPEG; // по умолчанию
RM_DESIGN,RM_JPEG: AReportMode := AReportMode; // допустимые значения
else
RaiseException('function Report_QR_Make(): Недопустимое значение AReportMode = '+IntToStr(AReportMode) );
end;
// нужен специальный отчет с компонентом генерации QR-кода
if AReportFileName = '' then
AReportFileName := 'QR.fr3';
// к базе не подключаемся
SetLength( tmpDataSets,0 );
SetLength( tmpDSNames, 0 );
// текст для создания кода передаем параметром
SetLength( tmpStrParam, 1 ); // даты фестиваля и город
SetLength( tmpStrParamName, 1 );
// параметры
i := 0;
// Текст для кода
tmpStrParamName[i] := 'TextData';
tmpStrParam[i] := AText;
inc(i);
// нам понадобится временный файл
tmpFileName := GetTmpFilename('.jpg');
// вызвать универсальную функцию открытия отчета
Report_Open( tmpDataSets, tmpDSNames, tmpStrParam, tmpStrParamName, AReportMode, AReportFileName, '', tmpFileName );
// если сначала вызывали дизайнер, то потом ещё раз запустить конвертер
if AReportMode = RM_DESIGN then
Report_Open( tmpDataSets, tmpDSNames, tmpStrParam, tmpStrParamName, RM_JPEG, AReportFileName, '', tmpFileName );
// чистим...
Report_FreeDataSets( tmpDataSets );
Result := tmpFileName; // в файле - картинка
except
RaiseException('function Report_QR_Make(): '+ExceptionMessage );
end;
end;
Code language: Delphi (delphi)
Отчет представляет собой страницу размером, совпадающим с размером QR-кода. К сожалению, интеграция компонента QR-кода разработчиком MVDB была произведена не полностью, из-за чего нет возможности управлять параметрами генератора (размеры точек, отступы от края и тип кодирования) c помощью скрипта, то есть при изменении размера данных, отображаемых в QR-коде, потребуется ручная корректировка размера страницы.

В то же время для передачи данных в компонент придется написать коротки скрипт непосредственно в самом отчете – обработчик события OnAfterData для компонента QRCode, в котором свойству Text, отвечающему за содержимое кода, передаётся значение из параметра TextData.
procedure QRcodeOnAfterData(Sender: TfrxComponent);
begin
QRcode.Text := <TextData>;
end;
Code language: Delphi (delphi)
Для загрузки QR-кода в картинку добавим процедуру Report_QR_Load(), задача которой создать файл изображения, а после его загрузки в компонент на форме, удалить временный файл.
procedure Report_QR_Load ( AText:string; AImage: TdbImage; AReportFileName: string = ''; AReportMode:integer = -1 );
// загрузка QR-кода в картинку
var
tmpFilename: string;
begin
tmpFilename := Report_QR_Make (AText,AReportFileName,AReportMode );
AImage.Picture.LoadFromFile(tmpFilename);
DeleteFile(tmpFilename);
end;
Code language: JavaScript (javascript)
В модуле Report.pas необходимо разместить константы, определяющие режим работы генератора отчетов. Туда же можно перенести из модуля AppConstVar.pas переменные, отвечающие за работу FastReport.
uses 'System\Utils.pas', 'VClass\AppConstVar.pas';
const
// режим отчёта
RM_DESIGN = 0; // редактор
RM_PREVIEW = 1; // предварительный просмотр
RM_PDF = 2; // экспорт в PDF
RM_EXCEL = 3; // экспорт в Excell
RM_JPEG = 4; // экспорт в JPG
var
Report: TfrxReport; // движок отчетов и его элементы:
PDFExport: TfrxPDFExport; // экспорт в PDF
XLSExport: TfrxXLSExport; // экспорт в XLS
JPEGExport: TfrxJPEGExport; // экспорт в JPG
Code language: Delphi (delphi)
В качестве иллюстрации использования вышеописанной технологии используется процедура Report_QR_Demo(), которая добавляет QR-код с адресом сайта на форму “О программе”. Вызов данной процедуры нужно добавить в процедуре UserApp_MainForm_OnShow() или в любом другом месте, после инициализации системных переменных, которое происходит в процедуре App_InitSystemVar().
procedure Report_QR_Demo;
// демонстрация загрузки QR-кода в картинку
var
tmpImage: TdbImage;
begin
// создаем картинку на форме "О программе"
tmpImage := TdbImage.Create(frmdbCoreAbout);
tmpImage.Name := 'imgQRCode';
tmpImage.Parent := frmdbCoreAbout;
tmpImage.Width := frmdbCoreAbout.Button1.Width;
tmpImage.Height := tmpImage.Width;
tmpImage.Proportional := True;
tmpImage.Stretch := True;
tmpImage.Top := 10;
tmpImage.Left := frmdbCoreAbout.Button1.Left;
// загружаем в неё адрес сайта
Report_QR_Load( APP_SITE, tmpImage );
// можно передавать имя отчета и включать режим отладки:
// Report_QR_Load( APP_SITE, tmpImage, 'QR.fr3',0 );
end;
Code language: Delphi (delphi)

Ссылки
CleanApp – архив с исходными текстами (доступен подписчикам библиотеки)