При формировании печатных форм в среде «1С:Предприятие 8» разработчики часто сталкиваются с жесткими рамками стандартного функционала. Типичный пример такой задачи — необходимость убрать нижний или верхний колонтитул на самой последней странице отчета или договора (например, чтобы освободить место под подписи и печати сторон). Для освоения базовых принципов разработки подобных отчетов полезно изучить методику создания внешних печатных форм на основе типовых решений.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем архитектурные ограничения платформы и рассмотрим три практических способа реализации этой задачи: от простого визуального лайфхака до профессионального метода ручной разбивки страниц.
В платформе 1С объект ТабличныйДокумент имеет встроенные свойства для настройки колонтитулов (например, НижнийКолонтитул.Выводить или НижнийКолонтитул.НачальнаяСтраница). Однако у колонтитула нет свойства конечной страницы.
Платформа позволяет лишь задать страницу, с которой начнется вывод колонтитулов, но не позволяет штатно указать страницу, на которой этот вывод должен прекратиться. Именно из-за этого ограничения нам приходится прибегать к обходным путям разработки.
Если на последней странице вашего документа выводится фиксированная область (например, реквизиты и подписи сторон в договоре), мы можем применить оригинальный визуальный трюк. Суть метода заключается в том, чтобы обмануть механизм определения номеров страниц платформы.
Давайте разберем этот алгоритм по шагам:
ТабДок.ВывестиГоризонтальныйРазделительСтраниц().Посмотрим на пример реализации данного метода в коде:
// Создаем результирующий табличный документ
ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("МакетДоговора");
// 1. Сначала выводим финальную страницу (которая по логике должна быть последней)
ОбластьПодписи = Макет.ПолучитьОбласть("ПодписиСторон");
ОбластьПодписи.Параметры.Заполнить(ДанныеДляПечати);
ТабДок.Вывести(ОбластьПодписи);
// 2. Вставляем принудительный разделитель страниц
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
// 3. Выводим основные (первые) страницы документа
ОбластьТекстДоговора = Макет.ПолучитьОбласть("ОсновнойТекст");
ОбластьТекстДоговора.Параметры.Заполнить(ДанныеДляПечати);
ТабДок.Вывести(ОбластьТекстДоговора);
// 4. Настраиваем колонтитул так, чтобы он не выводился на первой физической странице
ТабДок.НижнийКолонтитул.Выводить = Истина;
ТабДок.НижнийКолонтитул.НачальнаяСтраница = 2;
ТабДок.НижнийКолонтитул.ТекстВЦентре = "Страница [&НомерСтраницы] из [&СтраницВсего]";
Результат: На первой напечатанной странице (где выведены подписи) колонтитул выводиться не будет, а на всех последующих (основных) страницах — отобразится. Единственным минусом этого метода является то, что при просмотре документа на экране порядок страниц будет нарушен (финальный лист окажется первым), но при двусторонней физической печати или правильной подборке листов это решает задачу без написания громоздких алгоритмов проверки вывода.
Если порядок страниц на экране критически важен для пользователей, мы можем сформировать документ стандартным образом, но перед выводом разделить его на две части. Первая часть (все страницы, кроме последней) будет содержать включенные колонтитулы, а вторая часть (последняя страница) будет напечатана без них.
Проанализируем этот подход подробнее:
ТабличныйДокумент.КоличествоСтраниц() мы узнаем общий объем получившегося файла.ТабличныйДокумент.НижнийКолонтитул.Выводить = Ложь.Этот метод чист с точки зрения кода, но требует от разработчика точного понимания того, где именно проходит граница последней страницы, чтобы перенос областей во второй табличный документ не нарушил структуру данных.
Самым гибким, надежным и профессиональным решением является полный отказ от встроенных колонтитулов 1С в пользу собственных областей макета, вывод которых мы будем контролировать вручную.
Выясним причину, почему это лучше: ручной контроль вывода через метод ПроверитьВывод() позволяет нам абсолютно точно знать, в какой момент страница заполняется, и программно решать, добавлять ли нижний колонтитул на текущий лист или нет.
Рассмотрим по шагам рабочий алгоритм реализации этого метода:
НижнийКолонтитул).Давайте посмотрим на практический пример кода, реализующий эту логику:
// Создаем результирующий документ и получаем области макета
ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("НашМакет");
ОбластьСтрока = Макет.ПолучитьОбласть("СтрокаДанных");
ОбластьКолонтитул = Макет.ПолучитьОбласть("РучнойКолонтитул");
// Массив областей для выполнения проверки
МассивДляПроверки = Новый Массив;
// Предположим, у нас есть массив или таблица значений "ВыборкаСтрок"
КоличествоСтрок = ВыборкаСтрок.Количество();
Для Индекс = 0 По КоличествоСтрок - 1 Цикл
СтрокаДанных = ВыборкаСтрок[Индекс];
// ВАЖНО: Сначала заполняем параметры области реальными данными!
ОбластьСтрока.Параметры.Заполнить(СтрокаДанных);
// Определяем, является ли текущая строка последней в документе
ЭтоПоследняяСтрока = (Индекс = КоличествоСтрок - 1);
МассивДляПроверки.Очистить();
МассивДляПроверки.Добавить(ОбластьСтрока);
// Если строка НЕ последняя, мы обязаны резервировать место под колонтитул
Если Не ЭтоПоследняяСтрока Тогда
МассивДляПроверки.Добавить(ОбластьКолонтитул);
КонецЕсли;
// Проверяем, помещаются ли строка (и колонтитул, если строка не последняя) на страницу
Если Не ТабДок.ПроверитьВывод(МассивДляПроверки) Тогда
// Места не хватает. Если мы выводили не последнюю строку,
// сначала закрываем текущую страницу выводом колонтитула:
Если Не ЭтоПоследняяСтрока Тогда
ОбластьКолонтитул.Параметры.НомерСтраницы = ТабДок.КоличествоСтраниц() + 1;
ТабДок.Вывести(ОбластьКолонтитул);
КонецЕсли;
// Переносим указатель печати на новую страницу
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
// Выводим саму заполненную строку данных
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Обратите внимание на важнейшее правило разработки в 1С: заполнение параметров области макета (через свойство Параметры.Заполнить() или прямым присвоением) должно происходить строго до вызова метода ПроверитьВывод().
Если ваша область содержит параметры, у которых включено свойство «Размещать: Переносить» (многострочный текст), то пустая область макета и область, заполненная длинным текстом, будут иметь совершенно разную высоту в пикселях. Проверка незаполненной области вернет результат Истина (все помещается), но после заполнения реальными данными высота строки увеличится, что приведет к сдвигу макета, некорректному разрыву страниц и "наползанию" текста на границы листа.
Если вы все же решили использовать стандартные колонтитулы 1С, помните о правиле их инициализации: настройки встроенных колонтитулов (такие как Выводить, ТекстВЦентре и т. д.) необходимо применять после того, как в ТабличныйДокумент выведена хотя бы одна область, либо после полного формирования документа. В противном случае настройки могут сброситься до значений по умолчанию, заданных в самом макете.
Также учитывайте формат финального использования документа пользователями: