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

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

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

Однако здесь возникает классическая техническая дилемма: как вывести в такой подвал информацию вида «Страница X из Y»? На момент вывода первой страницы платформа еще не знает, сколько всего страниц получится в итоге. Общее число страниц становится известным только после того, как весь табличный документ полностью сформирован в памяти. В этой статье мы подробно разберем несколько способов решения этой задачи, оценим их производительность и выберем наиболее оптимальный вариант для боевых условий.

Способ 1. Поиск и автозамена текстовых меток (Решение из темы форума)

Данный подход заключается в том, что в макете подвала в ячейку вписывается текстовый маркер (например, $ВсегоСтраниц$ или $КоличествоСтраниц$). Документ выводится стандартным образом. После завершения вывода мы получаем общее количество страниц, обходим весь готовый табличный документ с помощью встроенного поиска 1С и заменяем наш маркер на реальное число.

Рассмотрим пример реализации этого алгоритма в виде универсальной процедуры:


Процедура ТабличныйДокумент_ПроставитьГлобальнуюПеременную(ТабДок, ИмяПерем, ЗнчПерем)
    ОблНачало = Неопределено;
    Найдено = Истина;
    ОблНайдено = Неопределено;
    
    Пока Найдено Цикл 
        // Ищем ячейку, содержащую наш маркер, ограниченный символами "$"
        ОблНайдено = ТабДок.НайтиТекст("$" + ИмяПерем + "$", ОблНачало, , , , , Истина);
        Найдено = НЕ (ОблНайдено = Неопределено);
        
        Если Найдено Тогда 
            ОблНачало = ОблНайдено;
            // Производим замену маркера на фактическое значение
            ОблНайдено.Текст = СтрЗаменить(ОблНайдено.Текст, "$" + ИмяПерем + "$", Строка(ЗнчПерем));
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Преимущества метода:

Недостатки метода:


Способ 2. Запоминание выведенных областей в массив (Наиболее оптимальный)

Вместо того чтобы заставлять платформу искать текст по всему документу, мы можем точечно запоминать области подвалов прямо в процессе их вывода. Метод табличного документа Вывести() не просто копирует строки из макета, он возвращает объект типа ТабличныйДокументОбласть, которая указывает на конкретные координаты в результирующем документе. Мы можем сохранить эти области в массив и заполнить параметры позже.

Проанализируем по шагам, как это реализовать на практике:


// Создаем массив для хранения ссылок на области подвалов страниц
МассивОбластейПодвала = Новый Массив;
НомерСтраницы = 1;

// Цикл обхода данных и формирования документа
Пока ВыборкаДанных.Следующий() Цикл
    
    // ... Здесь выводим шапку и строки данных ...
    
    // Когда пришло время выводить подвал страницы (например, по условию перехода на новый лист)
    ОбластьПодвала = Макет.ПолучитьОбласть("Подвал");
    
    // Заполняем локальные параметры, которые известны прямо сейчас
    ОбластьПодвала.Параметры.НомерСтраницы = НомерСтраницы;
    
    // Выводим область и СОХРАНЯЕМ ссылку на нее в массив
    ВыведенныйПодвал = ТабДок.Вывести(ОбластьПодвала);
    МассивОбластейПодвала.Добавить(ВыведенныйПодвал);
    
    НомерСтраницы = НомерСтраницы + 1;
КонецЦикла;

// Документ полностью сформирован, теперь мы можем получить точное число страниц
Попытка
    ВсегоСтраниц = ТабДок.КоличествоСтраниц();
Исключение
    ВсегоСтраниц = НомерСтраницы - 1; // Резервный вариант на случай проблем с принтером
КонецПопытки;

// Обходим сохраненные области и напрямую заполняем оставшиеся параметры
Для Каждого ОбластьПодвала Из МассивОбластейПодвала Цикл
    // Вариант А: Если в макете был объявлен параметр "ВсегоСтраниц"
    // (Этот вариант сработает, если область не была принудительно очищена)
    Попытка
        ОбластьПодвала.Параметры.ВсегоСтраниц = ВсегоСтраниц;
    Исключение
        // Вариант Б: Запись напрямую в текст конкретной ячейки внутри области
        // Например, если ячейка с общим числом страниц — это первая строка и третья колонка области
        ОбластьПодвала.Область(1, 3).Текст = Строка(ВсегоСтраниц);
    КонецПопытки;
КонецЦикла;

Преимущества метода:


Способ 3. Двухпроходный вывод

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

Рассмотрим схему реализации:


// Шаг 1: Первый (черновой) проход формирования
ЧерновойТабДок = Новый ТабличныйДокумент;
СформироватьПечатнуюФорму(ЧерновойТабДок, Неопределено); // Передаем Неопределено вместо общего числа страниц

// Шаг 2: Вычисление общего количества страниц из чернового документа
ВсегоСтраниц = ЧерновойТабДок.КоличествоСтраниц();

// Шаг 3: Второй (чистовой) проход формирования
ТабДок.Очистить();
СформироватьПечатнуюФорму(ТабДок, ВсегоСтраниц); // Теперь передаем реальное число страниц во все параметры макета

Для оптимизации этого метода важно не выполнять тяжелые запросы к базе данных дважды. Все данные для печати необходимо предварительно выгрузить в ТаблицаЗначений или массив структур на первом шаге и использовать эту готовую коллекцию на втором шаге.


Способ 4. Контроль разбиения страниц с помощью ПроверитьВывод()

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


ТабДок.КлючПараметровПечати = "ПараметрыПечати_УниверсальныйДокумент";
МассивОбластейДляЗаполнения = Новый Массив;
НомерСтраницы = 1;

ОбластьШапки = Макет.ПолучитьОбласть("Шапка");
ОбластьСтроки = Макет.ПолучитьОбласть("Строка");
ОбластьПодвала = Макет.ПолучитьОбласть("Подвал");

// Выводим шапку первой страницы
ТабДок.Вывести(ОбластьШапки);

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

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

// Рассчитываем итоговые данные
ВсегоСтраниц = ТабДок.КоличествоСтраниц();

// Заполняем сквозной параметр во всех листах
Для Каждого ПодвалИзМассива Из МассивОбластейДляЗаполнения Цикл
    ПодвалИзМассива.Параметры.ВсегоСтраниц = ВсегоСтраниц;
КонецЦикла;

Важные технические нюансы работы с КоличествоСтраниц()

При использовании методов расчета страниц платформы 1С крайне важно учитывать системные особенности работы платформы, чтобы избежать ошибок в рабочей базе:

  1. Зависимость от принтера: Методы КоличествоСтраниц() и ПроверитьВывод() обращаются к драйверу принтера, установленному по умолчанию в операционной системе. Если код выполняется на сервере 1С под управлением Linux, где не настроен ни один принтер, или служба печати Windows зависла, вызов методов вернет ошибку (вызовет исключение). Всегда оборачивайте эти вызовы в конструкцию Попытка...Исключение со страховочным сценарием расчета.
  2. Ключ параметров печати: Обязательно задавайте свойство ТабДок.КлючПараметровПечати. Без него платформа применит стандартные настройки по умолчанию, в то время как пользователь мог изменить поля, ориентацию (ландшафт вместо портрета) или масштаб печати. Если настройки будут отличаться, метод выдаст неверное количество страниц.
  3. Автомасштаб: Если для табличного документа включено свойство Автомасштаб = Истина, платформа попытается уместить документ по ширине страницы, что может кардинально изменить общее количество листов. Учитывайте это при проектировании дизайна макета.
← На главную