FAIL (the browser should render some flash content, not this).
  • Главная
  • ИТ-аутсорсинг
  • Сайтостроение
  • Портфолио
  • Контакты
  • Информация



Построение отчетов в нескольких потоках на Delphi

  Иногда требуется организовать многопоточное создание документов в каком-либо формате. Это может быть разработка веб-сервиса или вывод информации из уже существующего многопоточного приложения.

  Для создания документов в нужном формате удобно использовать генератор отчетов FastReport VCL. Эта библиотека компонентов проста в освоении, имеет удобный дизайнер отчетов, позволяет легко подключаться к различным источникам данных, в числе которых могут быть и внутренние данные приложение — массивы, наборы параметров и пр. Традиционное использование FastReport, как правило, не вызывает никаких сложностей, но сейчас мы рассмотрим ситуацию применения этого генератора отчетов в многопоточном приложении. Выходным форматом файлов станет PDF.

  Класс TfrxReport имеет в своем описании несколько свойств, которые необходимо настроить непосредственно после создания объекта отчета. Необходимо помнить, что объект должен работать в потоке без создания всевозможных диалоговых окон, прогресс бара и прочей визуальной информации. Рассмотрим пример создания и настройки объекта класса TfrxReport, перед его запуском в отчете:

1
2
3
4
5
6
7
8
9
10
// Создаем объект
FReport := TfrxReport.Create(nil);
// Запрещаем вывод различных сообщений
FReport.EngineOptions.SilentMode := True;
// Опция многопоточности, проверяется в некоторых местах при построении отчета
FReport.EngineOptions.EnableThreadSafe := True;
// Использование файлового кеша при построении отчетов
FReport.EngineOptions.UseFileCache := false;
// Запрещаем показ прогресс бара
FReport.ShowProgress := False;

  Также необходимо помнить о том, что некоторые отчеты имеют интегрированные диалоговые формы, показ которых должен быть запрещен по понятным причинам. Для перехвата форм переопределим обработчик события TfrxReport.Engine.OnRunDialog — присвоим ему процедуру ShowReportDialog.

1
2
// При наличии в отчете диалогов, вместо них будет вызываться ShowReportDialog
FReport.Engine.OnRunDialog := ShowReportDialog;

  Таким образом вместо показа каждой диалоговой формы отчета будет вызвана наша процедура. Там можно обратиться к контролам формы, изменить их значение, а можно все оставить как есть по умолчанию — в таком случае наша процедура будет пустой.

1
2
3
4
procedure TTestThread.ShowReportDialog(Page: TfrxDialogPage);
begin
   // пусто
end;

  Не забываем о настройках экспорта, нужно отключить показ всех диалогов и заранее установить все нужные нам параметры.

1
2
3
PDF := TfrxPDFExport.Create(nil);
PDF.ShowDialog := False;
PDF.ShowProgress := False;

  Все операции по созданию объектов отчета и экспорта можно сделать в конструкторе класса потока, соответственно деструктор потока должен содержать следующий код:

1
2
3
4
5
6
7
destructor TTestThread.Destroy;
begin
   // destroy all created objects
   PDF.Free;
   FReport.Free;
   inherited;
end;

  Нужные объекты созданы и сконфигурированы. Теперь можно загрузить шаблон отчета из файла и запустить отчета на выполнение в главной процедуре потока Execute. Там же выполним экспорт в нужный формат.

1
2
3
4
5
6
7
8
9
10
11
12
// загружаем шаблон отчета
FReport.LoadFromFile(FFileName);
// устанавливаем переменные отчета, если нужно
FReport.Variables['ThreadID'] := QuotedStr(FId);
// строим отчет
if FReport.PrepareReport then
begin
   // сохраняем результат в PDF
   PDF.FileName := FOutPath + '\report_'+ FId +
     '_' + FormatDateTime('YYYYYMMDDHHMMSS', Now) + '.pdf';
   FReport.Export(PDF);
end;

  Помните — если в отчете используется RichText, то в потоках могут быть проблемы. Старайтесь строить отчеты без использования RichText объектов. Если в отчетах используется подключение ADO, не забываем включить в uses модуль ActiveX и в процедуре Execute перед созданием отчета добавить вызов CoInitialize(nil). А после завершения работы с отчетов в потоке, соответственно нужно будет вызвать CoUninitialize.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Процедура потока
procedure TTestThread.Execute;
begin
   // Инициализирует библиотеку COM в текущем потоке
   CoInitialize(nil);
   try
     // загружаем шаблон отчета из файла
     FReport.LoadFromFile(FFileName);
     ...
     ...
     ...
   finally
     // Uninitialize COM
     CoUninitialize;
   end;
end;

Copyright© 2010 Александр Федяшов, ведущий разработчик FastReports