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

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

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

Разберем основные практические подходы к решению этой задачи в коде платформы 1С:Предприятие.

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

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

Разберем по шагам логику этого алгоритма:

  1. Перед циклом вывода строк детальных записей запоминаем номер первой выводимой строки через свойство ВысотаТаблицы.
  2. В цикле построчно выводим строки с помощью метода ТабДок.Вывести(). Значение родительской сущности (например, наименование услуги) можно передать в первую строку группы.
  3. После завершения вывода подчиненных строк фиксируем номер последней строки.
  4. Если в группе было выведено две и более строки, получаем область по числовым координатам Область(Верх, Лево, Низ, Право) и вызываем метод Объединить().

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


&НаСервере
Процедура СформироватьТабличныйДокумент(ТабДок, ДанныеДляПечати)
    
    Макет = Документы.ОказаниеУслуг.ПолучитьМакет("Печать");
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
    
    ТабДок.Очистить();
    ТабДок.Вывести(ОбластьШапка);
    
    НомерКолонкиУслуги = 1;
    
    Для Каждого ГруппаУслуг Из ДанныеДляПечати Цикл
        
        НомерПервойСтроки = ТабДок.ВысотаТаблицы + 1;
        ПерваяСтрокаГруппы = Истина;
        
        Для Каждого Подстрока Из ГруппаУслуг.СписокРабот Цикл
            
            Если ПерваяСтрокаГруппы Тогда
                ОбластьСтрока.Параметры.Услуга = ГруппаУслуг.Наименование;
                ПерваяСтрокаГруппы = Ложь;
            Иначе
                ОбластьСтрока.Параметры.Услуга = "";
            КонецЕсли;
            
            ОбластьСтрока.Параметры.Работа = Подстрока.Наименование;
            ОбластьСтрока.Параметры.Сумма = Подстрока.Сумма;
            
            ТабДок.Вывести(ОбластьСтрока);
            
        КонецЦикла;
        
        НомерПоследнейСтроки = ТабДок.ВысотаТаблицы;
        
        Если НомерПоследнейСтроки > НомерПервойСтроки Тогда
            ОбластьДляОбъединения = ТабДок.Область(НомерПервойСтроки, НомерКолонкиУслуги, НомерПоследнейСтроки, НомерКолонкиУслуги);
            ОбластьДляОбъединения.Объединить();
            ОбластьДляОбъединения.ВертикальноеПоложение = ВертикальноеПоложение.Верх;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Способ 2. Использование метода Присоединить и вспомогательного табличного документа

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

Рассмотрим пример кода на стороне сервера:


&НаСервере
Процедура СформироватьСПрисоединением(ТабДок)
    
    // Формируем родительскую секцию нужной высоты
    СекцияРодитель = ТабДок.ПолучитьОбласть("R1C1:R3C1");
    ОбластьРодитель = СекцияРодитель.Область("R1C1:R3C1");
    ОбластьРодитель.Объединить();
    ОбластьРодитель.ВертикальноеПоложение = ВертикальноеПоложение.Верх;
    СекцияРодитель.Область("R1C1").Текст = "Услуга комплексная";
    ТабДок.Вывести(СекцияРодитель);
    
    // Формируем подчиненные строки во временном документе
    ТабДокДетали = Новый ТабличныйДокумент;
    
    СекцияДетали = ТабДокДетали.ПолучитьОбласть("R1C1");
    СекцияДетали.Область().Текст = "Работа 1";
    ТабДокДетали.Вывести(СекцияДетали);
    
    СекцияДетали = ТабДокДетали.ПолучитьОбласть("R1C1");
    СекцияДетали.Область().Текст = "Работа 2";
    ТабДокДетали.Вывести(СекцияДетали);
    
    СекцияДетали = ТабДокДетали.ПолучитьОбласть("R1C1");
    СекцияДетали.Область().Текст = "Работа 3";
    ТабДокДетали.Вывести(СекцияДетали);
    
    // Присоединяем сформированную детальную часть к основной таблице
    ТабДок.Присоединить(ТабДокДетали);
    
КонецПроцедуры

Обратите внимание: этот способ требует точного совпадения высоты родительской ячейки и суммарной высоты всех выводимых подчиненных строк во вспомогательном документе, иначе строки таблицы могут сместиться по вертикали относительно друг друга.

Способ 3. Имитация объединения через оформление границ ячеек

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

Разберем логику настройки макета:

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

Визуально для пользователя колонка услуги выглядит монолитной, при этом сами строки остаются независимыми ячейками, что исключает ошибки при экспорте в форматы Excel или расчете автовысоты.

Важные нюансы при работе с объединенными ячейками

Выясним особенности поведения платформы 1С при вертикальном объединении ячеек:

  1. Контроль разрыва страниц при печати: объединенная ячейка не может быть разорвана страницей пополам. Если группа строк целиком не помещается на лист, перед ее выводом следует проверять вместимость методом ТабДок.ПроверитьВывод(). Если группа не помещается, вызываем ТабДок.ВывестиГоризонтальныйРазделительСтраниц().
  2. Автовысота строк: механизм АвтоВысотаСтроки рассчитывает требуемую высоту по первой строке объединенной области. Если текст в родительской ячейке длинный, а суммарной высоты подчиненных строк недостаточно, текст может обрезаться. В таких ситуациях рекомендуется явно задавать высоту строк через свойство ВысотаСтроки.
← На главную