Visual FoxPro 9 вводит технологию формирования отчетов с помощью объектов - object-assisted. Используя эту технологию и Ваши существующие отчеты, Вы можете расширить процесс формирования отчетов разными способами, например, такими как:

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

Система формирования отчетов Visual FoxPro 9 точнее описывается словами "с помощью объектов" чем термином "объектно-ориентированная". Генератор отчетов - это не объект. Однако когда Вы используете новую технологию, генератор отчетов передает большую часть своей работы объектам.

NoteПримечание

Дизайнер отчетов также не включает ссылки на классы Visual FoxPro, определенные в визуальной библиотеке классов (.vcx файлы) или в программе (.prg файлы) как на элементы отчета. Однако, используя новую технологию design-time, Вы можете использовать экземпляры классов Visual FoxPro для определения атрибутов элементов отчета. Эти классы шаблонов могут быть присоединены к структуре отчета, и обеспечить динамическое изменение форматирования и кодов методов в процессе выполнения отчета. Для получения дополнительной информации смотрите Расширения Отчетов XML данных.

Технология формирования отчета в процессе исполнения (Run-time)

В ранних версиях Visual FoxPro механизм генерации отчетов был "монолитным". Он выполнялся весь как единый процесс. На этапе проектирования отчета Вы имели возможность добавить некоторый код в различных местах, прежде всего, в месте начала или завершения процесса формирования полосы отчета.

В Visual FoxPro 9 генератор отчетов осуществляет перемещение указателя записи в области данных Ваших отчетов и вычисляет выражения. Но он делегирует процесс отображения результатов новому базовому классу Visual FoxPro с именем ReportListener. Поскольку Вы можете создать класс-наследник от класса ReportListener, то Вы можете влиять на процесс отображения отдельных объектов в отчете на много более детальном уровне, чем раньше. Для получения дополнительной информации смотрите Объект ReportListener.

Visual FoxPro Reporting Engine Overview graphic

Как активизировать процесс построения отчетов с помощью объектов

Вы можете использовать опцию OBJECT [TYPE <N>] в команде REPORT FORM или LABEL для того, чтобы сообщить генератору отчетов, что следует использовать объект на основе класса ReportListener или использовать тип объекта. Вы можете также сообщить генератору отчетов о необходимости использовать приложение, имя которого хранится в системной переменной _REPORTOUTPUT, для того, чтобы назначить соответствующий объект для Вас. Если Вы установите настройку SET REPORTBEHAVIOR в значение 90, то генератор отчетов автоматически будет использовать приложение, имя которого хранится в системной переменной _REPORTOUTPUT для получения объекта используемого каждый раз при выполнении команды REPORT FORM или LABEL.

Visual FoxPro Reporting Engine Print Path I graphi

Если Вы хотите вызвать команду REPORT FORM или LABEL только с целью отобразить окно предварительного просмотра, то система отчетов вызовет другой объект "PreviewContainer" для отображения предварительного просмотра после завершения его работ по вычислению и отрисовке содержимого отчета. Поскольку PreviewContainer это объект среды Visual FoxPro, то Вы можете создавать самые разнообразные предварительные просмотры, соответствующие условиям и задачам Ваших приложений. Для получения дополнительной информации о том, как создать объект, соответствующий требованиям PreviewContainer смотрите API Контейнер Предварительного Просмотра Отчетов.

Visual FoxPro Reporting Engine Preview Path I grap

Режимы работы генератора отчетов

Процесс обработки объектом ReportListener отчетов или этикеток может происходить в двух различных режимах в зависимости от значения его свойства ListenerType. Вы можете рассматривать эти два режима как "режим печати" и "режим предварительного просмотра", или "по странице за раз" и "все страницы разом".

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

