Здравствуйте читатели моего блога. Сегодня я хочу вам продолжить рассказ о таком компоненте для формирования отчетов – Fast Report. В предыдущих статьях  я рассказывал, как установить  и русифицировать Fast Report в Delphi XE4. Все подробно и пошагово расписано. В конце стать есть ссылка на для скачивания.

Предисловие…

Мы уже разбирали, что отчет – это данные, которые будут на выходе из вашей программы. Раньше я не придавал отчетам большого значения, потому как я работаю напрямую с базой данных и нужные данные я мог вывести запросом.  Но мой проект в страховой компании рос день от дня. Сейчас я уже не могу поддерживать его в одиночку.  Поэтому у нас есть несколько человек, которым я делегировал часть своих прав на управление базой данных — это администраторы.

Админы (администраторы) – это IT-специалисты, которые  имеют частичный доступ к базе данных, могут вносить исправления и делать выборки.  В идеале это не совсем правильно, так как админы должны иметь доступ к данным, так же как и обычные агенты через программу.  При этом, как показала практика, не только меню нужно разделять в зависимости от прав, но и отображаемые данные.  Местами разграничение доступа можно ввести скрытием или отображение дополнительных элементов, но это не панацея.

Существует еще одна проблема. Часто администраторам нужно не просто видеть результат выборки двух – трех таблиц связанных условием, а чтобы оценивать ситуацию полностью — нужно видеть сразу несколько выборок  и т.д. Можно это назвать информативными отчетами. Например, нужен отчет истории ежедневных отчетов из ТФОМС (отчеты приходят в виде *.xml) с привязкой к нашей выгрузке в ТФОМС, текущее состояние записи в базе, кто ее изменял и когда.

Исходя, из всего выше описанного я пришел к тому, что мне нужно сделать динамичные и информативные отчеты. «Динамичные» — чтоб я мог изменять их структуру на «лету», «информативные» — собирать информацию с нескольких источников, преобразовать ее и выдавать в читаемом виде. В этом мне мог помочь Fast Report. Я уже рассматривал как можно быстро  (примерно минут за 15)  собрать отчет из базы данных с помощью средств Fast Report  в Delphi XE.

Задача…

Я вам покажу, как делать подобные отчеты на примере, казалось бы, простого формирования акта передачи полисов. В головной офис из ТФОМС привозят полисы ОМС, их отсканировали и занесли в базу. К полисам идет опись, по описи полисы делятся на короба (пачки). Каждый полис по ЕНП может быть идентифицирован с определенным коробом (или коробами, если человек, например, раньше имел полис, а сейчас ему пришел дубликат).

Коробам присвоены порядковые номера.  В одном коробе может быть больше одного пункта выдачи. Так как полисы на данный момент могут быть двух типов (УЭК – не присылают в страховую компанию): электронные карты или бумажный — каждый тип лежит в отдельном коробе. Например, в коробе «22299» — лежат только бумажные полисы, а в коробе «24555» -лежат только электронные карты.

Давайте представим все вышеописанное в виде схемы.

короб полисов омс

Задача состоит в том, чтобы сделать формирование акта о передачи полисов из определенных коробов на пункт выдачи, которому они предназначаются по описи. Важно: на разные типы полисов нужно разные формы акта.

Реализация…

Я опущу описание всего механизма реализации решения данной задачи, потому как эта статья об отчетах в Fast Report. Имеется реализованная форма для оформления процесса передачи полисов, к ней необходимо добавить вывод печатной формы:

реализаци передачи коробов

 

При выборе меню «Куда отправляем», формируется список доступных коробов – т.е.  короба, которые находятся в офисе. С помощью кнопок управления мы формируем список коробов которые хотим передать. В таблицу выбираются все полисы для указанного пункта выдачи. Видите в зеленом прямоугольнике у нас в один список попали электронные полисы (тип 2) и бумажные бланки (тип 1).

Может возникнуть ситуация, когда нужно отправить полисы из короба, но выбрать определённые – для этого нам необходима возможность дать пользователю выбирать запись или нет. По этой причине в табличке есть CheckBox.

