При разработке внешних печатных форм с использованием БСП (Библиотеки стандартных подсистем) программисты часто сталкиваются с ограничением: в отличие от табличного документа (ТабДок), где существует прекрасный метод ПроверитьВывод(), механизмы работы с Word-макетами не предоставляют встроенного способа узнать, уместится ли выводимая область на текущей странице. Это становится критичным, когда необходимо, например, перенести блок подписей или лист ознакомления на новую страницу целиком, не допуская его разрыва.
В этой статье мы подробно разберем, как обойти это ограничение, используя возможности самого Microsoft Word и программные методы взаимодействия через COM-соединение.
Прежде чем приступать к написанию сложного кода, проанализируем возможности самого макета. В большинстве случаев задачу можно решить без программирования логики переноса в 1С, изучив базовые принципы заполнения Word-макетов при помощи БСП и настроив свойства абзацев в файле .dot (шаблоне).
Рассмотрим по шагам, как заставить Word автоматически следить за целостностью блока:
Этот способ идеально подходит для небольших блоков подписей. Word сам рассчитает высоту и при необходимости перенесет весь блок на следующий лист.
Если логика требует более сложного поведения, нам придется обратиться к объектной модели Word, учитывая при этом возможную оптимизацию и ускорение печати в docx. Выясним причину, почему это работает: когда БСП формирует печатную форму, она создает COM-объект приложения MS Word. Мы можем использовать свойство Information объекта Selection или Range.
Рассмотрим пример кода, который позволяет определить вертикальную позицию курсора на странице. Мы используем константу wdVerticalPositionRelativeToPage (числовое значение 6), которая возвращает расстояние от верхнего края страницы в пунктах.
// Предположим, у нас есть объект Word-документа, полученный из БСП
ОбъектWord = ПечатнаяФорма.СведенияОПечатнойФорме.MSWord;
Курсор = ОбъектWord.Application.Selection;
// Получаем текущую вертикальную позицию (в пунктах)
ТекущаяПозиция = Курсор.Information(6); // 6 = wdVerticalPositionRelativeToPage
// Получаем параметры страницы
ВысотаСтраницы = ОбъектWord.PageSetup.PageHeight;
НижнееПоле = ОбъектWord.PageSetup.BottomMargin;
// Вычисляем доступное место
ДоступноМеста = ВысотаСтраницы - НижнееПоле - ТекущаяПозиция;
// Если предполагаемая высота нашей области (например, 100 пунктов) больше доступного места
Если ДоступноМеста < 100 Тогда
// Вставляем разрыв страницы программно
Курсор.InsertBreak(7); // 7 = wdPageBreak
КонецЕсли;
Проанализируем эту ситуацию: данный метод требует точного знания высоты выводимой области в пунктах, что не всегда удобно. Поэтому рассмотрим альтернативный "динамический" подход.
Этот метод напоминает принцип работы ПроверитьВывод(): мы пробуем вставить данные, смотрим, что получилось, и если результат нас не устраивает — откатываем или корректируем. Для быстрой реализации этого подхода можно использовать готовый шаблон внешней подключаемой печатной формы.
Разберем алгоритм по шагам:
ComputeStatistics.Посмотрим на пример реализации:
// 2 - это константа wdStatisticPages
КоличествоСтраницДо = ДокументWord.ComputeStatistics(2);
// Вызываем стандартный механизм БСП для вывода области
УправлениеПечатьюБСП.ЗаполнитьОбласть(ДокументWord, "Подписи", ДанныеПодписей);
КоличествоСтраницПосле = ДокументWord.ComputeStatistics(2);
Если КоличествоСтраницПосле > КоличествоСтраницДо Тогда
// Если нам нужно, чтобы блок был целиком на новой странице,
// нам пришлось бы вставить разрыв ПЕРЕД выводом области.
// В БСП это можно сделать, вставив символ разрыва в данные или макет.
КонецЕсли;
Часто в сообщениях форумов упоминается проблема "Листа ознакомления". Если список сотрудников большой, он неизбежно займет несколько страниц. Чтобы не потерять связь листов с основным приказом, воспользуемся особенностью таблиц Word.
Рассмотрим подробнее: если оформить область ознакомления в виде таблицы, мы можем программно или в макете установить свойство "Повторять заголовки на каждой странице".
Проанализируем преимущество этого метода:
HeadingFormat = Истина.Выясним причину, по которой иногда стоит последовать совету из "Сообщения 7" и переделать макет на ТабДок.
В современных версиях БСП (3.0 и выше) активно внедряется серверная печать в формате PDF. Если на сервере 1С не установлен Microsoft Office, стоит рассмотреть шаблон ВПФ для вывода в Word без использования COM-соединения. В тех случаях, когда БСП использует внутренние библиотеки для рендеринга, COM-объект MS Word не создается, и все методы типа ComputeStatistics или Information перестают работать.
Если ваша задача требует прецизионного контроля над каждым миллиметром страницы, а печать должна работать в фоновом режиме на сервере — Табличный документ будет гораздо надежнее. В нем вы сможете использовать стандартный и очень быстрый метод:
МассивОбластей = Новый Массив;
МассивОбластей.Добавить(ОбластьПодписи);
Если Не ТабДок.ПроверитьВывод(МассивОбластей) Тогда
ТабДок.ВывестиГоризонтальныйРазрывСтраницы();
КонецЕсли;
ТабДок.Вывести(ОбластьПодписи);
Подводя итог, можно сказать: прямого аналога ПроверитьВывод() для Word в БСП не существует, но мы обладаем широким арсеналом средств. Для простых случаев достаточно настройки "Не отрывать от следующего" в макете. Для сложных сценариев на клиенте используйте COM-объект Word и проверку вертикальной позиции. Если же требуется универсальность и работа на сервере — рассмотрите вариант переноса макета в формат ТабДок, используя проверенные шаблоны внешних печатных форм для БСП.