В режиме "по странице за раз", класс ReportListener запускает событие OutputPage для формирования каждой страницы и одновременно отправляет каждую страницу на принтер или в очередь печати. Ваш класс наследник получает доступ только к той странице, которая только что была подготовлена и только в это время. Этот режим имеет смысл, если Вам надо получить доступ к каждой странице только один раз. Например, Вы могли бы сохранять каждую страницу на диске как изображение. Для получения более полной информации о возможностях и доступных опциях смотрите Метод OutputPage.

Visual FoxPro Reporting Engine Print Path II graph

В режиме "все страницы разом" ReportListener подготавливает все страницы для отображения и кэширует их. Событие OutputPage не срабатывает до тех пор, пока не будут подготовлены все страницы. Когда выполнение отчета завершается, Вы можете вызвать метод OutputPage чтобы получить доступ к любой странице отчета по ее номеру. Вы можете запрашивать страницы в любом порядке много раз.

Visual FoxPro Reporting Engine Preview Path II gra

Теперь отчет полностью подготовлен и готов к предварительному просмотру. В этот момент, если свойство Listenertype объекта ReportListener было установлено в значение 1, объект ReportListener вызывает объект, ссылка на который записана в его свойстве PreviewContainer для отображения предварительного просмотра.

Вы можете сохранить ссылку на любой объект, отвечающий требованиям PreviewContainer API в этом свойстве. Если в данном свойстве нет ссылки на объект, то Reportlistener попытается получить объектную ссылку из приложения, имя которого записано в системной переменной _REPORTPREVIEW.

Visual FoxPro Reporting Engine Preview Path III gr

Когда отчет полностью подготовлен, ReportListener вызывает метод SetReport объекта PreviewContainer. Эта операция передает объекту PreviewContainer ссылку на объект ReportListener, и показывает готовность объекта ReportListener к предварительному просмотру. В этот момент объект PreviewContainer принимает контроль над процессом подготовки отчета. Он использует метод OutputPage объекта ReportListener для запроса отображаемых страниц в той последовательности, в какой пользователь просматривает отчет.

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

Если пользователь решит распечатать отчет из интерфейса предварительного просмотра, то объект PreviewContainer вызовет метод OnPreviewClose объекта ReportListener с соответствующими параметрами. Объект ReportListener возвращает себе управление и отправляет на печать буфер предварительно подготовленной страницы. Для получения дополнительной информации, смотрите OnPreviewClose, Метод-Событие.

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

Процесс вывод во время исполнения (Run-time)

В последующем изложении описывается полное выполнение отчета. Как было описано в предыдущем разделе, есть несколько способов, при которых Вы можете быть уверены, что команда REPORT FORM или LABEL выполняются со ссылкой на объект. Различные способы вызова построения отчета с помощью объектов не изменяют последовательность вызова событий, описанную в данном разделе.

Генератор отчетов и базовый класс ReportListener выполняют формирование отчета в ряде событий, которые начинаются с события BeforeReport и завершаются событием AfterReport. Базовый класс ReportListener также предоставляет два внешних или рамочных (framing) события LoadReport и UnloadReport, которые позволяют создавать код "перед" и "после" процесса выполнения отчета.

NoteПримечание

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

Начало выполнения отчета

Когда команда REPORT FORM или LABEL начинают исполняться, генератор отчетов сначала проверяет, не включала ли предшествующая аналогичная команда ключевое слово NOPAGEEJECT. Это ключевое слово указывает, что несколько отчетов обрабатываются вместе и что некоторая часть отчета уже находится в очереди для возможного показа или печати.

Если предшествующие команды не содержали ключевое слово NOPAGEJECT, то значение свойства OutputPageCount объекта ReportListener сбрасывается в 0.

Затем генератор отчета создает специальную сессию данных для объекта ReportListener и предоставляет значение DataSessionID этой сессии объекту ReportListener, используя свойство FRXDataSession объекта ReportListener. Он также присваивает значение свойству CommandClauses объекта ReportListener; хотя не все свойства объекта CommandClauses доступны немедленно. Для получения дополнительной информации смотрите CommandClauses свойство.

