При формировании печатных форм и отчетов в 1С разработчики часто сталкиваются с задачей вывода связанных данных типа «один ко многим». Типичный пример — список профессий (должностей), каждой из которых соответствует несколько позиций спецодежды или средств индивидуальной защиты (СИЗ). В результирующем документе требуется отобразить название профессии один раз, а справа от нее вывести перечень СИЗ, либо вертикально объединить повторяющиеся ячейки с названием должности.
Попытка решить эту задачу с помощью стандартной комбинации методов Вывести() и Присоединить() часто приводит к неожиданному поведению: строки детальных записей начинают сдвигаться вправо в виде лесенки, а не располагаются ровным списком. Выясним причину этой ошибки и подробно разберем правильные способы компоновки таких макетов.
Проанализируем механику работы методов табличного документа, чтобы понять источник проблемы:
Вывести() всегда смещает указатель вывода строго вниз. Он создает в табличном документе новую строку (или группу строк) на всю ширину под ранее выведенными областями.Присоединить() берет область и пристыковывает ее справа от последней сформированной секции, ориентируясь на верхнюю границу выведенной строки.Если мы попытаемся вывести ячейку с должностью методом Вывести(), а затем в цикле присоединять к ней несколько строк с номенклатурой методом Присоединить(), платформа не будет смещать каждую следующую позицию вниз под предыдущую. Каждая новая присоединенная секция будет пристыковываться правее предыдущей. В результате мы получим не вертикальную колонку, а горизонтальный ряд уходящих вправо ячеек. Вывести данные «столбиком» справа от уже выведенной высокой ячейки через один только Присоединить() невозможно.
При оформлении табличных документов начинающие разработчики нередко путают эти два метода объекта ОбластьТабличногоДокумента:
ОтображатьГруппировки.Разберем классический подход: в процессе обхода строк мы выводим детальные записи построчно через Вывести(), фиксируем начальную и конечную координаты выведенного диапазона, а затем вызываем метод Объединить().
Для определения точных номеров строк воспользуемся свойством табличного документа ВысотаТаблицы. Это избавит нас от необходимости вручную рассчитывать номера строк на основе предварительной свертки или подсчета единиц в таблицах значений.
Посмотрим на пример реализации с предварительно сгруппированными данными в выборке запроса:
// Предположим, что выборка построена по группировке: Профессия -> СИЗ
ВыборкаПрофессии = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
ОбластьСтрока = Макет.ПолучитьОбласть("СтрокаТаблицы");
Пока ВыборкаПрофессии.Следующий() Цикл
// Фиксируем номер первой строки будущей группы
НомерПервойСтроки = ТабДок.ВысотаТаблицы + 1;
ВыборкаСИЗ = ВыборкаПрофессии.Выбрать();
Пока ВыборкаСИЗ.Следующий() Цикл
ОбластьСтрока.Параметры.Заполнить(ВыборкаСИЗ);
// Заполняем наименование профессии только для корректности данных
ОбластьСтрока.Параметры.НаименованиеПрофессии = ВыборкаПрофессии.НаименованиеПрофессии;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
// Фиксируем номер последней строки группы
НомерПоследнейСтроки = ТабДок.ВысотаТаблицы;
// Если в группе было выведено больше одной строки, объединяем диапазон ячеек
Если НомерПоследнейСтроки > НомерПервойСтроки Тогда
// Параметры метода Область(R1, C1, R2, C2): левый верхний и правый нижний углы
// Например, наименование профессии находится в колонке 2
ОбластьДляОбъединения = ТабДок.Область(НомерПервойСтроки, 2, НомерПоследнейСтроки, 2);
ОбластьДляОбъединения.Объединить();
КонецЕсли;
КонецЦикла;
Обратите внимание: метод ТабДок.Область(R1, C1, R2, C2) принимает номера строк и колонок в числовом формате (начиная с 1). В качестве первой колонки указывается номер столбца, в котором находится должность, а последней строкой выступает ТабДок.ВысотаТаблицы.
Несмотря на популярность метода Объединить(), у физического слияния ячеек есть существенные недостатки: при экспорте отчета в формат Excel объединенные ячейки ломают автофильтр, сортировку и выделение колонок. Кроме того, при печати многостраничного документа объединенная по вертикали ячейка может некорректно разорваться между листами.
Рассмотрим альтернативное решение — псевдообъединение. В макете создаются две области строк:
СтрокаШапкаГруппы — выводит наименование профессии, у ячейки отключена нижняя граница.СтрокаПродолжение — колонка профессии остается пустой, у ячейки отключены верхняя и нижняя границы.Разберем программную реализацию такого вывода при обходе обычной отсортированной таблицы значений:
ОбластьШапка = Макет.ПолучитьОбласть("СтрокаШапкаГруппы");
ОбластьПродолжение = Макет.ПолучитьОбласть("СтрокаПродолжение");
ТекПрофессия = Неопределено;
Для Каждого СтрДанных Из ТаблицаСИЗ Цикл
Если ТекПрофессия <> СтрДанных.НаименованиеПрофессии Тогда
// Началась новая профессия: выводим строку с заполненным наименованием
ТекПрофессия = СтрДанных.НаименованиеПрофессии;
ОбластьШапка.Параметры.Заполнить(СтрДанных);
ТабДок.Вывести(ОбластьШапка);
Иначе
// Продолжение текущей профессии: выводим строку без названия профессии
ОбластьПродолжение.Параметры.Заполнить(СтрДанных);
ТабДок.Вывести(ОбластьПродолжение);
КонецЕсли;
КонецЦикла;
При таком подходе визуально ячейки выглядят как одна общая область за счет отсутствия горизонтальных разделителей. При этом в документе сохраняется корректная табличная сетка, полностью готовая для выгрузки в Excel и работы с фильтрами.
Если группа строк с одной профессией содержит десятки позиций, существует риск, что объединенная секция окажется разорванной при выводе на печать. Чтобы табличный документ переносил группу целиком на новую страницу при нехватке места, перед выводом рекомендуется проверять вместимость методом ПроверитьВывод():
// Формируем массив областей всей группы перед их отправкой в документ
МассивОбластейГруппы = Новый Массив;
// Заполняем массив выводимыми строками...
Если Не ТабДок.ПроверитьВывод(МассивОбластейГруппы) Тогда
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
Для Каждого Обл Из МассивОбластейГруппы Цикл
ТабДок.Вывести(Обл);
КонецЦикла;
Если макет строится с нуля, наиболее надежным решением является отказ от ручной отрисовки макета в пользу СКД. В настройках структуры компоновки достаточно настроить группировку по полю НаименованиеПрофессии, а внутрь нее поместить детальные записи по номенклатуре СИЗ. Платформа 1С автоматически сформирует иерархический табличный документ, корректно расставит заголовки и выведет данные без необходимости писать сложный код позиционирования ячеек.