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

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

В процессе разработки отчетов в 1С часто возникает задача представить данные в сгруппированном виде. Стандартные механизмы, например, в СКД, отлично справляются с этим, размещая группировочные поля в заголовках. Но что делать, если по требованиям заказчика сгруппированные данные (например, "Операция" или "Оборудование") должны находиться справа от детализированных записей, а ячейки с одинаковыми значениями должны быть объединены по вертикали?

Рассмотрим несколько программных подходов для решения этой задачи в обычном макете табличного документа.

Решение 1: Постобработка табличного документа после вывода

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

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

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

Посмотрим на пример кода для постобработки одной колонки:

Предположим, у нас есть сформированный табличный документ ТабДок, и нам нужно объединить ячейки во второй колонке.


// ТабДок - уже сформированный табличный документ
// НомерКолонки - номер колонки для объединения (например, 2)

ПоследняяСтрока = ТабДок.ВысотаТаблицы;
// Начинаем со строки, где идут данные (пропускаем заголовок)
НачалоОбъединения = 2; 

Для НомерСтроки = 2 По ПоследняяСтрока Цикл
    // Получаем текст текущей ячейки
    ТекстТекущий = ТабДок.Область(НомерСтроки, НомерКолонки).Текст;
    
    // Получаем текст следующей ячейки, если она существует
    ТекстСледующий = "";
    Если НомерСтроки < ПоследняяСтрока Тогда
        ТекстСледующий = ТабДок.Область(НомерСтроки + 1, НомерКолонки).Текст;
    КонецЕсли;

    // Условие завершения группы: текст в следующей строке отличается или это последняя строка таблицы
    Если ТекстТекущий <> ТекстСледующий Или НомерСтроки = ПоследняяСтрока Тогда
        
        // Проверяем, есть ли что объединять (в группе больше одной строки)
        Если НомерСтроки > НачалоОбъединения Тогда
            // Определяем область для объединения
            ОбластьДляОбъединения = ТабДок.Область(НачалоОбъединения, НомерКолонки, НомерСтроки, НомерКолонки);
            // Выполняем объединение
            ОбластьДляОбъединения.Объединить();
        КонецЕсли;
        
        // Началом следующей группы будет следующая строка
        НачалоОбъединения = НомерСтроки + 1;
    КонецЕсли;
КонецЦикла;

Важный момент: производительность. Для отчетов размером до нескольких десятков тысяч строк этот метод работает достаточно быстро. Однако на очень больших объемах данных (сотни тысяч строк) он может вызывать заметные "тормоза", так как работа с уже отрисованным табличным документом — довольно ресурсоемкая операция.

Решение 2: Оптимизация процесса объединения

Чтобы избежать медленного второго прохода по большому табличному документу, можно подготовить информацию для объединения уже на этапе первоначального формирования отчета. Это можно сделать двумя способами.

Способ А: Использование маркеров в служебной колонке

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

  1. При выводе данных в цикле отслеживаем смену значения в поле "Операция".
  2. Когда значение меняется, в служебную колонку предыдущей строки ставим метку "КонецГруппы", а в текущую — "НачалоГруппы".
  3. После полного вывода отчета запускаем быстрый цикл, который ищет эти метки и выполняет объединение.
  4. В конце очищаем служебную колонку или просто скрываем ее.

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

Способ Б: Объединение "на лету" с помощью переменных

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

Алгоритм такой:

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


// Примерный код в цикле выборки данных
Перем ПредыдущаяОперация, НачалоГруппыОперация;

//...
// Внутри цикла обхода выборки
//...

// Если это первая строка или сменилась операция
Если ПредыдущаяОперация = Неопределено ИЛИ ПредыдущаяОперация <> Выборка.Операция Тогда
    // Если это не первая строка, значит, предыдущая группа закончилась. Объединяем ее.
    Если ПредыдущаяОперация <> Неопределено Тогда
        КонецГруппыОперация = ТабДок.ВысотаТаблицы;
        Если КонецГруппыОперация > НачалоГруппыОперация Тогда
            ТабДок.Область(НачалоГруппыОперация, НомерКолонкиОперация, КонецГруппыОперация, НомерКолонкиОперация).Объединить();
        КонецЕсли;
    КонецЕсли;

    // Запоминаем данные для новой группы
    ПредыдущаяОперация = Выборка.Операция;
    НачалоГруппыОперация = ТабДок.ВысотаТаблицы + 1; // +1, так как строка еще не выведена
КонецЕсли;

// ... здесь идет код вывода строки в ТабДок ...
ТабДок.Вывести(ОбластьСтрока);

// ... после цикла нужно не забыть объединить последнюю группу ...

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

Решение 3: Альтернатива — имитация объединения через оформление

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

Суть метода:

Визуально это выглядит как одна большая ячейка, но структурно это остаются отдельные ячейки. Это сохраняет функциональность отчета при дальнейшей работе с ним. В обычном макете это реализуется программным управлением свойствами ячеек (ВерхняяГраница, НижняяГраница, Текст) в цикле вывода данных.

← На главную