Далее генератор вызывает событие LoadReport объекта ReportListener и оценивает возвращаемое значение любого пользовательского кода, который Вы можете написать в этом событии. Если событие LoadReport возвращает значение "Ложь" (.F.), то выполнение отчета на этом прерывается.

NoteЗамечание

Если Вы хотите изменить отчет или этикетку или текущий драйвер принтера, то событие LoadReport - это Ваша возможность сделать это. Вы можете также динамически изменить значение члена ReportListener.CommandClauses.Prompt и других членов объекта ReportListener.CommandClauses.

После события LoadReport генератор готов проанализировать содержимое таблицы отчета или этикетки. Если это предусмотрено в настройках, то генератор формирует частную сессию данных для хранения данных отчета. Он сохраняет значение DataSessionID для данных, которые будут обработаны в процессе выполнения отчета в свойстве CurrentDataSession объекта ReportListener.

Затем генератор отчетов переключается в сессию, идентификатор которой указан в свойстве FRXDataSession и открывает копию таблицы отчета или этикетки в режиме "только чтение" (read-only), используя алиас FRX в этой сессии.

NoteЗамечание

Генератор отчетов и объект ReportListener не используют эту копию таблицы отчета или этикетки; фактически они никогда больше не переключаются в эту сессию в процессе выполнения отчета. Генератор отчетов считывает содержимое таблицы в отдельную структуру, которую и использует впоследствии.

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

NoteПримечание

В этом разделе Вы узнали о двух сессиях данных, используемых в процессе выполнения отчета (их идентификаторы хранятся в свойствах CurrentDataSession и FRXDataSession). Эти две сессии данных наиболее важны для того, чтобы понять, как начать писать код объекта ReportListener. Однако другие сессии данных могут быть использованы в процессе выполнения отчета. Последующие разделы данной темы более подробно описывают соответствующие типы сессий данных.

Начало внутренней обработки выполнения отчета

Если свойство ListenerType объекта ReportListener установлено в значение 1 (печать) и если Вы использовали опцию PROMPT в команде выполнения отчета или этикетки или Вы установили свойство ReportListener.CommandClauses.Prompt в значение .T. в событии LoadReport, то в этот момент будет отображено диалоговое окно Print Setup. Начальные значения в этом диалоговом окне отображают любые значения опции RANGE, которые Вы использовали при подаче команды; однако реальные значения опции RANGE и членов объекта ReportListener.CommandClauses, которые будут использованы при печати отчета, могут быть изменены пользователем в диалоговом окне.

Когда пользователь закрывает диалоговое окно, генератор отчетов открывает очередь печати, если необходимо и если пользователь не отменил выполнение печати. Он также проверяет текущие установки принтера (даже если собственно печати не требуется) для того, чтобы определить текущие размеры страницы. Если Вы используете ключевое слово NODIALOG при подаче команды, но не устанавливаете свойство ReportListener.QuietMode в значение "Истина" (.T.), это свойство автоматически устанавливается в значение "Истина" (.T.) для сбалансированности выполнения отчета. Затем генератор отчетов выполняет событие BeforeReport.

NoteЗамечание

Здесь мы достигли последовательности событий, которые входят в родной (native) процесс выполнения отчета Visual FoxPro. Методы GetPageHeight и GetPageWidth объекта ReportListener вернули корректные значения. Все члены объекта CommandClauses подготовлены. Вы можете использовать метод CancelReport объекта ReportListener, начиная с данного момента и до окончания выполнения события AfterReport, если Вы хотите прервать и преждевременно закончить выполнение отчета.

После события BeforeReport генератор отчетов и объект ReportListener выполняют начальное определение различных аспектов таблицы отчета или этикетки. Например, они проверяют, была ли использована системная переменная _PAGETOTAL в выражениях отчета. Если была, то свойство TwoPassProcess объекта ReportListener устанавливается в значение "Истина" (.T.). Свойства CurrentPass объекта ReportListener в то же время устанавливается в значение 0. Для получения дополнительной информации смотрите CurrentPass свойство и TwoPassProcess свойство.

NoteПримечание

Вы можете установить свойство TwoPassProcess в значение "Истина" (.T.) вручную, если хотите заставить выполнить отчет в два прохода. Объект ReportListener учтет это ручное назначение, если Вы выполните его до выполнения команды REPORT FORM или LABEL в событии LoadReport или BeforeReport.

Обработка содержимого отчета

Генератор отчетов и объект ReportListener завершили фазу настроек. Теперь они приступают к обработке всех событий полос отчета относящихся к данному отчету. Между событиями BeforeBand и AfterBand каждой полосы отчета они обрабатывают каждый элемент отчета находящийся внутри соответствующей полосы. Каждый элемент отчета потенциально может иметь следующие события:

  • Событие EvaluateContents, если данный элемент это поле (Field) или выражение (Expression).

  • Событие AdjustObjectSize, если данный элемент это рамка (Shape) или изображение (Image). Если рамка или изображение не помещаются на странице, то данное событие может быть повторено еще раз на следующих страницах.

  • Начало выполнение многих событий Render для всех типов элементов отчета. Элемент не выполняет событие Render если его выражение "Print When" принимает значение "Ложь" (.F.). В противном случае срабатывает как минимум один раз событие Render, а возможно и большее количество раз, если объект охватывает несколько полос или страниц.

Если свойство ReportListener.TwoPassProcess имеет значение "Истина" (.T.), то генератор отчетов и объект ReportListener обрабатывают все полосы и элементы отчета дважды. Первый раз они вычисляют выражения и расположение на странице, фактически ничего не отображая. Это предварительная обработка (pre-processing), или проход вычисления (calculation pass). Это позволяет генератору отчетов рассчитать значение _PAGETOTAL для его использования при отображении результата на втором проходе при реальной отрисовке (rendering). Проход для предварительной обработки также предоставляет возможность Вашему коду рассчитать другие значения.

NoteЗамечание

Вы можете использовать ReportListener Debug Foundation Class для контроля выполнения событий отчета непосредственно в процессе их выполнения. Используйте свойство Verbose этого класса для того, чтобы проверить содержимое членов объекта CommandClauses класса ReportListener в различных точках процесса выполнения отчета и получить расширенную информацию о различных параметрах разных методов.

Завершение выполнения отчета

Последняя выполняемая полоса отчета - это либо полоса "Page Footer" либо полоса "Summary"; даже если Вы используете метод CancelReport объекта ReportListener, генератор отчетов сначала полностью завершит обработку текущей страницы, перед тем как прервать выполнение отчета.

После выполнения последней полосы отчета, объект ReportListener и генератор отчетов запускают процедуры очистки.

Частные сессии данных отчета, если таковые имеются, закрываются перед выполнением события AfterReport. Для того чтобы быть уверенным, что объект ReportListener всегда имеет корректный сеанс данных, в который он может вернуться, если отчет использовал частный сеанс данных, в этот момент свойство CurrentDataSession объекта ReportListener сбрасывается в значение 1, т.е. в значение по умолчанию. Если отчет не использовал частную сессию данных, то свойство CurrentDataSession не контролируется системой отчетов и не изменяется.

Затем вызывается событие AfterReport объекта ReportListener. После выполнения события AfterReport, формирование отчета завершено. Если поток печати был открыт для данного отчета, то теперь он закрыт. В этот момент метод CancelReport прекращает оказывать какое-либо влияние на внутреннюю обработку; он больше не может "выполнять отчет" с точки зрения генератора отчетов.

Свойство ReportListener.QuietMode восстанавливает значение "Ложь" (.F.), если оно было временно переключено вследствие использования ключевого слова NODIALOG.

