Построение отчета с помощью кода
Построением отчета обычно занимается ядро FastReport. Оно выводит бэнды отчета в определенной последовательности столько раз, сколько имеется данных, формируя таким образом готовый отчет. Иногда необходимо вывести отчет нестандартной формы, который ядро FastReport сформировать не в состоянии. В этом случае можно воспользоваться возможностью построения отчета вручную, с помощью события TfrxReport.OnManualBuild. Если определить обработчик этого события, ядро FastReport передаст управление ему. При этом распределение обязанностей по формированию отчета меняется следующим образом:
Ядро:
подготовка отчета к формированию (инициализация скрипта, источников данных, формирование дерева бэндов)
все вычисления (агрегатные функции, обработчики событий)
формирование новых страниц/колонок (автоматический вывод page/column header/footer, report title/summary)
прочая рутинная работа
Обработчик:
- вывод бэндов в определенном порядке
Т.е., суть обработчика OnManualBuild состоит в том, чтобы давать ядру FastReport команды на вывод определенных бэндов. Все остальное ядро сделает самостоятельно: сформирует новую страницу, когда место на текущей закончится, выполнит скрипты и т.д.
Ядро представлено классом TfrxCustomEngine. Ссылка на экземпляр этого класса находится в свойстве TfrxReport.Engine. Ядро имеет следующие свойства и методы:
Свойство или метод | Описание |
---|---|
procedure NewColumn | Формирует новую колонку. Если колонка была последней, формирует новую страницу. |
procedure NewPage | Формирует новую страницу. |
procedure ShowBand(Band: TfrxBand) | Показывает бэнд. |
procedure ShowBand(Band: TfrxBandClass) | Показывает бэнд заданного типа. |
function FreeSpace: Extended | Возвращает количество свободного места на странице (в пикселах). После вывода очередного бэнда это значение уменьшается. |
property CurColumn: Integer | Возвращает/устанавливает номер текущей колонки. |
property CurX: Extended | Возвращает/устанавливает текущую позицию X. |
property CurY: Extended | Возвращает/устанавливает текущую позицию Y. После вывода очередного бэнда это значение увеличивается. |
property DoublePass: Boolean | Является ли отчет двухпроходным. |
property FinalPass: Boolean | Является ли текущий проход последним. |
property FooterHeight: Extended | Возвращает высоту page footer. |
property HeaderHeight: Extended | Возвращает высоту page header. |
property PageHeight: Extended | Возвращает высоту области печати страницы. |
property PageWidth: Extended | Возвращает ширину области печати страницы. |
property TotalPages: Integer | Возвращает количество страниц в готовом отчете (только на втором проходе двухпроходного отчета). |
Приведем пример простого обработчика. В отчете имеется два бэнда master data, не подключенных к данным. Обработчик выведет эти бэнды в чередующемся порядке, каждый по 6 раз. После шести бэндов будет сделан небольшой промежуток.
Pascal:
var
i: Integer;
Band1, Band2: TfrxMasterData;
{ находим нужные бэнды }
Band1 := frxReport1.FindObject('MasterData1') as TfrxMasterData;
Band2 := frxReport1.FindObject('MasterData2') as TfrxMasterData;
for i := 1 to 6 do
begin
{ выводим бэнды друг за другом }
frxReport1.Engine.ShowBand(Band1);
frxReport1.Engine.ShowBand(Band2);
{ делаем небольшой промежуток }
if i = 3 then
frxReport1.Engine.CurY := frxReport1.Engine.CurY + 10;
end;
C++:
int i;
TfrxMasterData * Band1;
TfrxMasterData * Band2;
// находим нужные бэнды
Band1 := dynamic_cast <TfrxMasterData *> (frxReport1->FindObject("MasterData1"));
Band2 := dynamic_cast <TfrxMasterData *> (frxReport1->FindObject("MasterData2"));
for(i = 1; i <= 6; i++)
{
// выводим бэнды друг за другом
frxReport1->Engine->ShowBand(Band1);
frxReport1->Engine->ShowBand(Band2);
// делаем небольшой промежуток
if(i == 3)
frxReport1->Engine->CurY += 10;
}
Следующий пример выведет две группы бэндов рядом друг с другом.
Pascal:
var
i, j: Integer;
Band1, Band2: TfrxMasterData;
SaveY: Extended;
Band1 := frxReport1.FindObject('MasterData1') as TfrxMasterData;
Band2 := frxReport1.FindObject('MasterData2') as TfrxMasterData;
SaveY := frxReport1.Engine.CurY;
for j := 1 to 2 do
begin
for i := 1 to 6 do
begin
frxReport1.Engine.ShowBand(Band1);
frxReport1.Engine.ShowBand(Band2);
if i = 3 then
frxReport1.Engine.CurY := frxReport1.Engine.CurY + 10;
end;
frxReport1.Engine.CurY := SaveY;
frxReport1.Engine.CurX := frxReport1.Engine.CurX + 200;
end;
C++:
int i, j;
TfrxMasterData * Band1;
TfrxMasterData * Band2;
Extended SaveY;
Band1 = dynamic_cast <TfrxMasterData *> (frxReport1->FindObject("MasterData1"));
Band2 = dynamic_cast <TfrxMasterData *> (frxReport1->FindObject("MasterData2"));
SaveY = frxReport1->Engine->CurY;
for(j = 1; j <= 2; j++)
{
for(i = 1; i <= 6; i++)
{
frxReport1->Engine->ShowBand(Band1);
frxReport1->Engine->ShowBand(Band2);
if(i == 3)
frxReport1->Engine->CurY += 10;
}
frxReport1->Engine->CurY = SaveY;
frxReport1->Engine->CurX += 200;
}