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

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Выясняем причину: почему ломается таблица при обычном выводе

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


// ОШИБОЧНЫЙ ПОДХОД
Для каждого СтрокаТовара Из Товары Цикл
    ТабДокумент.Вывести(ОбластьСтрокиЛево); // Выводим начало строки (Товар)
    
    Для каждого СтрокаПоставщика Из СтрокаТовара.Поставщики Цикл
        ОбластьАртикула.Параметры.Артикул = СтрокаПоставщика.Артикул;
        ТабДокумент.Присоединить(ОбластьАртикула); // Присоединяем артикулы по очереди
    КонецЦикла;
    
    ТабДокумент.Присоединить(ОбластьСтрокиПраво); // Присоединяем Количесто, Цену, Сумму
КонецЦикла;

Почему этот код ломает таблицу? Метод Присоединить добавляет ячейки в ту же самую строку табличного документа справа от уже выведенных. Если у первого товара 3 поставщика, метод Присоединить(ОбластьАртикула) выполнится 3 раза, а затем прикрепится правая часть. Строка расширится вправо на 3 ячейки. Если у второго товара всего 1 поставщик, цикл выполнится 1 раз, и правая часть (Количество, Цена) прикрепится гораздо левее. В итоге колонки «Количество» первой и второй строки окажутся в совершенно разных столбцах печатной формы. Таблица «съедет».

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

---

Шаг 1. Разметка макета (Использование именованных вертикальных областей)

Чтобы управлять горизонтальным выводом ячеек, нам необходимо правильно спроектировать макет (ускоряет задачу конструктор произвольных документов и печатных форм 1С) в конфигураторе. Простого деления на горизонтальные строки (секции) здесь недостаточно. Мы должны разделить макет по вертикали.

Создадим три вертикальные именованные области, выделив соответствующие колонки в макете:

  1. ЛеваяЧасть — включает статические колонки начала таблицы: «№», «Код», «Товар».
  2. Центр (или ДинамическаяКолонка) — состоит ровно из одной колонки. В этой колонке мы размещаем параметр (например, Артикул) и настраиваем границы ячейки со всех сторон.
  3. ПраваяЧасть — включает статические колонки конца таблицы: «Ед. изм.», «Количество», «Цена», «Сумма».

После такой разметки мы сможем обращаться к пересечениям строк и колонок. Например, выражение Макет.ПолучитьОбласть("Строка|ЛеваяЧасть") вернет нам только левую часть строки с информацией о товаре.

---

Шаг 2. Расчет максимального количества динамических колонок

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

Проанализируем пример кода для расчета лимита колонок:


МаксПоставщиков = 0;

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

// На случай, если у товаров вообще нет поставщиков, выведем хотя бы одну пустую колонку
Если МаксПоставщиков = 0 Тогда
    МаксПоставщиков = 1;
КонецЕсли;

Теперь переменная МаксПоставщиков содержит точное число динамических колонок, которые гарантированно вместят все данные без урезания.

---

Шаг 3. Алгоритм вывода шапки документа

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

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


// 1. Создаем и выводим левую статическую часть шапки
ОбластьШапкаЛево = Макет.ПолучитьОбласть("Шапка|ЛеваяЧасть");
ТабДокумент.Вывести(ОбластьШапкаЛево);

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

// 3. Присоединяем правую статическую часть шапки
ОбластьШапкаПраво = Макет.ПолучитьОбласть("Шапка|ПраваяЧасть");
ТабДокумент.Присоединить(ОбластьШапкаПраво);

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

---

Шаг 4. Вывод строк данных с заполнением пустых областей

Переходим к выводу строк. Основной секрет здесь в том, что цикл вывода динамических колонок внутри строки товара должен выполняться ровно МаксПоставщиков раз, независимо от того, сколько реальных поставщиков привязано к текущему товару.

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

Реализуем этот алгоритм в коде:


НомерСтроки = 0;

Для каждого ВыборкаСтрокТовары Из ЗапросТовары Цикл
    НомерСтроки = НомерСтроки + 1;
    
    // 1. Выводим левую часть строки с основными реквизитами товара
    ОбластьСтрокиЛево = ...; // Получаем область "Строка|ЛеваяЧасть" из макета
    ОбластьСтрокиЛево.Параметры.НомерСтроки = НомерСтроки;
    ОбластьСтрокиЛево.Параметры.Товар = ВыборкаСтрокТовары.Товар;
    // (Заполняем другие параметры левой части)
    ТабДокумент.Вывести(ОбластьСтрокиЛево); // Создаем новую строку в табличном документе
    
    // 2. Выводим строго фиксированное количество динамических колонок
    ОбластьСтрокиЦентр = Макет.ПолучитьОбласть("Строка|Центр");
    ТаблицаПоставщиков = ВыборкаСтрокТовары.Номенклатура.МТД_Поставщики;
    
    Для К = 1 По МаксПоставщиков Цикл
        // Проверяем, есть ли данные для текущего индекса колонки
        Если К <= ТаблицаПоставщиков.Количество() Тогда
            ТекущаяСтрокаПоставщика = ТаблицаПоставщиков[К - 1];
            ОбластьСтрокиЦентр.Параметры.Артикул = ТекущаяСтрокаПоставщика.Артикул;
        Иначе
            // Обязательно очищаем параметр для пустых ячеек во избежание "мусора"
            ОбластьСтрокиЦентр.Параметры.Артикул = "";
        КонецЕсли;
        
        // Присоединяем ячейку к текущей строке табличного документа
        ТабДокумент.Присоединить(ОбластьСтрокиЦентр);
    КонецЦикла;
    
    // 3. Присоединяем правую часть строки (Количество, Цена, Сумма)
    ОбластьСтрокиПраво = Макет.ПолучитьОбласть("Строка|ПраваяЧасть");
    ОбластьСтрокиПраво.Параметры.Заполнить(ВыборкаСтрокТовары);
    ТабДокумент.Присоединить(ОбластьСтрокиПраво);
    
КонецЦикла;

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

---

Альтернативное решение: вывод через Систему компоновки данных (СКД)

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

Выясним, как настроить такую структуру в СКД:

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

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

---

Важные мелочи при программном выводе таблиц

Чтобы печатная форма выглядела эстетично, обратите внимание на следующие нюансы:

← На главную