Введение

В предыдущей статье был рассмотрен механизм интерактивных отчетов, который предоставляет ядро генератора отчета FastReport 5. Базовые возможности ядра генератора, были расширены и сегодня мы поговорим о новых способах создания интерактивных отчетов и способах их применения. Как говорилось ранее, FastReport предлагает несколько вариантов интерактивности, основные использование группировочных бэндов и гиперссылки. Интерес вызывает второй вариант – гиперссылки, где имеется возможность открытия детализирующего отчета с передачей ему параметров родительского отчета. Такую схему взаимодействия можно назвать реакцией «один к одному» и представить следующим рисунком.

 

 

 

 

 

 

 

 

 

Рис. 1 (схема взаимодействия «один к одному»)

Недостатком такого решения является жесткое определение единственного детализирующего отчета.

Но что делать, если мы хотим реализовать схему «один к многим»,

Рис. 2 (схема взаимодействия «один к многим»)

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


Реализация

1. Создание базового отчета

Добавим новый отчет в раздел справочники + каталог клиентов

1.1. Определение источника данных

На закладке «Данные» разместим запрос, дадим ему имя cusQ, в текст запроса поместим SQL для выбора клиентов по помеченным. Так как запрос имеет переменную :p3, в которую передается маркер, свяжем переменную из запроса с внешней переменной отчета.

Рис. 3. (создание базового отчета, определение источника данных)

1.2. Разметка страницы

Переходим на закладку Page1 дизайнера отчета и определяем внешний вид отчета, в нашем случае это список помеченных клиентов.

Рис.4 (создание базового отчета, разметка страницы)

1.2.1. Выбор объекта детализации

Объектом детализации будем называть объект отчета, после нажатия на который будут производиться действия по запуску детализирующих отчетов.

В нашем случае выберем объект - колонку с номером клиента.

Рис.5 (создание базового отчета, определение объекта детализации)

 

Чтобы как то выделить интерактивный объект в отчете, изменим свойство шрифта и сделаем объект похожим на ссылку, установив свойство курсора объекта crHandPoint (указательный палец) см. Рис.1

Перейдем на закладку «События» инспектора объектов. Здесь мы видим список доступных событий (реакций) объекта.
Событие OnPreviewDblClick – вызывается в режиме предварительного просмотра (Preview) при двойном нажатии мышью (Double Click)

Дважды  нажав мышью в инспекторе объектов напротив события OnPreviewDblClick, мы попадаем в редактор кода, где сможем определить какие действия будут совершены по двойному щелчку.

Рис.6 (создание базового отчета, редактор кода)

1.2.2. Код объекта детализации

В меню «Отчет» + «Переменные», дизайнера отчетов, доступен перечень переменных, функций и классов, которые вы можете в скриптовом языке отчета. На закладке, «функции» в блоке  «FRREP Интерактивные отчеты», доступны все необходимые функции для реализации интерактивных отчетов.

Рис.7 (создание базового отчета. Функции блока интерактивных отчетов)

 

Для создания и использования группы интерактивных отчетов нам потребуются три функции:

создание группы отчетов

Function CreateReportGroupList(
          GroupListName : String,
          REPORT_CAPTION : String,
          REPORT_ID : String,
          REPORT_TYPE_ID : String,
          REPORT_SORT : String,
          SID : String,
          P1 : String,
          P10 : String)

где:

         GroupListName           - имя создаваемой группы отчетов
         REPORT_CAPTION     - заголовок используемый при отображении группы
         REPORT_ID              - идентификатор отчета
         REPORT_TYPE_ID      - идентификатор типа отчета
         REPORT_SORT          - параметр сортировки
         SID                          - идентификатор сессии SESSION_ID
         P1…P10                    - параметры отчета P1…P10

 

Добавление отчета в именованную группу

Function AddReportToGroupList(
         GroupName : String,
         ReportCaption : String.
         ReportFileName : String)

где:

        GroupName                  - имя группы отчетов, куда будет добавлен отчет
        ReportCaption : String.  - заголовок отчета для отображения в списке
        ReportFileName : String - имя файла отчета (в каталоге UFS)

 

Отображение диалога выбора отчетов из именованной группы

Function RunReportFromGroupList(GroupListName)

где:

        GroupName                   - имя группы отчетов

Финальный код обработки события двойного клика:

//обработка двойного нажатия на объект отчета
procedure cusQICUSNUMOnPreviewDblClick(Sender: TfrxView; Button: TMouseButton; Shift: Integer; var Modified: Boolean);
var
   keyValue : String; //значение ключа для передачи в детализирующий отчет
