Печать отчета из скрипта

Подскажите пожалуйста, или ткните пальцем где почитать.
Как запускать отчет из скрипта и сразу же отправлять его на печать, без вывода на экран.
Версия: 3.0.2.242.

Нравится

47 комментариев

Нужно доработать функцию ShowReport так, что бы она передавала параметр в окно предпросмотра, говорящий о том, что нужно сразу печатать без предпросмотра. Как фариант сделать функцию PrintReport.
Функцию PrepareReport в scr_BaseFastReportPreview нужно доработать так, чтобы она анализировала этот параметр и вызывала PrintReport() вместо Self.Show при необходимости.
См. функции ProcessNotify и PrepareReport.

был бы признателен за примерчик

Извините, сейчас никак.

Добрый день, _e_u_!
Вопрос печати отчета без показа решается легко, но нужно предварительно ответить на следующие вопросы:
1) Все ли отчеты требуется сразу выводить на печать или только некоторые? Или выводить на печать в зависимости от некоторых условий?
2) Содержит ли отчет, подлежащий выводу на печать, форму предварительной фильтрации или нет? Если да, то какую - стандартную (настраиваемую при редактировании сервиса FastReport) или пользовательскую ?
3) Какого типа отчет планируется подавать на печать - для выделенной записи, для выделенных записей, для всех записей?

Ответы на эти вопросы существенно влияют на реализацию. Дело в том, что подготовка и показ отчета реализованы в окне wnd_BaseFastReportPreview, и собственно показ (Show для этого окна) выполняется в нескольких местах скрипта scr_BaseFastReportPreviewScript.
Предположим, что Вас интересует вариант с выводом отчета с показом стандартной формы фильтрации. Как совершенно правильно отметил Underscore, в этом случае показ окна отчета выполняется в функции ProcessNotify() указанного выше скрипта. Вам необходимо каким-то образом определить, что данный отчет нужно сразу печатать, и вместо Self.Show() реализовать следующее:

var ReportPreviewer = frpMain;
ReportPreviewer.Print();
Self.Close();

Однако, самый сложный вопрос - определить те случаи, в которых необходимо делать печать вместо показа. Реализация зависит от ответа на вопрос №1. В любом случае, придется вносить изменения в функции ShowReport(), ShowSingleRecordReport(), ShowSelectedRecordsReport() скрипта scr_ReportUtils (в зависимости от ответа на вопрос №3), с целью передать необходимый признак в окно предпросмотра отчета wnd_BaseFastReportPreview. Непосредственно передачу признака можно реализовать установкой атрибутов окна (примеры см. в этих же функциях).
Надеюсь, данный ответ поможет определиться с постановкой и реализовать задачу.

Спасибо за ответ.

1. на данном этапе 3 отчета должны автоматом выходить, при условии что стоит галочка "вывод на печать"
2. фильтрация данных происходит в скрипте
3. отчет получается "для выделенной записи"
Если интересно, то общий принцип:
После выбора определенных условий пользователем, и нажатия ОК, запускается скрипт, который формирует 3 типа документов. Для каждого из типов давно существуют отчеты, в данный момент отчеты формируют вручную указав на нужную запись и выбрав соответствующий отчет.
Поскольку я первый раз пробую вызывать отчет из скрипта, сейчас вот пытаюсь решить проблему, как сказать отчету какие данные выводить...жизненных примеров на форуме не получилось найти.

1. Неясно, где именно установлена галочка "вывод на печать".

Для изучения общего механизма создания и показа отчетов рекомендуется изучить код функции ReportMenuItemExecute() скрипта scr_ReportUtils. Эта функция - обработчик нажатия на пункт меню списка отчетов раздела. Для отчета типа "для выделенной записи", судя по всему, должна вызываться функция ShowSingleRecordReport().
Кстати, будет очень полезно в режиме отладки проверить, как выполняется код функции при показе требуемых отчетов. Это поможет быстрее реализовать задуманное.
Внутри этой функции Вам необходимо реализовать проверку того, что если строится один из интересующих отчетов (можно реализовать проверку по коду или USI отчета), то передавать в окно предпросмотра атрибут, который будет означать необходимость печати вместо показа.
В скрипте окна предпросмотра реализовать в функции PrepareReport() реализовать считывание этого атрибута и после построения отчета вместо его показа выполнять печать. Примеров для установки и чтения атрибутов в коде достаточно, код для выполнения печати отчета см. в предыдущем сообщении.
Желаю успехов!

"Гамора Дмитрий" написал: Неясно, где именно установлена галочка