Если свойство ReportListener.ListenerType имеет значение 1, то в этот момент объект ReportListener вызывает объект PreviewContainer для отображения результатов формирования отчета, выполняя UnloadReport после того, как PreviewContainer вернет управление ReportListener. Если значение свойства ListenerType отлично от 1, то метод UnloadReport объекта ReportListener будет выполнен немедленно.

После события UnloadReport, генератор отчетов закрывает специальную сессию данных, в которой открыта копия таблицы отчета или этикетки. В этот момент значение свойства ReportListener.FRXDataSession сбрасывается в значение по умолчанию -1, сигнализируя о том, что больше нет никакой сессии выполняющей эту задачу между выполнением отчета.

Свойство ReportListener.TwoPassProcess сбрасывается в значение по умолчанию .F.. Сбрасывая это свойство в его значение по умолчанию, ReportListener предоставляет Вам возможность явным образом повторно указать его значение перед следующим разом, когда Вы используете экземпляр объекта ReportListener. Значение свойства ReportListener.CurrentPass не обнуляется; его текущее значение дает Вам возможность определить, что случилось в предшествующем процессе выполнения отчета.

Если Вы не использовали ключевое слово NOPAGEEJECT в процессе выполнения данного отчета, то в этом месте методы GetPageWidth и GetPageHeight объекта ReportListener прекращают проверять корректность значений.

Сопоставление сеансов данных с выполнением отчетов с помощью объектов

Когда каждое событие объекта ReportListener начинает исполняться, то сессия данных - это та, в которой объект ReportListener был первоначально создан. Этот сессия данных не всегда та же самая, в которой Вы дали команду REPORT FORM или LABEL. Базовый фундаментальный класс ReportListener использует сессию ListenerDataSession связанную с соответствующим защищенным членом свойства для того, чтобы описать и управлять сессией данных в которой это произошло.

В "рамочных" (framing) событиях отчета (LoadReport и UnloadReport), Вы должны вернуться к сессии данных ListenerDataSession после завершения любых операций связанных с переключением в другие сессии данных. Генератор отчетов будет ожидать, что объект ReportListener находится в этой сессии данных после завершения указанных событий. Смотрите Команда SET DATASESSION для получения более подробной информации о переключении между сессиями данных.

При последовательном выполнении прочих событий отчета и внутренних процессов генератора отчета Ваш код объекта ReportListener обычно переключается между сессиями данных, идентификатор которых записан в свойствах Свойство CurrentDataSession и Свойство FRXDataSession объекта ReportListener. Переключение между этими двумя сессиями данных позволит Вам ссылаться на файлы данных отчетов и на копию таблицы отчета или этикетки в процессе выполнения отчета, если это необходимо.

Генератор отчетов также предоставляет Вам информацию о четвертой сессии данных: сессия данных, в которой выполняется команда REPORT FORM или LABEL. Вы найдете значение DataSessionID этой сессии как член StartDataSession свойства объекта Свойство CommandClauses. Обычно Вам нет необходимости ссылаться на эту четвертую сессию данных в коде объекта ReportListener. Необходимость в этом возникает, если Вам надо получить настройки среды окружения, в которой была дана эта команда. Например, Вы хотите проверить такую настройку как SET("DELETED"). Для получения дополнительной информации смотрите Настройка окружения сессии данных.

StartDataSession команд REPORT FORM или LABEL может быть той же самой, на которую ссылается свойство CurrentDataSession объекта ReportListener. Однако если в таблице отчета указана частная сессия данных для выполнения отчета, то CurrentDataSession и StartDataSession будут разными. StartDataSession также может быть той сессией, в которой объект ReportListener был создан, если объект ReportListener существует в контексте формы или объекта "session". Однако объект ReportListener часто существует в глобальном контексте, например в результате создания приложением "Report Output Application" или менеджером объектов, связанным с Вашим приложением. В этом случае значения StartDataSession и ListenerDataSession не связаны между собой.

Смотрите также