Небольшое отступление. Некоторых новичков наверное мучает вопрос, как сделать такие CheckBox в табличке. Для их отображения я использовал компонент DBGridEh из Ehlib. В DBGridEh есть специальное свойство, с помощью которого можно отображать у каждой строки CheckBox. Находим свойство «IndicatorOpions»  и ставим галочки у «gioShowRowselCheckboxesEh» и «gioShowRowIndicatorEh». Второй параметр создает небольшой отступ от CheckBox, так выглядит более приятно. Ну как вы наверное догадались «gioShowRecNoEh» — это вывод номера строки. Если ставите это свойство, то табличка иногда даже становится похожа на Excel. При условии, что мне нужно выводить много похожих строк, я ставлю эту опцию – потому что так можно добиться более удобной навигации.

ChekBox в DBGridEh

В итоге мы у нас удобный и гибкий интерфейс для создания нужной нам выборки. Но вот в чем вопрос… Помните, что на электронные полисы и бумажные бланки актов должны быть разные, и еще одно ограничение — иногда требуется вывести только выбранные записи.  По этим причинам мы не можем просто передать данные из DataSource в Fast Report.

В поисках решения для описанной проблемы, я изучал мануалы по Fast Report 4. Обнаружил такую интересную фишку, что оказывается в качестве источника данных можно обычный массив с данными. Эврика!!!!

Алгоритм решения:

  • Создаем два массива — один под электронные полисы (Electronic), другой — для бумажных бланков (Paper).
  • Пробегаем в цикле по все выбранным строчкам и в зависимости от значения в поле «Тип полиса», записываем данные в один из массивов (Electronic, Paper).
  • Проверяем заполонен ли массив и выводим соответствующий отчет. В одном отчете можно создать два страницы отчета. Одна для бумажных бланков, другая для электронных полисов.

Создаем массивы.

type
 TPolis=array of array of String; //Описываем новый тип массива
вставлять сразу после описанных модуле

……..
……..

var
Paper,Electronic: TPolis; //Задаем их как глобальные переменные
i,CountP,CountE:Integer;

Готовим наш отчет в визуальном дизайнере отчетов Fast Report. Вот как у меня выглядит готовая основа отчета.

Основа отчета FastReport

 

Цветами я выделил области, на которых хотел бы заострить ваше внимание.

Зеленые —  это компоненты TMemo сейчас они пустые, так как будем заполнять мы из программно. Ниже я расскажу как работать с указателями на компоненты и даже целые листы отчета.

Оранжевым – это я вам показал, что у меня в отчете существует два листа, один для бумажных бланков, второй для электронных полисов (можно догадаться из названия). Оба листа похожи, между собой — различаются только заголовком под надписью «АКТ №». Но не смотря на то что, в визуальном дизайнере отчетов листы в отдельных вкладках, в готовом отчете он просто будут идти друг за другом.

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

Сначала я приведу вам весь код, который выполняется по кнопке «Передать выбранные полисы». А потом разберу отдельные моменты.


procedure TFormTransfer.ButtonSendClick(Sender: TObject);
var
 KobBloc,NumerAct:String;
 p,e:Integer; //Количество передаваемых бумажных и пластиковых
 TitlTipP,OtKydaP,KogdaP,NumerActP: TfrxMemoView;
 TextActP: TfrxMemoView;
 SdalKtoP,FIO1MP,PrinlP,FIO2MP,KodP: TfrxMemoView;

 TitlTipE,OtKydaE,KogdaE,NumerActE: TfrxMemoView;
 TextActE: TfrxMemoView;
 SdalKtoE,FIO1ME,PrinlE,FIO2ME,KodE: TfrxMemoView;

 ActPagePaper,ActPageElectronic:TfrxPage;
 TextActPaper,KorodPaper, TextActElectronic,KorodElectronic:String;
 R:Word;

begin

if (Length(cbKyda.Text)=0)  or (Length(cbKomy.Text)=0)   then
begin
   ShowMessage('Ошибка! Не хватает данных для формирования акта передачи!');
   exit;
end;

if DBgrid.SelectedRows.Count > 0 then // DBgrid.SelectedRows.Count
//это кол-во все выбранных строк
begin
 ButtonSend.Enabled:=False; //Отключаем кнопку что нельзя было нажать
//повторно пока мы не закончили
 Randomize;//Обновляем рандом
 KobBloc:=IntToStr(RandomRange(100000000, 999999999));   //  Генерируем код

 sql := 'SELECT * FROM ******** WHERE KodBlock='+C+KobBloc+C;
 Query.SQL.Clear;
 Query.SQL.Add(sql);
 Query.Open;

 if Query.RecordCount<>0 then
 begin
   ShowMessage('Не удалось сгенерировать уникальный код передачи! Поробуйте еще раз.');
   ButtonSend.Enabled:=True;
   exit;
 end;

