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

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

Соглашение по проектированию расширений системы отчетов

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

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

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

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

NoteЗамечание

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

Определите Вашу стратегию обработки ошибок и опубликуйте Ваши требования к объекту в этом приветствии.
Объекты ReportListener взаимодействует с обработчиком отчетов (Report Engine) уникальным образом, потому что они обрабатывают коды пользователя в течение одной  команды Visual FoxPro. Они также частично взаимодействуют с другим кодом пользователя в методах окружения данных и функциях пользователя (UDFs), включенных в файл отчета или наклейки.

Существуют различные способы обработки команды REPORT FORM, которые не совсем правильны. Смотри Обработка ошибок во время прогона отчета для информации и предложений. Когда Вы выберите стратегию будьте уверены, что пользователи  вашего класса ReportListener имеют правильную информацию для обеспечения правильной очистки в случае возникновения ошибки.

 
Разместите требуемые временные таблицы объекта ReportListener в специальной сессии для этой цели.

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

Caution noteВнимание

Убедитесь, что Вы переключились на соответствующую сессию данных во время прогона отчета, когда Вы хотите использовать копию отчета или  другие рабочие файлы. Для дополнительной информации см. Команда SET DATASESSION.

 

NoteПодсказка

Например, Объектно-ориентированный отчет, который использует дополнительные курсоры в сессии данных FRXD см. Report XML MemberData Extensions.

Сделайте различия между Свойством OutputType (Visual FoxPro) объекта ReportListener  и  Свойством ListenerType в вашем проекте.
OutputType дает вам значение, с которого Приложение вывода Отчета было вызвано, в то время как ListenerType представляет собственный режим генерации вывода, обеспечиваемый базовым классом ReportListener.

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

Пример: Влияние множества эффектов на множество типов вывода

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

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

  CopyCode imageКопировать код
DEFINE CLASS FX As Custom  && any base class
   * Требуемый интерфейс:
   PROCEDURE ApplyFX(toListener, tcProgram,;
                     tP1, tP2, tP3, tP4, tP5, tP6,;
                     tP7, tP8, tP9, tP10, tP11, tP12)
    * FXListener передает ссылку на себя как toListener,
    * PROGRAM() как tcProgram и
    * все параметры ReportListener как tP1 до tP12,
    * для каждого события ReportListener во время прогона.
    * Параметры от tP1 до tP12 передаются по ссылке,
    * поэтому изменения сделанные объектами effect видны
    * классу FXListener и его приемники возвращают из
    * этого метода.
   ENDPROC
ENDDEFINE

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

Пример ниже включает полный код для класса FXListener и простого класса "effect". Класс "effect" использует функцию UPPER() для всего выводного текста. Пример добавляет экземпляр класса  "effect" в коллекцию класса  FXListener. Он также назначает два приемника для FXListener (экземпляр ReportListener User Feedback Foundation Class и экземпляр ReportListener HTML Foundation Class) до того, как отчет будет вызван на прогон.

Изменения вывода отчета от  использования объектов "effect" отображаются в предварительном просмотре первичного класса ReportListener (экземпляр класса FXListener), также как вывод HTML генерируется объектом приемника  класса HTMListener в своей цепи.

 Работая одновременно, пользователь, по обратной связи с помощью класса ReportListener User Feedback , объединяет указатели на свойство PrintJobName первичного класса ReportListener, .

NoteПодсказка

Вывод текста изменяется на верхний регистр в методе Render даже при выполнении события EvaluateContents для лучшей призводительности. Использование Render также дает возможность изменять вывод элементов этикетки (Label layout), также как поле или выражение в отчете. Событие EvaluateContents не появляется для элементов этикетки.

Если Вы добавили объект "effect", который выполняет изменения фонта атрибутов, используя событие EvaluateContents , Вы увидите результаты этих изменений в предварительном просмотре. Однако, Вы не увидите тот же результат для  HTML; класс ReportListener HTML Foundation получает свой фонт атрибутов из элементов, определенных в FRX и не включает динамические изменения, сделанные во время прогона. Хорошо спроектированные классы "effect" учитывают возможности, требования и ограничения различных типов вывода, сгенерированных классом ReportListener.

Для получения других примеров классов "effect" см. Report XML MemberData Extensions.

  CopyCode imageКопировать код
#DEFINE FFC_HOME HOME() + "FFC\"

LOCAL loPrimaryRL, loSuccessorRL, loSuccessorRL2
loPrimaryRL = CREATEOBJECT("FXListener")
loSuccessorRL = NEWOBJECT("UpdateListener", ;
                FFC_HOME + "_ReportListener.vcx")
loSuccessorRL2 = NEWOBJECT("HTMLListener", ;
                FFC_HOME + "_ReportListener.vcx")

WITH loPrimaryRL
   .PrintJobName = "Проверка приемника FX (FX Listener Test)"
   .QuietMode = .T.
   .ListenerType = 1
   .FXs.Add(CREATEOBJECT("FXSimple"))
   .Successor = loSuccessorRL
