Внешняя печатная форма с сохранением дизайна в MS Word или LibreOffice из 1С
Шпаргалка по созданию внешней печатной формы, которая выводит результат в MS Word или в любой другой офисный пакет (LibreOffice, OnlyOffice, МойОфис и т.д.), который установлен на компьютере пользователя. При этом офисный пакет запускается даже на Linux (используем современный язык платформы 1С)!
Подготовка шаблона печатной формы
Верстаем в MS Word (LibreOffice, Google Doc) шаблон на красивом фирменном бланке с колонтитулами и логотипами, по следующему образцу. Просто набираем в лоб текст, без создания закладок и прочих хитростей:
В фигурных скобках находятся тэги, все они должны иметь формат {v8 ...}. Используются два вида тэгов:
- {v8 Область.ИмяОбласти} и {/v8 Область.ИмяОбласти} определяют начало и конец именованной области макета. Обязательно должен быть открывающий тэг и закрывающий! На печать вы выводятся.
- {v8 ИмяПараметра} - параметр, будет заменен значением при программном заполнении. Сохраняет форматирование (шрифт, цвет, фон)! Закрывающий тэг не нужен
Созданный шаблон загружаем в новый макет в двоичном формате:
По соглашению, принятому в библиотеке БСП имя макета должно иметь формат ПФ_DOC_НаименованиеМакета:
Подготовка внешней обработки
В модуль обработки добавляем стандарное описание внешней обработки для БСП. В качестве примера внешняя печатная форма добавлена назначением на справочник "Сотрудники":
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("3.1.9.232");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиПечатнаяФорма();
ПараметрыРегистрации.Версия = "1.0.0.1";
ПараметрыРегистрации.Информация = ЭтотОбъект.Метаданные().Синоним;
ПараметрыРегистрации.Назначение.Добавить("Справочник.Сотрудники");
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = ЭтотОбъект.Метаданные().Синоним;
НоваяКоманда.Идентификатор = ЭтотОбъект.Метаданные().Имя;
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
НоваяКоманда.ПоказыватьОповещение = Ложь;
Возврат ПараметрыРегистрации;
КонецФункции
Ключевые моменты в описании таковы (другие значения не годятся для нашей задачи):
Вид обработки: | ВидОбработкиПечатнаяФорма() |
---|---|
Тип команды: | ТипКомандыВызовКлиентскогоМетода() |
На следующем шаге нужно добавить форму и назначить её основной для внешней обработки. Эта форма необязательно должна показываться пользователю, и в моём примере она не показывается - поэтому ничего в ней не рисуем. Нам нужен только модуль этой формы и в модуле важна лишь одна экспортная процедура, которую будет искать и запускать БСП в контексте клиента:
&НаКлиенте
Процедура Печать(Идентификатор, ОбъектыНазначения) Экспорт
// ОбъектыНазначения - это массив ссылок на объекты, на которые мы
// назначили внешнюю печатную форму в описании. Их пользователь может выбрать
// как в форме элемента, так и в форме списка (множественный выбор)
Для Каждого ОбъектНазначения Из ОбъектыНазначения Цикл
Адрес = ВыполнитьПечатьDocxНаСервере(ОбъектНазначения);
// в Адресе находится адрес ВременногоХранилища с готовым результатом
// Как с ним поступить правильно покажу в конце статьи
КонецЦикла;
КонецПроцедуры
Программное заполнение
&НаСервере
Функция ВыполнитьПечатьDocxНаСервере(ОбъектНазначения)
ОписаниеОбластиТекст = Новый Структура("ИмяОбласти,ТипОбласти", "ТекстДоговора", "Общая");
ОписаниеОбластиВКолонтитул = Новый Структура("ИмяОбласти,ТипОбласти", "ВерхнийКолонтитул", "ВерхнийКолонтитул");
ОписаниеОбластиНКолонтитул = Новый Структура("ИмяОбласти,ТипОбласти", "НижнийКолонтитул", "НижнийКолонтитул");
ДвоичныеДанныеМакета = РеквизитФормыВЗначение("Объект").ПолучитьМакет("ПФ_DOC_Допсоглашение");
Макет = УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета,,);
АдресХранилищаПечатнойФормы = "";
ПечатнаяФорма = УправлениеПечатью.ИнициализироватьПечатнуюФорму(,,Макет);
Если ПечатнаяФорма = Неопределено Тогда
УправлениеПечатью.ОчиститьСсылки(Макет);
Возврат АдресХранилищаПечатнойФормы;
КонецЕсли;
// Пример вывода верхнего колонтитула
Область = УправлениеПечатью.ОбластьМакета(Макет, ОписаниеОбластиВКолонтитул);
УправлениеПечатью.ПрисоединитьОбласть(ПечатнаяФорма, Область, Ложь);
// Пример вывода нижнего колонтитула
Область = УправлениеПечатью.ОбластьМакета(Макет, ОписаниеОбластиНКолонтитул);
УправлениеПечатью.ПрисоединитьОбласть(ПечатнаяФорма, Область, Ложь);
// Тело печатной формы с параметрами:
ДанныеЗаполнения = ПолучитьДанныеДляПечатнойФормы(ОбъектНазначения);
// здесь мы должны получить структуру, ключ - имя параметра в шаблоне Word, значение - строка
Область = УправлениеПечатью.ОбластьМакета(Макет, ОписаниеОбластиТекст);
УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, Область, ДанныеЗаполнения);
АдресХранилищаПечатнойФормы = УправлениеПечатью.СформироватьДокумент(ПечатнаяФорма);
УправлениеПечатью.ОчиститьСсылки(Макет);
УправлениеПечатью.ОчиститьСсылки(ПечатнаяФорма);
Возврат АдресХранилищаПечатнойФормы;
КонецФункции
Разрывы страниц и разделов
Для вывода разрыва страниц нужно в макете добавить область по следующему образцу:
Обратите внимание, что область макета не может быть пустой (иначе БСП просто не выводит ничего), поэтому необходимо вставлять в область разрыва одну пустую строку.
ОписаниеОбластиРазрывСтраницы = Новый Структура("ИмяОбласти,ТипОбласти", "РазрывСтраницы", "Общая");
ОбластьРазрыв = УправлениеПечатью.ОбластьМакета(Макет, ОписаниеОбластиРазрывСтраницы);
УправлениеПечатью.ПрисоединитьОбласть(ПечатнаяФорма, ОбластьРазрыв);
К сожалению, с разрывом разделов библиотека на данный момент не умеет работать и такой фокус не работает! Как обходное решение, можно отдавать клиенту за один вызов два файла (например, в первом файле страницы в портретной ориентации, во втором - в альбомной).
Что ещё может БСП
В примере выше для простоты использованы не все типы областей. В описании функции УправлениеПечатью.ОбластьМакета можно подсмотреть их полный список:
// * ТипТипОбласти - Строка - тип области:
// "ВерхнийКолонтитул", "НижнийКолонтитул",
// "ВерхнийТитульныйКолонтитул", "НижнийТитульныйКолонтитул",
// "ВерхнийЧетныйКолонтитул", "НижнийЧетныйКолонтитул",
// "Общая",
// "СтрокаТаблицы",
// "Список".
Для заполнения таблиц в один заход в этом же модуле смотрите функцию ПрисоединитьИЗаполнитьКоллекцию.
Как вывести результат в любую офисную программу
Ниже пример самого древнего и протухшего кода. Перед выполнением необходимо записать двоичные данные в файл на компьютере клиента (вы знаете как это сделать):
Попытка
ОбъектВорд = Новый COMОбъект("Word.Application");
ОбъектВорд.Documents.Add(ИмяФайлаDocx);
ШаблонВорд = ОбъектВорд.ActiveDocument;
ОбъектВорд.Application.Visible = Истина;
ОбъектВорд.Activate();
Исключение
Сообщить("Разработчик передает пламенный привет линуксам, макосям,");
Сообщить("а также LibreOffice");
КонецПопытки;
Другой устаревший код - использовать процедуру глобального контекста ЗапуститьПриложение(ИмяФайлаDocx). Он работает только в Windows.
Если ОбщегоНазначенияКлиентСервер.ЭтоWindowsКлиент() Тогда
ЗапуститьПриложение(ИмяФайлаDocx);
ИначеЕсли ОбщегоНазначенияКлиентСервер.ЭтоLinuxКлиент() Тогда
Сообщить("Красноглазые пингвинусы должны страдать!");
ИначеЕсли ОбщегоНазначенияКлиентСервер.ЭтоOSXКлиент() Тогда
Сообщить("Нашёл деньги на макбук? Закажи печатку Эксперту по технологическим вопросам!");
ИначеЕсли ОбщегоНазначенияКлиентСервер.ЭтоВебКлиент() Тогда
Сообщить("За вами выехали!");
КонецЕсли;
К полному удовлетворению любителей макоси и линуксоводов существует более современный метод, добавленный в платформе 8.3.18:
// Адрес - адрес временного хранилища с результатом выполнения печатной формы
// ИмяФайла - предлагаемое имя файла если пользователь захочет его сохранить (необязательно)
ПолучитьФайлССервераАсинх(Адрес, ИмяФайла, Новый ПараметрыДиалогаПолученияФайлов());
При нажатии Открыть файл открывается в любом офисе, который назначен на полученный тип файла.