/*  У меня здесь был вызов сохранной функции генерировала
уникальный номер акта, в следующей статье я опишу как это делается.*/

 ProgressOverall.MaxValue:=DBgrid.SelectedRows.Count-1; //Заполняем прогрессбар
 CountP:=0; ///Обнуляем счетчики
 CountE:=0;
 for I := 0 to DBgrid.SelectedRows.Count-1 do //Пробегаем по все выбранным полисам
 begin
   DBGrid.Datasource.Dataset.Bookmark:= DBgrid.SelectedRows.Items[i];  
//Переходим на запись

 ///  У меня здесь был вызов сохранной функции
///которая помечала полис как переданный

   if DBGrid.Datasource.Dataset.Fields[2].AsString='1' then CountP:=CountP+1;  
///Количество полисов бумажных
   if DBGrid.Datasource.Dataset.Fields[2].AsString='2' then CountE:=CountE+1;
///Количество полисов пластиковых

   ProgressOverall.Progress:=ProgressOverall.Progress+1;
 end;
 ProgressOverall.Progress:=0;
 SetLength(Paper, CountP);  //Задаем размер массива полисов бумажных
 SetLength(Electronic, CountE);  //Задаем размер массива полисов пластиковых
 p:=0;
 e:=0;

 KorodPaper:=''; //Это прости строка с перечисление коробов, для текста акта
 KorodElectronic:='';

 for I := 0 to DBgrid.SelectedRows.Count-1 do //Пробегаем по все выбранным полисам
 begin
   DBGrid.Datasource.Dataset.Bookmark:= DBgrid.SelectedRows.Items[i];  //Переходим на запись

   if CountP<>0 then   //Проверяем стоит ли искать что-то
   begin
     if DBGrid.Datasource.Dataset.Fields[2].AsString='1' then   //Запись бумажный полис или нет
     begin
       if p<CountP then
       begin
        SetLength(Paper[p], 5);  //Переходим на запись
        if Pos(' Короб № '+DBGrid.Datasource.Dataset.Fields[1].AsString,KorodPaper)=0 then
        begin
         if Length(KorodPaper)=0 then
          KorodPaper:=KorodPaper+' Короб № '+
              DBGrid.Datasource.Dataset.Fields[1].AsString
         else KorodPaper:=KorodPaper+', Короб № '+
              DBGrid.Datasource.Dataset.Fields[1].AsString;
        end;

        Paper[p,0]:=DBGrid.Datasource.Dataset.Fields[1].AsString;  //Пришем короб
        Paper[p,1]:=DBGrid.Datasource.Dataset.Fields[3].AsString;  //Пришем Фамилию
        Paper[p,2]:=DBGrid.Datasource.Dataset.Fields[4].AsString;  //Пришем Имя
        Paper[p,3]:=DBGrid.Datasource.Dataset.Fields[5].AsString;  //Пришем Отчество
        Paper[p,4]:=DBGrid.Datasource.Dataset.Fields[6].AsString;  //Пришем Дата рождения
       end;
       p:=p+1; //Наращиваем индекс
     end;
   end;

   if CountE<>0 then   //Проверяем ст стоит ли искать что-то
   begin
     if DBGrid.Datasource.Dataset.Fields[2].AsString='2' then   //Запись бумажный полис или нет
     begin
       if e<CountE then
       begin
        SetLength(Electronic[e], 5);  //Переходим на запись
        if Pos(' Короб № '+DBGrid.Datasource.Dataset.Fields[1].AsString,KorodElectronic)=0 then
        begin
         if Length(KorodElectronic)=0 then
          KorodElectronic:=KorodElectronic+' Короб № '+
          DBGrid.Datasource.Dataset.Fields[1].AsString
         else KorodElectronic:=KorodElectronic+', Короб № '+
             DBGrid.Datasource.Dataset.Fields[1].AsString;
        end;
        Electronic[e,0]:=DBGrid.Datasource.Dataset.Fields[1].AsString;  //Пришем короб
        Electronic[e,1]:=DBGrid.Datasource.Dataset.Fields[3].AsString;  //Пришем Фамилию
        Electronic[e,2]:=DBGrid.Datasource.Dataset.Fields[4].AsString;  //Пришем Имя
        Electronic[e,3]:=DBGrid.Datasource.Dataset.Fields[5].AsString;  //Пришем Отчество
        Electronic[e,4]:=DBGrid.Datasource.Dataset.Fields[6].AsString;  //Пришем Дата рождения
       end;
       e:=e+1; //Наращиваем индекс
     end;
   end;
 end;

 R:=MessageBox(Handle,PChar('Вы хотите сейчас сформировать Акт приема-передачи полисов?'),
PChar('Формирование Акта'),MB_ICONINFORMATION+MB_OKCANCEL+MB_DEFBUTTON1);
   if R= IDOK then
   begin
       ActPagePaper:=TfrxPage(frxReport1.FindObject('PagePaper'));
       //Записываем указатели на страницы отчета
       ActPageElectronic:=TfrxPage(frxReport1.FindObject('PageElectronic'));

       if CountP<>0 then
       begin
           ///Генерирование отчета о передачи бумажных полисов         