begin
   keyValue :=  TfrxMemoView(Sender).Text; //записываем значение компонента на котором кликнули мышью в переменную    

   //создаем группу детализирующих отчетов для использования в механизме взаимодействия "один к многим"

   CreateReportGroupList('Группа1','Расшифровка показателя','','','','',
                                        keyValue,'','','','','','','','','');
                                     //^^^^^^^^^^^^^^^^
                                     //параметры P1...P10 для детализирующих отчетов "Группы1"
                                     //в данном случае в параметр P1 - передали номер клиента (keyValue) родительского отчета

    //наполняем созданную группу, списком детализирующих отчетов
   AddReportToGroupList('Группа1','Список счетов клиента','Xlesson5_1_cus_acc.fr3');
   AddReportToGroupList('Группа1','Список кредитных договоров клиента','Xlesson5_1_cus_cd.fr3');      
   AddReportToGroupList('Группа1','Операции по счетам клиента за период','Xlesson5_1_cus_operlist.fr3');

   //покажем диалог выбора отчетов Группы1
   RunReportFromGroupList('Группа1');        

end;

Мы создали группу отчетов «Группа1» и добавили в нее три отчета:

Таблица 1. (список детализирующих отчетов)

Наименование отчета

Файл отчета

Список счетов клиента

Xlesson5_1_cus_acc.fr3

Список кредитных договоров клиента

Xlesson5_1_fr3

Операции по счетам клиента за период

Xlesson5_1_cus_operlist.fr3

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

2. Создание детализирующего отчета «список счетов клиента»

Как показано в Таблице 1, для детализирующего отчета «Список счетов клиента» нам необходимо создать отчет с именем Xlesson5_1_cus_acc.fr3 (** для производных интерактивных отчетов, которые не являются cамостоятельными отчетами используем префикс «X» в имени файла)

Рис.8 (создание детализирующего отчета на новой вкладке.)

Создаем новый отчет на новой вкладке дизайнера, и сохраняем его с именем файла Xlesson5_1_cus_acc.fr3

 

2.1. Определение источника данных

На закладке «Данные» разместим запрос, дадим ему имя cusQ, в текст запроса поместим SQL для выбора клиентов по номеру.

Select icusnum, ccusname from cus
where icusnum = :icusnum

Свяжем параметр :icusnum с переменной P1 как показано на рисунке 9.

Рис. 9 (создание детализирующего отчета. Связывание переменных)

Почему же связываем параметр запроса :icusnum именно с переменной P1, а не P2 или P10?

Ответ кроется в вызове функции базового отчета:

CreateReportGroupList('Группа1','Расшифровка показателя','','','','',
                                     keyValue,'','','','','','','','','');
                                     //^^^^^^^^^^^^^^^
                                     //параметры P1...P10 для детализирующих отчетов "Группы1"
                                     //в данном случае в параметр P1 - передали номер клиента (keyValue) родительского отчета

Где мы создали группу отчетов в которой в параметр P1 передали номер клиента keyValue/

Добавляем второй источник данных accQ с SQL запросом отбора счетов по номеру клиента, где номер клиента будет определяться ведущим (master) запросом cusQ.

select * from acc where iacccus = :icusnum

Почему мы использовали master – detail запросы. Просто я хотел бы что бы Вы закрепили полученные знания на предыдущих уроках по созданию такого рода отчетов.
Для создания подчиненного источника данных, а именно таковым является наш accQ, в инспекторе объектов необходимо выставить свойство Master = cusQ

Внимание! Связывать поля детализирующего запроса с мастер запросом не требуется, если имя параметра детализирующего запроса совпадает с именем поля мастер запроса.

У нас такой параметр в подзапросе :icusnum совпадает с именем поля мастер запроса  icusnum.

 

 

Рис.10 (создание детализирующего отчета. Определение свойств подчиненного (deteil) источника данных.)

 

 2.2. Разметка страницы

Переходим на закладку Page1 дизайнера отчета и определяем внешний вид отчета. Нам потребуются два вида бандов первого и второго уровня, для мастер и детейл запроса соответственно. Произведем разметку отчета как показано на Рис.11

Рис.11 (создание детализирующего отчета. Разметка страницы.)

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

Детализирующий Отчет,   «Список кредитных договоров клиента» аналогичен текущему отчету и мы не будем рассматривать его реализацию. Вы сможете попробовать реализовать его самостоятельно в качестве закрепления материала. Интересен следующий отчет: «Операции по счетам клиента за период», разберем его.

 

3. Создание детализирующего отчета «операции по счетам клиента за период» доступ из отчета к формам ЦАБС

Интересным решением использования интерактивных отчетов является запуск форм ЦАБС в качестве расшифровки показателей отчета. Имеется два варианта запуска формы ЦАБС из отчета:

1. Без диалога ввода параметров
2. С диалогом ввода параметров.

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

Последний вариант более гибок и интересен, поэтому в нашем уроке мы рассмотрим именно этот вариант.

Итак, так как мы будем использовать диалог ввода параметров, нам понадобится новый отчет с диалоговой формой. Приступим к его созданию.

Как показано в Таблице 1, для детализирующего отчета «Операции по счетам клиента за период» нам необходимо создать отчет с именем Xlesson5_1_cus_operlist.fr3. Создадим новый пустой отчет и сохраним его с именем Xlesson5_1_cus_operlist.fr3.

 

3.1. Добавление диалога в отчет

Добавим диалог в отчет и поместим на форму компоненты выбора дат, присвоив им имена dt1 и dt2, две кнопки «Ок» и «Отмена».

 

Рис.12 (создание детализирующего отчета. Диалог интервал дат.)

Зададим свойства для кнопок «ОК» и «Отмена»:

Имя свойства

ОК

Отмена

Name

okButton

cancelButton

Caption

ОК

Отмена

ModalResult

mrOk

mrCancel

Если вы разместили в диалоге несколько элементов, то позаботьтесь о правильно выставленном свойстве TabOrder, чтобы ваши элементы правильно перебирались при использовании кнопки «Tab».

Для кнопки okButton, нам потребуется написать код обработки нажатия на кнопку (okButtonOnClick)

procedure okButtonOnClick(Sender: TfrxComponent);
var
   runstr : String;
   userid : String;
   sqlStr : String;                                      
   cusNum : String;
 begin
   //в переменную cusNum считываем значение внешнего параметра P1
   cusNum := TrimParam(Report.Variables.Variables('P1'));
   //формируем строку соединения БД, считывая значения соответствующих переменных отчета
   userid := TrimParam(Report.Variables.Variables('UserName'))+'/'+
                TrimParam(Report.Variables.Variables('Password'))+'@'+
                TrimParam(Report.Variables.Variables('Database'));
   sqlStr := 'trunc(dtrntran) between to_date('''+DateToStr(dt1.Date)+''',''DD.MM.RRRR'') and to_date('''+DateToStr(dt2.Date)+''',''DD.MM.RRRR'') ' +     
'and ('+
'      ctrnaccD in (select caccacc from acc where iacccus = '+cusNum+') or '+
'      ctrnaccC in (select caccacc from acc where iacccus = '+cusNum+')'+                
'    )';       
//формируем строку запуска ifrun60.exe для открытия формы operlist.fmx с фильтром отбора проводок
runstr := 'module=operlist.fmx userid='+userid+' where="'+ sqlStr+'"';  
//запускаем внешний процесс
RunProcess('ifrun60.exe', runstr);
end;

Появились новые функции, которые выделены в коде жирным шрифтом:

Function TrimParam(ParamValue : String) : String
Функция обрезает служебные символы, передаваемые ядром альтернативной печати. Рекомендуется выполнять перед использованием параметров в коде.
Что имеется ввиду? Почему есть такие рекомендации?
Дело в том, что строковые, передаваемые параметры могут содержать символы перевода строки, обрамляющие апострофы и потому при дальнейшем использовании таких параметров  скажем при динамическом формировании SQL запроса, могут возникнуть ошибки в правильности текста запроса, чтобы избежать неожиданностей, была введена данная функция.
Если вы уверены в том, что в передаваемых параметрах нет «мусора», использование данной функции не обязательно.
Пример применения функции:
значение до: '12345', значение после: 12345

Function RunProcess(FileName : String, CommandLine : String) : String
Функция запуска приложения FileName с параметрами командной строки CommandLine

Последняя функция собственно и запускает форму ЦАБС и в нашем случае, это форма отображения реестра документов Operlist.FMX.
Все формы Oracle Forms, запускаются с помощью клиентского приложения ifrun60.exe (Oracle Forms Runtime).
Для «правильного» запуска формы operlist.fmx нам остается сформировать командную строку запуска приложения ifrun60.exe.

Наша форма должна показать операции по счетам клиента (задаваемого номером P1), за период, определяемый в диалоге с dt1.Date по dt2.Date
Чтобы этого добиться, мы должны передать в форму Operlist.Fmx в параметр WHERE – условие отбора проводок.
Почему именно в параметр WHERE?
Дело в том, что если открыть исходный код формы, Operlist.FMB, мы увидим перечень параметров передающихся в форму, с помощью которых мы можем управлять данными отображаемыми данной формой (см. рис 13).

 

Рис.13 (Oracle Form Builder. Параметры, передающиеся форме OperList.FMX)

Подробности формирования командной строки для утилиты ifrun60.exe вы можете получить из справки, введя команду:

ifrun60.exe help=Y

ifrun60.exe userid=<uid/pwd> module=<form name> [parameters]

 

3.2. Установка свойств отображения страницы отчета

По сути, разработка детализирующего отчета, завершена. Отчет нам требовался, для использования диалога ввода дополнительных параметров. В нашем случае, отчет лишь запускает внешнее приложение, в которое передает необходимые параметры запуска и поэтому нам необходимо установить свойство «невидимый» страницы отчета  Page1.Visible := false (см. Рис. 14)

Рис.14 (установка свойства страницы отчета. «невидимая»)

 

Мы построили базовый отчет и детализирующие интерактивные отчеты. В разделе «Хранилище отчетов» вы можете скачать файлы отчетов урока.

Видео презентация урока:

В нашей следующей статье мы рассмотрим создание CrossTab отчетов.

Узнать дополнительную информацию о функционале генератора отчетов FastReport, а так же задать интересующие вас вопросы, Вы всегда можете, обратившись в службу технической поддержки компании Этот адрес электронной почты защищен от спам-ботов. У вас должен быть включен JavaScript для просмотра.