Почему двоится вывод данных в печатную форму (макет) в 1С и как это исправить?

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

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

Анализ проблемы: как возникает ошибка

Для начала посмотрим на пример кода, который приводит к подобной ошибке. Часто разработчики пытаются использовать сам объект макета для вывода в него же заполненных данных. Код может выглядеть примерно так:


Процедура ОсновныеДействияФормыПереместитьВПечать(Кнопка)
    // Получаем макет
    Макет = ПолучитьМакет("Макет");
    
    // Получаем область заголовка из макета
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьЗаголовок.Параметры.Склад = Склад.Магазин.Наименование;
    
    // ОШИБКА: Выводим область обратно в сам макет
    Макет.Вывести(ОбластьЗаголовок);
    
    // ... получение и вывод других областей ...
    
    // Показываем макет пользователю
    Макет.Показать();
КонецПроцедуры

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

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

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

Правильное решение: использование чистого табличного документа

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

Рассмотрим подробнее правильный алгоритм формирования:

  1. Получить макет-шаблон из метаданных конфигурации.
  2. Создать новый пустой табличный документ, который будет служить холстом для нашего отчета.
  3. Получить нужную область из макета-шаблона.
  4. Заполнить параметры в полученной области.
  5. Вывести заполненную область в наш новый табличный документ.
  6. Показать итоговый документ пользователю.

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


Процедура ОсновныеДействияФормыПереместитьВПечать(Кнопка)
    // 1. Получаем макет-шаблон
    Макет = ПолучитьМакет("Макет");
    
    // 2. Создаем новый чистый табличный документ для вывода результата
    ТабДок = Новый ТабличныйДокумент;
    
    // 3. Получаем область из макета
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    
    // 4. Заполняем параметры
    ОбластьЗаголовок.Параметры.Склад = Склад.Магазин.Наименование;
    ОбластьЗаголовок.Параметры.НачПериода = Формат(НачПериода,"ДЛФ=DD");
    ОбластьЗаголовок.Параметры.КонПериода = Формат(КонПериода,"ДЛФ=DD");
    
    // 5. Выводим заполненную область в НОВЫЙ табличный документ
    ТабДок.Вывести(ОбластьЗаголовок);
    
    // Пример вывода строк в цикле
    ОбластьТовар = Макет.ПолучитьОбласть("Товар");
    Для Каждого ТекСтрока Из Таб Цикл 
        ОбластьТовар.Параметры.Заполнить(ТекСтрока);
        ТабДок.Вывести(ОбластьТовар); // Выводим в ТабДок!
    КонецЦикла;
    
    // Вывод подвала
    ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
    ОбластьПодвал.Параметры.КонПериода = Формат(КонПериода+60*60*24,"ДЛФ=DD");
    ТабДок.Вывести(ОбластьПодвал);
    
    // 6. Показываем сформированный документ пользователю
    ТабДок.Показать("Печатная форма перемещения");
КонецПроцедуры

Дополнительные нюансы оформления табличных документов

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

Рассмотрим полезные свойства объекта ТабличныйДокумент:

Пример применения настроек:


// Перед вызовом ТабДок.Показать()
ТабДок.ТолькоПросмотр = Истина;
ТабДок.ОтображатьСетку = Ложь;
ТабДок.ОтображатьЗаголовки = Ложь;
ТабДок.АвтоМасштаб = Истина;
ТабДок.Показать("Итоговый отчет");

Горизонтальный вывод данных

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

Особенности работы в Управляемых формах (УФ)

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

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


&НаСервере
Процедура СформироватьНаСервере()
    // Очищаем реквизит формы от предыдущих данных
    ТабличныйДокументНаФорме.Очистить();
    
    // Получаем макет (для УФ это часто делается через объект или обработку)
    ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
    Макет = ОбработкаОбъект.ПолучитьМакет("Макет");
    
    Область = Макет.ПолучитьОбласть("Строка");
    // ... заполнение ...
    
    // Выводим данные в реквизит формы
    ТабличныйДокументНаФорме.Вывести(Область);
КонецПроцедуры

Подводя итог, запомним главное правило: никогда не используйте метод вывода данных, применяя его к самому макету. Макет — это только источник областей и форматирования. Данные всегда выводятся в отдельный объект табличного документа или соответствующий реквизит формы.

← На главную