///Получаем указатели
           TitlTipP:=TfrxMemoView(frxReport1.FindObject('Title2P'));    //Второй заголовок
           OtKydaP:=TfrxMemoView(frxReport1.FindObject('OtKydaP'));     //Откуда
           KogdaP:=TfrxMemoView(frxReport1.FindObject('KogdaP'));       //От Куда
           TextActP:=TfrxMemoView(frxReport1.FindObject('TextActP'));     ///текст акта
           SdalKtoP:=TfrxMemoView(frxReport1.FindObject('SdalKtoP'));
           FIO1MP:=TfrxMemoView(frxReport1.FindObject('FIO1P'));
           PrinlP:=TfrxMemoView(frxReport1.FindObject('PrinlP'));
           FIO2MP:=TfrxMemoView(frxReport1.FindObject('FIO2P'));
           KodP:=TfrxMemoView(frxReport1.FindObject('KodP'));
           NumerActP:=TfrxMemoView(frxReport1.FindObject('NumerP'));

           TitlTipP.Memo.Clear;        //Очищаем
           OtKydaP.Memo.Clear;
           KogdaP.Memo.Clear;
           TextActP.Memo.Clear;
           SdalKtoP.Memo.Clear;
           FIO1MP.Memo.Clear;
           PrinlP.Memo.Clear;
           FIO2MP.Memo.Clear;
           KodP.Memo.Clear;
           NumerActP.Memo.Clear;
           NumerActP.Memo.Add(NumerAct);

          sql:='call num_to_text_3r('+IntToStr(CountP)+')';
          Query.SQL.Clear;
          Query.SQL.Add(sql);
          Query.Open;

          rtext:=Query.FieldByName('rtext').AsString;

          TitlTipP.Memo.Add('приема-передачи бумажных полисов ОМС');   ///Заполняем второй заголовок

         OtKydaP.Memo.Add('г. Оренбург');  //От Куда
         KogdaP.Memo.Add(date_now+' г.');  //Когда

         TextActPaper:='  Настоящий Акт составлен в том, что '+office1+' '+cbKomy.Text+
         'приняла, а филиал «*********», в лице '+office2+'а '+Fio2+','+
         ' передал бумажные полисы ОМС в количестве '+IntToStr(CountP)+' ('+rtext+')'+
         ' штук по ФИО и ДР ('+KorodPaper+'):';
         TextActP.Memo.Add(TextActPaper);

         ///Данные формируется из базы напрямую

          SdalKtoP.Memo.Add('Сдал '+office2);
          FIO1MP.Memo.Add(Fio2+'___________________');
          PrinlP.Memo.Add('Принял '+office1);
          FIO2MP.Memo.Add(cbKomy.Text+'___________________');
          KodP.Memo.Add(KobBloc);

          frxDataSetPaper.RangeEnd := reCount;       //Выводим на печать массив
          frxDataSetPaper.RangeEndCount := Length(Paper);

          ActPagePaper.Visible:=True;
       end
       else
       begin
         ActPagePaper.Visible:=False;
       end;

       if CountE<>0 then
       begin
        ///Генерирование отчета о предачи электронных полисов
         TitlTipE:=TfrxMemoView(frxReport1.FindObject('Title2E'));    //Второй заголовок
         OtKydaE:=TfrxMemoView(frxReport1.FindObject('OtKydaE'));     //Откуда
         KogdaE:=TfrxMemoView(frxReport1.FindObject('KogdaE'));       //От Куда
         TextActE:=TfrxMemoView(frxReport1.FindObject('TextActE'));     ///текст акта
         SdalKtoE:=TfrxMemoView(frxReport1.FindObject('SdalKtoE'));
         FIO1ME:=TfrxMemoView(frxReport1.FindObject('FIO1E'));
         PrinlE:=TfrxMemoView(frxReport1.FindObject('PrinlE'));
         FIO2ME:=TfrxMemoView(frxReport1.FindObject('FIO2E'));
         KodE:=TfrxMemoView(frxReport1.FindObject('KodE'));
         NumerActE:=TfrxMemoView(frxReport1.FindObject('NumerE'));

         TitlTipE.Memo.Clear;        //Очищаем
         OtKydaE.Memo.Clear;
         KogdaE.Memo.Clear;
         TextActE.Memo.Clear;
         SdalKtoE.Memo.Clear;
         FIO1ME.Memo.Clear;
         PrinlE.Memo.Clear;
         FIO2ME.Memo.Clear;
         KodE.Memo.Clear;
         NumerActE.Memo.Clear;

          NumerActE.Memo.Add(NumerAct);
          sql:='call num_to_text_3r('+IntToStr(CountE)+')';
          Query.SQL.Clear;
          Query.SQL.Add(sql);
          Query.Open;

          rtext:=Query.FieldByName('rtext').AsString;

          TitlTipE.Memo.Add('приема-передачи электронных полисов ОМС');   
         ///Заполняем второй заголовок

         OtKydaE.Memo.Add('г. Оренбург');  //От Куда
         KogdaE.Memo.Add(date_now+' г.');  //Когда

         TextActElectronic:='  Настоящий Акт составлен в том, что '+office1+' '+cbKomy.Text+
         'приняла, а филиал «***********», в лице '+office2+'а '+Fio2+','+
         ' передал электронные полисы ОМС в количестве '+IntToStr(CountE)+' ('+rtext+')'+
         ' штук по ФИО и ДР ('+KorodElectronic+'):';

         TextActE.Memo.Add(TextActElectronic);
         ///Данные формируется из базы напрямую

          SdalKtoE.Memo.Add('Сдал '+office2);
          FIO1ME.Memo.Add(Fio2+'___________________');
          PrinlE.Memo.Add('Принял '+office1);
          FIO2ME.Memo.Add(cbKomy.Text+'___________________');

          KodE.Memo.Add(KobBloc);

          frxDataSetElectronic.RangeEnd := reCount;  //Выводим на печать массив
          frxDataSetElectronic.RangeEndCount := Length(Electronic);
          ActPageElectronic.Visible:=True;
       end
       else
       begin
          ActPageElectronic.Visible:=False;
       end;
       frxReport1.ShowReport;
        Query2.Close;
        ListPeredaem.Clear;
        ButtonSend.Enabled:=True;
   end;
   if R= IDCANCEL  then
   begin
        Query2.Close;
        ListPeredaem.Clear;
        ButtonSend.Enabled:=True;
   end;
   ButtonSend.Enabled:=True;
