При разработке печатных форм в среде «1С:Предприятие 8» программисты часто сталкиваются с задачей вывода динамического количества колонок — есть визуальный редактор печатных форм 1С без программирования. Яркий пример — печать документов, где для каждой номенклатурной позиции необходимо вывести список её поставщиков с их уникальными артикулами. У одного товара может быть один поставщик, у другого — три, а у третьего их нет вовсе.
Попытка выводить колонки «на лету» в цикле по фактическому количеству данных для каждой строки неизбежно приводит к тому, что правая часть таблицы (колонки с количеством, ценой и суммой) смещается. В результате структура документа полностью ломается. Разберем по шагам, почему возникает эта ошибка и как реализовать правильный, надежный алгоритм вывода динамических колонок с использованием методов Вывести и Присоединить — это также решается через печать документов по шаблонам Word из 1С.
Рассмотрим стандартный, но ошибочный подход, который часто пытаются использовать начинающие разработчики. Код обходит строки документа, а внутри каждой строки запускается цикл по подчиненным данным (например, по артикулам поставщиков):
// ОШИБОЧНЫЙ ПОДХОД
Для каждого СтрокаТовара Из Товары Цикл
ТабДокумент.Вывести(ОбластьСтрокиЛево); // Выводим начало строки (Товар)
Для каждого СтрокаПоставщика Из СтрокаТовара.Поставщики Цикл
ОбластьАртикула.Параметры.Артикул = СтрокаПоставщика.Артикул;
ТабДокумент.Присоединить(ОбластьАртикула); // Присоединяем артикулы по очереди
КонецЦикла;
ТабДокумент.Присоединить(ОбластьСтрокиПраво); // Присоединяем Количесто, Цену, Сумму
КонецЦикла;
Почему этот код ломает таблицу? Метод Присоединить добавляет ячейки в ту же самую строку табличного документа справа от уже выведенных. Если у первого товара 3 поставщика, метод Присоединить(ОбластьАртикула) выполнится 3 раза, а затем прикрепится правая часть. Строка расширится вправо на 3 ячейки. Если у второго товара всего 1 поставщик, цикл выполнится 1 раз, и правая часть (Количество, Цена) прикрепится гораздо левее. В итоге колонки «Количество» первой и второй строки окажутся в совершенно разных столбцах печатной формы. Таблица «съедет».
Для создания ровной и профессиональной таблицы необходимо использовать золотое правило динамической верстки в 1С: количество присоединенных колонок в каждой строке печатной формы должно быть строго одинаковым и равняться максимальному числу колонок в документе. Если для конкретной номенклатуры данных меньше, мы обязаны вывести пустые ячейки-заглушки — для этих целей есть обработка добавления колонок в печатные формы 1С.
---
Чтобы управлять горизонтальным выводом ячеек, нам необходимо правильно спроектировать макет (ускоряет задачу конструктор произвольных документов и печатных форм 1С) в конфигураторе. Простого деления на горизонтальные строки (секции) здесь недостаточно. Мы должны разделить макет по вертикали.
Создадим три вертикальные именованные области, выделив соответствующие колонки в макете:
Артикул) и настраиваем границы ячейки со всех сторон.После такой разметки мы сможем обращаться к пересечениям строк и колонок. Например, выражение Макет.ПолучитьОбласть("Строка|ЛеваяЧасть") вернет нам только левую часть строки с информацией о товаре.
---
Прежде чем выводить шапку таблицы, мы должны точно знать, сколько динамических колонок нам понадобится. Для этого необходимо проанализировать массив данных, подготовленный для вывода (например, результат запроса), и найти строку с максимальным количеством связанных записей.
Проанализируем пример кода для расчета лимита колонок:
МаксПоставщиков = 0;
// Обходим выборку или таблицу значений перед выводом на печать
Для каждого СтрокаДанных Из ЗапросТовары Цикл
// Предположим, что поставщики хранятся в табличной части номенклатуры или получены вложенным запросом
КоличествоПоставщиков = СтрокаДанных.Номенклатура.МТД_Поставщики.Количество();
Если КоличествоПоставщиков > МаксПоставщиков Тогда
МаксПоставщиков = КоличествоПоставщиков;
КонецЕсли;
КонецЦикла;
// На случай, если у товаров вообще нет поставщиков, выведем хотя бы одну пустую колонку
Если МаксПоставщиков = 0 Тогда
МаксПоставщиков = 1;
КонецЕсли;
Теперь переменная МаксПоставщиков содержит точное число динамических колонок, которые гарантированно вместят все данные без урезания.
---
Теперь, зная значение МаксПоставщиков, мы можем построить шапку таблицы. Сначала мы выводим левую часть шапки с помощью метода Вывести (это инициализирует создание новой строки в документе), затем в цикле присоединяем динамические колонки методом Присоединить, а в конце — правую часть.
Рассмотрим подробнее программный код заполнения заголовка таблицы:
// 1. Создаем и выводим левую статическую часть шапки
ОбластьШапкаЛево = Макет.ПолучитьОбласть("Шапка|ЛеваяЧасть");
ТабДокумент.Вывести(ОбластьШапкаЛево);
// 2. В цикле присоединяем нужное количество динамических заголовков
ОбластьШапкаЦентр = Макет.ПолучитьОбласть("Шапка|Центр");
Для К = 1 По МаксПоставщиков Цикл
// Задаем уникальный текст заголовка для каждой колонки
ОбластьШапкаЦентр.Параметры.ИмяКолонки = "Артикул поставщика " + К;
ТабДокумент.Присоединить(ОбластьШапкаЦентр);
КонецЦикла;
// 3. Присоединяем правую статическую часть шапки
ОбластьШапкаПраво = Макет.ПолучитьОбласть("Шапка|ПраваяЧасть");
ТабДокумент.Присоединить(ОбластьШапкаПраво);
Этот подход гарантирует, что шапка всегда будет соответствовать по ширине строкам с данными, сколько бы колонок мы ни вывели.
---
Переходим к выводу строк. Основной секрет здесь в том, что цикл вывода динамических колонок внутри строки товара должен выполняться ровно МаксПоставщиков раз, независимо от того, сколько реальных поставщиков привязано к текущему товару.
Если индекс шага цикла превышает количество реальных данных, мы программно очищаем параметр ячейки. Это критически важно, так как область макета используется многократно, и если не очистить параметр явно, в ячейке отобразится значение из предыдущей строки.
Реализуем этот алгоритм в коде:
НомерСтроки = 0;
Для каждого ВыборкаСтрокТовары Из ЗапросТовары Цикл
НомерСтроки = НомерСтроки + 1;
// 1. Выводим левую часть строки с основными реквизитами товара
ОбластьСтрокиЛево = ...; // Получаем область "Строка|ЛеваяЧасть" из макета
ОбластьСтрокиЛево.Параметры.НомерСтроки = НомерСтроки;
ОбластьСтрокиЛево.Параметры.Товар = ВыборкаСтрокТовары.Товар;
// (Заполняем другие параметры левой части)
ТабДокумент.Вывести(ОбластьСтрокиЛево); // Создаем новую строку в табличном документе
// 2. Выводим строго фиксированное количество динамических колонок
ОбластьСтрокиЦентр = Макет.ПолучитьОбласть("Строка|Центр");
ТаблицаПоставщиков = ВыборкаСтрокТовары.Номенклатура.МТД_Поставщики;
Для К = 1 По МаксПоставщиков Цикл
// Проверяем, есть ли данные для текущего индекса колонки
Если К <= ТаблицаПоставщиков.Количество() Тогда
ТекущаяСтрокаПоставщика = ТаблицаПоставщиков[К - 1];
ОбластьСтрокиЦентр.Параметры.Артикул = ТекущаяСтрокаПоставщика.Артикул;
Иначе
// Обязательно очищаем параметр для пустых ячеек во избежание "мусора"
ОбластьСтрокиЦентр.Параметры.Артикул = "";
КонецЕсли;
// Присоединяем ячейку к текущей строке табличного документа
ТабДокумент.Присоединить(ОбластьСтрокиЦентр);
КонецЦикла;
// 3. Присоединяем правую часть строки (Количество, Цена, Сумма)
ОбластьСтрокиПраво = Макет.ПолучитьОбласть("Строка|ПраваяЧасть");
ОбластьСтрокиПраво.Параметры.Заполнить(ВыборкаСтрокТовары);
ТабДокумент.Присоединить(ОбластьСтрокиПраво);
КонецЦикла;
Применив данную логику, мы получим идеально ровную таблицу. У товаров с одним поставщиком заполнится только первая колонка артикула, а остальные останутся пустыми, сохранив при этом правильное положение правой части таблицы.
---
Если печатная форма разрабатывается с нуля или допускает вывод в виде отчета, ручного написания сложного кода с макетами можно полностью избежать. Для задач с динамическими колонками идеально подходит Система компоновки данных (СКД) с типом структуры Таблица — поможет комплект инструментов разработчика 1С для отладки СКД.
Выясним, как настроить такую структуру в СКД:
Товар.Поставщик.Артикул (для него нужно настроить функцию, например, Максимум(Артикул)), а также ваши ресурсы Количество и Сумма.Преимущества использования СКД в данном случае: Платформа 1С самостоятельно проанализирует набор данных, автоматически определит максимальное количество колонок для поставщиков, построит шапку, отформатирует пустые ячейки и подведет общие итоги. Это исключает любые ошибки ручного позиционирования областей в коде.
---
Чтобы печатная форма выглядела эстетично, обратите внимание на следующие нюансы:
Присоединить() может некорректно состыковывать правые и левые рамки ячеек, если они настроены неодинаково. Убедитесь, что в макете у ячеек динамической области (Центр) явно включена сплошная тонкая рамка со всех четырех сторон.ТабДокумент.АвтоМасштаб = Истина;
"" или числу 0) в неиспользуемых динамических областях макета, чтобы избежать дублирования информации из предыдущих строк отчета.