Как не выводить колонтитул на последней странице табличного документа в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При формировании печатных форм в среде «1С:Предприятие 8» разработчики часто сталкиваются с жесткими рамками стандартного функционала. Типичный пример такой задачи — необходимость убрать нижний или верхний колонтитул на самой последней странице отчета или договора (например, чтобы освободить место под подписи и печати сторон). Для освоения базовых принципов разработки подобных отчетов полезно изучить методику создания внешних печатных форм на основе типовых решений.

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

1. В чем сложность? Архитектурное ограничение платформы 1С

В платформе 1С объект ТабличныйДокумент имеет встроенные свойства для настройки колонтитулов (например, НижнийКолонтитул.Выводить или НижнийКолонтитул.НачальнаяСтраница). Однако у колонтитула нет свойства конечной страницы.

Платформа позволяет лишь задать страницу, с которой начнется вывод колонтитулов, но не позволяет штатно указать страницу, на которой этот вывод должен прекратиться. Именно из-за этого ограничения нам приходится прибегать к обходным путям разработки.

Решение А. Обходной маневр с «реверсивным» выводом страниц (без сложного кода)

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

Давайте разберем этот алгоритм по шагам:

  1. В коде печатной формы мы сначала формируем и выводим финальную (последнюю) страницу.
  2. После нее принудительно вставляем разделитель страниц с помощью метода ТабДок.ВывестиГоризонтальныйРазделительСтраниц().
  3. Следом за ней выводим все остальные (основные) страницы документа.
  4. В коде прописываем инструкцию выводить колонтитул только со второй страницы.

Посмотрим на пример реализации данного метода в коде:


// Создаем результирующий табличный документ
ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("МакетДоговора");

// 1. Сначала выводим финальную страницу (которая по логике должна быть последней)
ОбластьПодписи = Макет.ПолучитьОбласть("ПодписиСторон");
ОбластьПодписи.Параметры.Заполнить(ДанныеДляПечати);
ТабДок.Вывести(ОбластьПодписи);

// 2. Вставляем принудительный разделитель страниц
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();

// 3. Выводим основные (первые) страницы документа
ОбластьТекстДоговора = Макет.ПолучитьОбласть("ОсновнойТекст");
ОбластьТекстДоговора.Параметры.Заполнить(ДанныеДляПечати);
ТабДок.Вывести(ОбластьТекстДоговора);

// 4. Настраиваем колонтитул так, чтобы он не выводился на первой физической странице
ТабДок.НижнийКолонтитул.Выводить = Истина;
ТабДок.НижнийКолонтитул.НачальнаяСтраница = 2;
ТабДок.НижнийКолонтитул.ТекстВЦентре = "Страница [&НомерСтраницы] из [&СтраницВсего]";

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

Решение Б. Разделение на два табличных документа

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

Проанализируем этот подход подробнее:

  1. Мы формируем документ стандартным образом в один большой ТабличныйДокумент.
  2. С помощью метода КоличествоСтраниц() мы узнаем общий объем получившегося файла.
  3. Если документ занимает более одной страницы, мы программно переносим области последней страницы в отдельный (второй) объект ТабличныйДокумент.
  4. Для первого документа мы оставляем колонтитулы включенными, а для второго — отключаем их свойством НижнийКолонтитул.Выводить = Ложь.
  5. Оба документа отправляются на печать один за другим.

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

Решение В. Полноценная реализация собственных колонтитулов через ПроверитьВывод()

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

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

Рассмотрим по шагам рабочий алгоритм реализации этого метода:

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

Давайте посмотрим на практический пример кода, реализующий эту логику:


// Создаем результирующий документ и получаем области макета
ТабДок = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("НашМакет");

ОбластьСтрока = Макет.ПолучитьОбласть("СтрокаДанных");
ОбластьКолонтитул = Макет.ПолучитьОбласть("РучнойКолонтитул");

// Массив областей для выполнения проверки
МассивДляПроверки = Новый Массив;

// Предположим, у нас есть массив или таблица значений "ВыборкаСтрок"
КоличествоСтрок = ВыборкаСтрок.Количество();

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

Критически важный нюанс: влияние параметров на ПроверитьВывод()

Обратите внимание на важнейшее правило разработки в 1С: заполнение параметров области макета (через свойство Параметры.Заполнить() или прямым присвоением) должно происходить строго до вызова метода ПроверитьВывод().

Если ваша область содержит параметры, у которых включено свойство «Размещать: Переносить» (многострочный текст), то пустая область макета и область, заполненная длинным текстом, будут иметь совершенно разную высоту в пикселях. Проверка незаполненной области вернет результат Истина (все помещается), но после заполнения реальными данными высота строки увеличится, что приведет к сдвигу макета, некорректному разрыву страниц и "наползанию" текста на границы листа.

Особенности настройки встроенных колонтитулов и экспорт документа

Если вы все же решили использовать стандартные колонтитулы 1С, помните о правиле их инициализации: настройки встроенных колонтитулов (такие как Выводить, ТекстВЦентре и т. д.) необходимо применять после того, как в ТабличныйДокумент выведена хотя бы одна область, либо после полного формирования документа. В противном случае настройки могут сброситься до значений по умолчанию, заданных в самом макете.

Также учитывайте формат финального использования документа пользователями:

← На главную