end;
end;

В коде много комментариев, но я поясню несколько моментов.

Генерирование кода разблокировки- это специальная процедура которая создает 9-значное число, которое будет дописанно в конце акта передачи. Зачем? Необходимо как-то контролировать фактическое поступление переданных на пункт выдачи коробов с готовыми полисами. Иногда возникает ситуация когда последний переданный короб уже поступил в пункт выдачи, а отправленный ранее (например, накануне) еще «в пути». Т.е., если все делается вовремя и аккуратно, при фактическом поступлении короба в пункт выдачи выполняется процедура «Прием полисов по Акт у№…». При этом будет запрошен код разблокировки, указанный в акте. Если этого не сделать полис будет иметь статус «в пути» и не удастся оформить выдачу полиса на руки (полис ведь фактически уже находится на пункте выдачи). Получается такой вот контроль, всегда можно посмотреть фактическое наличие полисов в пункт выдачи.

В качестве передаваемого «объекта» могут быть не обязательно полисы, главное сама суть данного подхода, что без акта ты не можешь получить доступ к тому материалу который передается в электроном виде.

Теперь перейдем к работе с компонентами отчета. Алгоритм обращения к компоненту.

  1. Создаем переменную такого же типа, что и компонент, указатель на который хотим получить. Например:  TextActP: TfrxMemoView; (Компонент Memo),  ActPagePaper:TfrxPage; (Page – страничка отчета)
  2. Сохраняем указатель на компонент отчета.  При этом пользуемся методом FindObject(), в качестве параметра передается название компонента (помните я писал: давайте осмысленное название компонентов). После получения указателя, его нужно преобразовать функцией TfrxMemoView() – это для компонента Memo. Для других компонентов другая функция используется.  В общем виде все выглядит вот так: «TitlTipE:=TfrxMemoView(frxReport1.FindObject(‘Title2E’));»
  3. После сохранения указателя в переменную, работаем с ней как будто с обычным компонентом. Например, я очищаю перед заполнением. Потом заполняем.