Насколько я понял нужно напечатать три конкретных отчета. Т.е. нужно создать компонет превьювера (правда не уверен что он заработает без окна). Присвоить ему отчет, вызвать метод Prepare(), отфильтровать главный датасет отчета и вызвать у превьювера Print().
И так три раза.
Если распотрошить scr_BaseFastReportPreview, то там все кроме создания превьювера есть.
Удачи.

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

В общем, Underscore вполне четко изложил идею.
Насчет галочки - теперь понятно, что это настройка вводится пользователем, и легко передать ее в функцию ShowSingleRecordReport(), с целью последующей передачи признака с помощью атрибутов в окно предпросмотра, чтобы затем в скрипте окна проанализировать значение признака и осуществить либо показ, либо печать.
Если остались вопросы - буду рад помочь. Готовый пример сделать трудно в основном потому, что речь идет о целом наборе доработок, и Вам будет проще реализовать свой вариант, чем дорабатывать предложенный под Ваши условия.

ShowSingleRecordReport(ReportUSI, FilteredDatasetUSI, GridDatasetID)

GridDatasetID - айдишник выбраной записи в гриде?

Да. Названия параметров и функций в конфигурации иногда просто удивляют :)

В данном случае назначение параметра GridDatasetID почти очевидно, для полной ясности можно было бы назвать GridDatasetRecordID. Название GridDatasetID сложилось исторически, появилось с самых ранних версий системы.

Тогда уже просто RecordID, раз функция ShowSingleRecordReport называется. Причем тут вообще грид и датасет?

Потому что речь идет именно о считывании ID текущей записи, выбранной в разделе. Также, в функции ShowSelectedRecordsReport() без DataGrid не обойтись вообще, т.к. информация о нескольких выбранных записях в реестре хранится исключительно в компоненте, а не датасете. При именовании переменных разработчики старались давать исчерпывающие названия функциям и переменным.

А при чем здесь ShowSelectedRecordsReport. Я именно о ShowSingleRecordReport говорил. Функция печатает отчет, отфильтровав его датасет по одной записи. То что в одном конкретном случае идентификатор этой записи берется из грида раздела еще не повод называть соответствуюзий параметр с упоминанием грида и датасета.
То что старались, я не спорю. Просто разработчики бывают разные и стараются по разному :)

Согласен с Вами, Underscore. Думаю, продолжать спор не будем. Главное - это результат, в нашем случае означает успешную реализацию функции.

спасибо за советы.
так как все же правильней?
PrintReport()
или
var ReportPreviewer = frpMain;
ReportPreviewer.Print();
где можно посмотреть описание этих функций?
почему то так и так не идет на печать, сформировать документы из скрипта получилось с горем пополам:)

кстати странно, что на форуме такой задачи ни у кого не стояло...только я ее поднимал 2 года почти назад:)

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

Функция ReportPreviewer.Print() - функция ядра, библиотека TSReportLibrary.dll, осуществляет печать подготовленного отчета. В Вашем случае можно порекомендовать отладку кода, чтобы понять причину такого поведения.

Ну чтож, добился того, что у меня документы выпрыгивают пачками, как и хотелось:) но пока на экран
куда вставить Print() я понял, в отладчике прогонял, функция эта как будто просто мимо проходится...
может надо в нее параметр какой нибудь передать?...
и еще можно ли сказать этой функции, что печатать надо 2 копии?

Печатать можно только подготовленный отчет (т.е. после выполнения ReportPreviewer.Prepare()).

На самом деле, по нажатию кнопки "Печать" в окне предпросмотра отчета, выполняется только метод  frpMain.Print(); и больше ничего.

По сути дела, Вам необходимо выполнить построение отчета, но после этого не показывать окно с отчетом, а осуществить его печать.

Метод Print() не принимает параметров, при его выполнении осуществляется показ стандартного окна настройки печати, в котором при необходимости можно установить количество копий, качество печати и т.п.

А если мне не нужно стандартное окно настройки печати? можно заставить скрипт нажать кнопку Печать самостоятельно?

получилось вызвать окно печати с помощью  frpMain.Print();   , но предварительно вызвав  Self.Show(); ....

это функция из scr_ReportUtils :

function ShowSingleRecordReport(ReportUSI, FilteredDatasetUSI, GridDatasetID) 

