В составе генератора отчетов 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)
Форма “О программе” с QR-кодом

Ссылки

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *