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

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

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

Выясним причину ошибки: почему не работает связка Объединить и Разъединить

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


ОбластьСтрока.Область(1, 2, 1, 4).Объединить();
ОбластьСтрока.Параметры.Поле1 = "1. Поступление товаров.";
ЭлементыФормы.ПолеОтчета.Вывести(ОбластьСтрока);
ОбластьСтрока.Область(1, 2, 1, 4).Разъединить();

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

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

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

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

  1. В макете создаем две разные именованные строки: строку Итог, в которой колонки со 2 по 4 уже объединены в визуальном редакторе, и строку Строка с обычной разбивкой колонок.
  2. Перед началом цикла получаем обе секции из макета.
  3. В зависимости от логики заполняем параметры соответствующей секции и выводим нужную область.

Посмотрим на пример реализации данного подхода:


// Получаем готовые секции из макета один раз
ОбластьИтог = Макет.ПолучитьОбласть("Итог");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");

ЭлементыФормы.ПолеОтчета.НачатьАвтогруппировкуСтрок();

Если ТзПост.Количество() > 0 Тогда
    
    // Заполняем и выводим итоговую строку с объединенными ячейками
    ОбластьИтог.Параметры.Поле1 = "1. Поступление товаров.";
    ОбластьИтог.Параметры.Поле4 = Формат(ТзПост.Итог("Сумма"), "ЧЦ=10; ЧДЦ=2");
    ЭлементыФормы.ПолеОтчета.Вывести(ОбластьИтог, 1, "ИтогПТ", Истина);
    
    // Заполняем и выводим детальные строки
    Для Каждого ТекСтр Из ТзПост Цикл
        ОбластьСтрока.Параметры.Поле1 = ТекСтр.Номенклатура;
        ОбластьСтрока.Параметры.Поле2 = Формат(ТекСтр.Количество, "ЧЦ=10; ЧДЦ=3");
        ОбластьСтрока.Параметры.Поле3 = Формат(ТекСтр.Сумма / ТекСтр.Количество, "ЧЦ=10; ЧДЦ=2");
        ОбластьСтрока.Параметры.Поле4 = Формат(ТекСтр.Сумма, "ЧЦ=10; ЧДЦ=2");
        
        ЭлементыФормы.ПолеОтчета.Вывести(ОбластьСтрока, 2, "СтрокаПТ", Ложь);
    КонецЦикла;
    
КонецЕсли;

ЭлементыФормы.ПолеОтчета.ЗакончитьАвтогруппировкуСтрок();

Преимущества: код получается чистым, понятным и производительным, так как платформа не тратит ресурсы на динамическое объединение ячеек во время формирования отчета.

Способ 2. Объединение ячеек в готовом результирующем документе

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

Обратим внимание на важную деталь: метод Вывести() у объекта ТабличныйДокумент является процедурой и не возвращает выведенную область. Попытка написать Обл = ПолеОтчета.Вывести(...) вернет значение Неопределено. Поэтому определять координаты выведенной строки следует по свойству ВысотаТаблицы.

Разберем по шагам реализацию объединения в результирующей таблице:


// Запоминаем номер строки, которая будет выведена следующей
НомерСтроки = ЭлементыФормы.ПолеОтчета.ВысотаТаблицы + 1;

// Заполняем исходную секцию (ячейки в ней не объединяем!)
ОбластьСтрока.Параметры.Поле1 = "1. Поступление товаров.";
ОбластьСтрока.Параметры.Поле4 = Формат(ТзПост.Итог("Сумма"), "ЧЦ=10; ЧДЦ=2");

// Выводим секцию в отчет
ЭлементыФормы.ПолеОтчета.Вывести(ОбластьСтрока, 1, "ИтогПТ", Истина);

// Находим выведенную область в самом ПолеОтчета и объединяем нужные колонки (например, со 2 по 3)
ОбластьДляОбъединения = ЭлементыФормы.ПолеОтчета.Область(НомерСтроки, 2, НомерСтроки, 3);
ОбластьДляОбъединения.Объединить();

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

Способ 3. Повторное получение секции из макета

Если по каким-либо причинам требуется модифицировать именно исходную область секции перед выводом, необходимо компенсировать потерю параметров повторным чтением области из макета после завершения вывода итоговой строки:


// Объединяем и выводим первую строку
ОбластьСтрока.Область(1, 2, 1, 4).Объединить();
ОбластьСтрока.Параметры.Поле1 = "Итог";
ЭлементыФормы.ПолеОтчета.Вывести(ОбластьСтрока);

// Перечитываем исходную секцию из макета заново, сбрасывая изменения
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");

// Теперь параметры Поле2, Поле3 и Поле4 снова доступны
ОбластьСтрока.Параметры.Поле2 = "Данные";
ЭлементыФормы.ПолеОтчета.Вывести(ОбластьСтрока);

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

← На главную