{

var Report = Services.GetNewItemByUSI(ReportUSI);

var  ReportPreviewer =  Services.GetNewItemByUSI('wnd_BaseFastReportPreview');

var  ReportPreviewerComponent =  ReportPreviewer.Attributes('ReportPreviewer');

var ReportDataset =  Services.GetNewItemByUSI(FilteredDatasetUSI);

SetAttribute(ReportPreviewer,  'Report', Report);

ApplyDatasetFilter(ReportDataset, 'ID',  GridDatasetID,  true);

ReportPreviewer.Build(); ReportPreviewer.Prepare();

ReportPreviewerComponent.DatasetByComponentName(FilteredDatasetUSI)  = ReportDataset;



это функция из scr_BaseFastReportPreview

function PrepareReport(AWindow) {

....................................   

var EfPrintDocs =  Connector.Attributes('EfPrintDocs');

var ActPrintDocs =  Connector.Attributes('ActPrintDocs');

var InvPrintDocs =  Connector.Attributes('InvPrintDocs');

if  ((EfPrintDocs)||(ActPrintDocs)||(InvPrintDocs))   {      

// PrintReport();   // Self.Close();

      Self.Show();

             }else  {   

Self.Show();            }  



}

}   else {   

var EfPrintDocs =  Connector.Attributes('EfPrintDocs');

var ActPrintDocs =  Connector.Attributes('ActPrintDocs');

var InvPrintDocs =  Connector.Attributes('InvPrintDocs');

if  ((EfPrintDocs)||(ActPrintDocs)||(InvPrintDocs))   {       

//PrintReport();    //Self.Close();    Self.Show();    }else   {    Self.Show();    }   }}



вставляя в scr_BaseFastReportPreview функцию PrintReport() получается что на печать идет отчет не прошедший до конца

функцию ShowSingleRecordReport , а именно строку ReportPreviewerComponent.DatasetByComponentName(FilteredDatasetUSI)  = ReportDataset;

по всей видимости нужно PrintReport() размещать в скрипте scr_ReportUtils ?

или я что то перепутал? попробовал, ругается на frpMain 

 



прошу прощения за форматирование....чето оно дикое какое то тут... или я

frpMain это компонент окна предпоомотра. Понятно что в scr_ReportUtils ругается.

Кстати вызов ReportPreviewerComponent.DatasetByComponentName в scr_ReportUtils меня тоже немного смущает. Как оно работает? Мы сначала показываем отчет, а потом присваиваем датасет отчету.

Underscore a.k.a.

А как обратиться к frpMain  из scr_ReportUtils?

а по поводу ReportPreviewerComponent.DatasetByComponentName(FilteredDatasetUSI)  = ReportDataset;

не могу ничего сказать, так было изначально... но ведь работает как то:)

Вот и меня больше всего удивляет. На первый взгляд бред написан. Но работает. :)

Можно создать frpMain. Имя кокласса TSDskWindowLibrary.DskFastReportPreviewer.

Создавать



var Previewer = Services.CreateObject('TSDskWindowLibrary.DskFastReportPreviewer');

Но! Это компонент окна и как он будет без окна работать я не знаю. У него есть метод Build.Судя по названию он что-то важное делает. Возможно нужно его вызывать до печати отчета. Хотя недавний случай со свойством IsDesigning говорит о том что всяко может быть и возможно этот метод совсем не нужен :)



Удачи. Отпишитесь, если все заработает.

на строке var Previewer = Services.CreateObject('TSDskWindowLibrary.DskFastReportPreviewer');



говорит "Объект не поддерживает это свойство или метод"....мож скрипт какой подключить?

скопируйте сервис wnd_BaseFastReportPreview с его скриптом

назовите его wnd_BaseFastReportPreviewWithoutShow

и поменяйте функцию



function PrepareReport(AWindow) {

 CheckAttribute(AWindow, 'Report');

 frpMain.Report = GetAttribute(AWindow, 'Report');

 var FiltersCaption = frpMain.Report.Caption + " (Фильтры)";

 var PreviewCaption = frpMain.Report.Caption + " (Предпросмотр)";

 frpMain.PrepareReport();

 Self.WindowCaption = PreviewCaption;

 if (IsAttributeExists(AWindow, 'ShowFilterForm'))

 {

  if (IsAttributeExists(AWindow, 'FilterForm')) {

   var FilterForm = GetAttribute(AWindow, 'FilterForm');

   FilterForm.Attributes('NotifyObject') = AWindow;

   FilterForm.Attributes('ReportPreviewer') = frpMain;  

   FilterForm.Prepare();

   FilterForm.WindowCaption = FiltersCaption;

   FilterForm.Show();

  } else{

   if (frpMain.Report.FiltersXML != EmptyStr) {

    BaseFastReportPreview.FiltersWindow =

     Services.GetNewItemByUSI(ReportFiltersWindowUSI);

      BaseFastReportPreview.FiltersWindow.Attributes('NotifyObject') =

       AWindow;

      BaseFastReportPreview.FiltersWindow.Attributes('ReportPreviewer') =

     frpMain;

      BaseFastReportPreview.FiltersWindow.Attributes('FastReport') =

     frpMain.Report;

      BaseFastReportPreview.FiltersWindow.Prepare();

      BaseFastReportPreview.FiltersWindow.WindowCaption = FiltersCaption;

    BaseFastReportPreview.FiltersWindow.Show();

   } else {
     frpMain.PreviewReport();

     frpMain.Print();

   }
  }

 }  else {
   frpMain.PreviewReport();

   frpMain.Print();

 }
}