TextActE.Memo.Clear;   
TextActElectronic:='  Настоящий Акт составлен в том, что '+office1+' '+cbKomy.Text+
' приняла, а филиал «Оренбург-РОСНО-МС», в лице '+office2+'а '+Fio2+','+
' передал электронные полисы ОМС в количестве '+IntToStr(CountE)+' ('+rtext+')'+
' штук по ФИО и ДР ('+KorodElectronic+'):';

TextActE.Memo.Add(TextActElectronic);

Как работать с элементами отчета Fast Report в Delphi мы разобрались. Дальше перейдем к выводу на печать  массива данных. Того самого динамического массива, который мы заполняли — Electronic, Paper.

Нам понадобится компонент TfrxUserDataSet (пользовательский DataSet), он находится в палитре “FastReport”.  У меня их специально два: frxDataSetPaper,frxDataSetElectronic. Далее нужно подготовить почву для отчета. Кидаем на отчет бэнд MasterData и прописываем в нем источник TfrxUserDataSet. Как это делается прочитайте предыдущую статью “Быстрый старт Fast Report. Делаем просто отчет.”. В бэнд MasterData, кидаем обычные Memo,  внутри которых пишем название поля, которое будем выводить. Название обязательно должно быть в квадрантных скобках например “[FamP]”, и желательно использовать латиницу. Я русские название не использовал, во избежание проблем с кодировками и возможных скрытых багов.

В итоге у вас должно получится например что так:

Пример бэнда MasterData

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

В компоненте frxReport находим событие OnGetValue. В событии пишем следующий код:


  if CountP<>0 then ///Проверяем есть что наших массивах (CountP - числов которое поределяло длину массива)

 begin

  if CompareText(VarName, 'KorobP') = 0 then //Ищем элемент по названию 

    Value := Paper[frxDataSetPaper.RecNo,0]; ///Перемещаемся по масиву по столбцу 0

  if CompareText(VarName, 'FamP') = 0 then

    Value := Paper[frxDataSetPaper.RecNo,1];

  if CompareText(VarName, 'ImP') = 0 then

    Value := Paper[frxDataSetPaper.RecNo,2];

  if CompareText(VarName, 'OtP') = 0 then

    Value := Paper[frxDataSetPaper.RecNo,3];

  if CompareText(VarName, 'DrP') = 0 then

    Value := Paper[frxDataSetPaper.RecNo,4];

 end;

 if CountE<>0 then

 begin

  if CompareText(VarName, 'KorobE') = 0 then

    Value := Electronic[frxDataSetElectronic.RecNo,0];

  if CompareText(VarName, 'FamE') = 0 then

    Value := Electronic[frxDataSetElectronic.RecNo,1];

  if CompareText(VarName, 'ImE') = 0 then

    Value := Electronic[frxDataSetElectronic.RecNo,2];

  if CompareText(VarName, 'OtE') = 0 then

    Value := Electronic[frxDataSetElectronic.RecNo,3];

  if CompareText(VarName, 'DrE') = 0 then

    Value := Electronic[frxDataSetElectronic.RecNo,4];

 end;

Важный момент: здесь должны быть описанны все элементы отчета в формате “[название]”. Если это условие не выполнить при открытии отчета получите ошибку, что не удалось найти элемент и его название.

Теперь когда все готово, просто перед открытием отчета пропишем наши массивы. Я тут использовал маленькую хитрость — проверяю если массив заполнен, то только в этом случае прописываю его в frxUserDataSet. Таким образом, например, формируем акт только с бумажными полисами, и у нас не будет ошибки “элемент не найдет….” для массива с электронными полисами (он останется пустым).

 frxDataSetElectronic.RangeEnd := reCount;  //Выводим на печать массив
 frxDataSetElectronic.RangeEndCount := Length(Electronic);
 frxReport1.ShowReport;

Ну вот собственно я и показал как работать программно с компонентами отчета в FastReport в Delphi. Так же рассказал как можно вывести на печать массив данных и еще несколько хитростей.

Жду с нетерпением ваших комментариев… С уважением, ваш Shinobi.

 

1 комментарий

  1. Kolambawew

    спасибо. очень хороший
    и полезный сайт.
    удачииуспехавам.

    Ответить

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

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.