При разработке сложных отчетов или печатных форм, особенно тех, которые имитируют иерархические структуры (организационные диаграммы, деревья подчиненности), программисты 1С часто сталкиваются с загадочным поведением метода Присоединить. Данные либо "улетают" в сторону, либо накладываются друг на друга, либо вовсе не отображаются в нужной позиции, хотя отладчик показывает, что код выполняется без ошибок. Проанализируем эту ситуацию на примере реального кейса и разберем, как построить корректный алгоритм вывода.
Рассмотрим ситуацию: разработчик пытается программно сформировать структуру подчиненности сотрудников. Для каждой "ветки" рабочих создается отдельный временный ТабличныйДокумент, в который выводятся карточки сотрудников, после чего этот временный документ должен "присоединиться" справа к основному итоговому документу. Посмотрим на фрагмент кода, который вызывает проблему:
// Фрагмент проблемного кода
Для каждого нСтр из ПодчиненныеНачальникаПодразделения цикл
ТабДокОднаВеткаРабочих = Новый ТабличныйДокумент; // Создание нового объекта в цикле
// ... заполнение ТабДокОднаВеткаРабочих данными ...
// Попытка присоединить целый документ к другому документу
ТабДокРабочие.Присоединить(ТабДокОднаВеткаРабочих);
КонецЦикла;
На первый взгляд логика кажется верной, однако именно здесь кроется системная ошибка. Выясним причину, по которой 1С "проскакивает" вывод или делает смещение. Основная проблема заключается в том, что ТабДокОднаВеткаРабочих — это полноценный, независимый объект ТабличныйДокумент. У него есть своя собственная сетка колонок, свои настройки ширины и высоты ячеек, которые могут не совпадать с итоговым документом ТабДокРабочие.
Разберем по шагам, что происходит "под капотом" платформы 1С при выполнении такого кода:
Новый ТабличныйДокумент, он имеет стандартную ширину колонок. Если в итоговом документе ширина колонок была изменена, то при выполнении Присоединить платформа пытается совместить две разные геометрии. Это неизбежно приводит к визуальным искажениям и "сдвигам".Присоединить ищет крайнюю правую заполненную ячейку в текущей строке вывода. Если вы передаете целый объект ТабличныйДокумент, система не всегда может корректно определить его границы, особенно если в нем есть объединенные ячейки.КарточкаСерединаВниз) содержат объединение ячеек по горизонтали или вертикали, то при попытке горизонтального присоединения 1С может "сломать" сетку, пытаясь втиснуть объединенную область в структуру колонок итогового документа. Это выглядит как "дырка" в отчете или смещение на одну колонку в сторону.ТабличныйДокумент остался пустым, выполнение Присоединить(ПустойДокумент) может сбить внутренний курсор вывода, из-за чего следующая итерация начнется не с той позиции.Для исправления ситуации необходимо отказаться от создания промежуточных объектов ТабличныйДокумент внутри цикла. Вместо этого следует использовать области макета (ТабличныйДокументОбласть). Этот метод считается "золотым стандартом" разработки в 1С, так как он гарантирует сохранение единой геометрии документа. Рассмотрим, как переписать код правильно.
Проанализируем шаги для реализации корректного вывода:
ПолучитьОбласть() для извлечения нужных фрагментов (карточек).Вывести() для начала новой строки и Присоединить() для добавления данных справа в ту же строку.Разберем пример правильного построения цикла:
// Инициализируем итоговый документ и макет
ТабДокИтог = Новый ТабличныйДокумент;
Макет = ПолучитьМакет("МакетКарточек");
// Основной цикл формирования структуры
Для каждого Стр Из ТЗ Цикл
// Сначала выводим заголовок строки или левую часть через Вывести()
ОбластьЗаголовок = Макет.ПолучитьОбласть("ЗаголовокВетки");
// ... заполнение параметров ...
ТабДокИтог.Вывести(ОбластьЗаголовок);
// Вложенный цикл для горизонтального вывода подчиненных
Для каждого нСтр Из Подчиненные Цикл
// Определяем, какую карточку выводить
ИмяОбласти = ?(ЭтоПоследний, "КарточкаКонецВниз", "КарточкаСерединаВниз");
ОбластьКарточка = Макет.ПолучитьОбласть(ИмяОбласти);
// Заполнение параметров области напрямую
ОбластьКарточка.Параметры.Сотрудник = нСтр.Сотрудник;
ОбластьКарточка.Параметры.Должность = нСтр.Должность;
// ВАЖНО: Присоединяем ОБЛАСТЬ, а не документ
ТабДокИтог.Присоединить(ОбластьКарточка);
КонецЦикла;
КонецЦикла;
Когда мы используем ОбластьКарточка = Макет.ПолучитьОбласть(...), объект ОбластьКарточка не является самостоятельным табличным документом в полном смысле слова. Он хранит в себе информацию о структуре ячеек макета-донора. При выполнении метода Присоединить(ОбластьКарточка) платформа 1С:
Вывести).Важный совет: Если вы строите сложную схему, где карточки должны выравниваться "в шахматном порядке" или иметь разную высоту, следите за тем, чтобы высота (количество строк) во всех присоединяемых областях была одинаковой. Если КарточкаСерединаВниз занимает 5 строк, а КарточкаКонецВниз — 4 строки, визуально нижняя граница "поплывет". В таких случаях рекомендуется добавлять пустые строки в макет для выравнивания высоты всех областей.
Выяснив причину смещения, мы можем сформулировать основные правила работы с Присоединить:
Вывести всегда создает переход на новую строку (опускает виртуальный курсор вниз). Метод Присоединить добавляет колонки справа в текущей строке. Смещение часто происходит из-за того, что программист случайно вызывает Вывести там, где нужно было Присоединить.Следуя этим правилам, вы сможете создавать отчеты любой сложности, включая динамические диаграммы и деревья подчиненности, без визуальных багов и смещений.