должен работать

Хм. Оказывается одного Print не хватало. Нужен еще и PreviewReport. Спасибо, запомню.

Там еще ProcessNotify нужно подправить по хорошему. Ну для того что бы работало если будет форма фильтрации. И может все-таки переделать на использование параметров. Ато две почти одинаковые формы не совсем красиво. Ну это уже на Ваше усмотрение.



Прошу прощения



 var Previewer = System.CreateObject('TSDskWindowLibrary.DskFastReportPreviewer');

вроде все срабатывает, окно печати появляется и просто зависает падает вся срм...

напомню, что если стоит Self.Show(); то все работает на ура

я думаю окно печати можно накрутить так чтобы оно не появлялось :-) 

а как? псоветуйте?

почти добил же задачу:)

в идеале у меня будут около сотни отчетов по разным документам (сформированным автоматически) выходить на печать

Может пусть окно появляется. Вызываем Print и закрываем окно. Или включаем таймер, который его закроет через какое-то время. 

как обратиться к этому окну печати?

Закрыть можно из самого же окна Self.Close() ;

Self.Close() ;  разве не окно предпросмотра закрывает?

как сказать, чтоб нажалась кнопка ОК в окне печати?

и в чем может быть причина зависания СРМ? абсолютно тот же код, только вместо 

   frpMain.PreviewReport();

   frpMain.Print();

стоит

Self.Show();

он работает.

виснет непосредственно после появления окна печати. дебагер показывает последней команду frpMain.Print();

---виснет непосредственно после появления окна печати. дебагер показывает последней команду frpMain.Print(); ---

после команды print() управление переходит к окошку предпечати , пока не выполнится либо печать либо отмена , скрипт будет ждать

Ну кто нибудь? :)

А увас нормально принтер настроен? Т.е. если сделать Self.Show(); и руками кнопку печати нажать?



Вы пробовали сделать так





...

Self.Show();

if (Признак что отчет просто печатаем) {

 frpMain.Print();

 Self.Close() ;

}

...

А увас нормально принтер настроен? Т.е. если сделать Self.Show(); и руками кнопку печати нажать?







да, нет проблем с этим...

А так как я предлагал, прообывали? Показать окно-напечатать-закрыть. Программно разумеется :)

попробовал

ну во первых, как я понял frpMain.Print(); - это не печать отчета, а только отображения окна печати, сейчас стоит вопрос как программно нажать в этом окне кнопочку ОК.

а второе, в данном варианте почему то отчет стал некорректно формироваться, как будто не отфильтровались данные.

С фильтрами наверное это связано с той строкой

 ReportPreviewerComponent.DatasetByComponentName(FilteredDatasetUSI) = ReportDataset;

Она не отрабатывает и датасет не фильтруется. Как-то эта печать через гланды сделана.  Нужно передавать FilteredDatasetUSI GridDatasetID  в атрибуты окна предпросмотра и уже в этом окне фильтровать датасет. А не делать это в ShowSingleRecordReport.



Програмно наверное не получится (вариант написания COM, который возьмет верхнее окно, найдет в нем кнопку Ок и отправит ей сообщение нажаться не рассматриваем :) ) В ReportPreviewer-е вынесен только метод Print. Параметров у него нет.  Другого метода для печати без показа диалогового окна тоже нет :(

невесело....тогда буду создавать другой топик:))

"_e_u_" написал:сейчас стоит вопрос как программно нажать в этом окне кнопочку ОК.
а второе, в данном варианте почему то отчет стал некорректно формироваться, как будто не отфильтровались данные.

Столкнулся с такой же проблемой. "Нажать" программно кнопку ОК в окне печати не удалось.
Проблема с неправильной фильтрацией набора данных для отчета решилась так:
1. В функцию ShowSelectedRecordsReport (думаю, с ShowSingleRecordReport подойдет такое же решение) добавлен еще один параметр - ForcedPrinting. При вызове функции из скрипта необходимо передавать с его помощью какое-либо значение.
2. В конце функции ShowSelectedRecordsReport после строки

ReportPreviewerComponent.DatasetByUSI(FilteredDatasetCode) = ReportDataset;

выполнить функцию PrintReport скрипта scr_BaseFastReportPreviewScript, если вызов ShowSelectedRecordsReport произведен с параметром ForcedPrinting

if (ForcedPrinting) {
		ReportPreviewer.ScriptControl.Run('PrintReport');
	}

т.е. окно печати появится уже после того, как к отчету будет "привязан" отфильтрованный набор данных.

Показать все комментарии