ENDWITH
loSuccessorRL.Successor = loSuccessorRL2
loSuccessorRL2.QuietMode = .T.

REPORT FORM ? OBJECT loPrimaryRL  

* FXListener,
* "Эффекты использующие класс производный от ReportListener:
DEFINE CLASS FXListener AS _ReportListener OF ;
                 (FFC_HOME + "_reportListener.vcx")
   FXs = NULL
   PROCEDURE Init()
      THIS.FXs = CREATEOBJECT("Collection")    
   ENDPROC
   PROCEDURE SendFX(tcProgram, ;
     tP1, tP2, tP3, tP4, tP5, tP6, tP7, tP8, tP9, tP10, tP11,tP12)
      IF (NOT THIS.IsSuccessor) AND THIS.FXs.Count > 0
         * Только lead делает эту работу.
         * Для того, чтобы 
         * вызвать этот метод,
         * который заканчивается DODEFAULT()
         * для каждого события, 
         * сделайте результаты доступными 
         * для всех приемников.
          LOCAL loFX
          FOR EACH loFX IN THIS.FXs FOXOBJECT
              loFX.ApplyFX(THIS,tcProgram, ;
                           @tP1, @tP2, @tP3, @tP4, @tP5, @tP6, ;
                           @tP7, @tP8, @tP9, @tP10, @tP11, @tP12)
          NEXT
      ENDIF
   ENDPROC
   PROCEDURE BeforeReport()
      THIS.SendFX(PROGRAM())  
      NODEFAULT
      RETURN DODEFAULT()
   ENDPROC
   PROCEDURE AfterReport()
      THIS.SendFX(PROGRAM())  
      NODEFAULT
      RETURN DODEFAULT()
   ENDPROC
   PROCEDURE BeforeBand(nBandObjCode, nFRXRecNo)
      THIS.SendFX(PROGRAM(),nBandObjCode, nFRXRecNo)  
      NODEFAULT
      RETURN DODEFAULT(nBandObjCode, nFRXRecNo)
   ENDPROC
   PROCEDURE AfterBand(nBandObjCode, nFRXRecNo)
      THIS.SendFX(PROGRAM(),nBandObjCode, nFRXRecNo)  
      NODEFAULT
      RETURN DODEFAULT(nBandObjCode, nFRXRecNo)
   ENDPROC
   PROCEDURE EvaluateContents(nFRXRecno, oObjProperties)
       THIS.SendFX(PROGRAM(),nFRXRecno, oObjProperties)
       NODEFAULT
       IF (NOT ISNULL(THIS.Successor))
          THIS.SetSuccessorDynamicProperties()
          THIS.Successor.EvaluateContents(nFRXRecno, oObjProperties)
       ENDIF
       DODEFAULT(nFRXRecno, oObjProperties)
   ENDPROC
   PROCEDURE AdjustObjectSize(nFRXRecno, oObjProperties)
       THIS.SendFX(PROGRAM(),nFRXRecno, oObjProperties)
       NODEFAULT
       IF (NOT ISNULL(THIS.Successor))
          THIS.SetSuccessorDynamicProperties()
          THIS.Successor.AdjustObjectSize(nFRXRecno, oObjProperties)
       ENDIF
       DODEFAULT(nFRXRecno, oObjProperties)
   ENDPROC
   PROCEDURE Render(nFRXRecNo,;
                    nLeft,nTop,nWidth,nHeight,;
                    nObjectContinuationType, ;
                    cContentsToBeRendered, GDIPlusImage)
       THIS.SendFX(PROGRAM(),nFRXRecNo,;
                   @nLeft,@nTop,@nWidth,@nHeight,;
                   @nObjectContinuationType, ;
                   @cContentsToBeRendered, @GDIPlusImage)
       NODEFAULT 
       RETURN DODEFAULT(nFRXRecNo,;
                        nLeft,nTop,nWidth,nHeight,;
                        nObjectContinuationType, ;
                        cContentsToBeRendered, GDIPlusImage)
   ENDPROC
ENDDEFINE

* Пример класса FX, заполняющего контракт на разработку FX 
* установкой требуемого интерфейса:
DEFINE CLASS FXSimple AS Custom
   PROCEDURE ApplyFX(toListener, tcProgram,;
                     tP1, tP2, tP3, tP4, tP5, tP6, ;
                     tP7, tP8, tP9, tP10, tP11, tP12)
      IF ATC("Render",tcProgram) > 0
          tP7 = UPPER(tP7)
          * cContentsToBeRendered
          * является 7-ым параметром Render
          * Заметьте, что многие изменения свойства
          * cContentsToBeRendered в методе Render
          * будут требовать использования STRCONV() для
          * обеспечения результата в Unicode, хотя это
          * простое изменение не требует этого.
      ENDIF               
   ENDPROC
ENDDEFINE

Смотри также