Вывод подписи в макете на каждой странице: исправляем работу ПроверитьВывод в 1С

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

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

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

Выясняем причину: почему подпись «убегает» на новую страницу?

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

В чем кроется логическая ошибка? Мы проверяем на заполняемость страницы только строку таблицы. Но мы забываем, что сразу за этой строкой должен идти подвал (подпись). Если строка по высоте еле-еле умещается в самый низ страницы, метод ПроверитьВывод() для нее вернет значение Истина. Строка будет успешно напечатана. Но когда код дойдет до вывода области подписи, места на странице для нее уже не останется! Платформа будет вынуждена автоматически перенести подпись на следующую страницу. В итоге мы получаем пустой лист, на котором сиротливо располагается одна лишь подпись директора.

Базовое решение: проверка вывода массива областей

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

Разберем правильный алгоритм по шагам:

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

Давайте посмотрим на программную реализацию этого алгоритма:


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

Критически важный нюанс №1: Заполнение параметров ДО проверки вывода

Обратите внимание на последовательность действий в приведенном выше коде. Мы сначала заполняем параметры в объекте ОбластьМакетаСтрока (ФИО, суммы, номера) и только после этого добавляем область в массив и вызываем ПроверитьВывод().

Почему это критично? Если вызовем метод для пустой, незаполненной области, платформа рассчитает высоту строки на основе пустых ячеек. Если у реального сотрудника окажется слишком длинное имя или сложная должность, текст перенесется на вторую или третью строчку внутри ячейки, увеличив физическую высоту строки. Пустая строка проверку пройдет, но при реальном выводе заполненные данные «вытолкнут» подпись за пределы листа. Всегда заполняйте параметры перед проверкой!

Критически важный нюанс №2: Влияние свойства «Автомасштаб»

Очень частая и неочевидная ошибка разработчиков — включенное свойство Автомасштаб = Истина у проверяемого табличного документа.

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

Решение проблемы: на время расчета и вывода строк необходимо программно отключать автомасштаб, а в самом конце — включать его обратно. Рассмотрим пример реализации:


// Отключаем автомасштаб на время заполнения документа
ТабличныйДокумент.Автомасштаб = Ложь;
ТабличныйДокумент.МасштабПечати = 100; // Устанавливаем фиксированный масштаб для расчета

// [Здесь выполняется наш цикл вывода областей с проверкой ПроверитьВывод()]

// После завершения формирования документа возвращаем автомасштаб
ТабличныйДокумент.Автомасштаб = Истина;

Критически важный нюанс №3: Безопасный вызов (проблема отсутствия принтера)

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

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


Поместилось = Истина;
Попытка
    Поместилось = ТабличныйДокумент.ПроверитьВывод(МассивОбластей);
Исключение
    // В случае отсутствия принтера считаем, что все помещается,
    // чтобы не прерывать работу пользователя и дать ему сформировать документ
    Поместилось = Истина; 
КонецПопытки;

Если Не Поместилось Тогда
    // Действия по переносу на новую страницу...
КонецЕсли;

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

ОбщегоНазначения.ПроверитьВыводТабличногоДокумента(ТабличныйДокумент, МассивОбластей)

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

Критически важный нюанс №4: Сохраненные настройки печати пользователя

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

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

Ограничения использования нижних колонтитулов

Иногда программисты предлагают альтернативный вариант — выводить подпись директора через нижний колонтитул табличного документа. Действительно, свойство НижнийКолонтитул.Выводить = Истина позволяет автоматически печатать заданный текст в самом низу каждого листа. Однако у этого способа есть критические ограничения:

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

Сложный сценарий: вывод промежуточного итога vs финального подвала

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

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


КоличествоСтрок = ТЗ.Количество();

Для Индекс = 0 По КоличествоСтрок - 1 Цикл
    
    ДанныеСтроки = ТЗ[Индекс];
    
    // Заполняем параметры строки...
    ОбластьМакетаСтрока.Параметры.НомерСтроки = Индекс + 1;
    // ... заполнение остальных параметров ...

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

// В самом конце, после завершения цикла, выводим финальный подвал
ТабличныйДокумент.Вывести(ОбластьМакетаПодвалФинал);

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

← На главную