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

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

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

В этой статье мы подробно разберем, как решить данную задачу с помощью встроенного языка 1С. Мы рассмотрим несколько профессиональных подходов к динамическому объединению ячеек, управлению сеткой табличного документа и программному оформлению («свистелкам»), которые позволят сделать ваш отчет презентабельным и соответствующим любым требованиям руководства.

Базовый механизм: Метод Объединить()

Для объединения ячеек в табличном документе используется стандартный метод Объединить() объекта ОбластьЯчеекТабличногоДокумента. Этот метод соединяет все ячейки, входящие в указанную область, в одну общую ячейку.

Посмотрим на базовый синтаксис использования этого метода:


// Выделяем область ячеек (строка_начала, колонка_начала, строка_конца, колонка_конца)
Область = ТабДок.Область(2, 2, 3, 3);
// Объединяем ячейки в выделенной области
Область.Объединить();

Этот метод доступен на сервере, в толстом клиенте и внешнем соединении. Именно он лежит в основе всех динамических манипуляций с шапкой отчета.

Вариант 1. Расчет координат объединения «на лету»

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

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

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

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


// Предположим, что ТабДок — это наш формируемый ТабличныйДокумент
// НомерСтрокиШапки — строка, в которой будет находиться общий объединенный заголовок
НомерСтрокиШапки = 2; 

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

Вариант 2. Метод постобработки (слияние одинаковых ячеек)

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

Проанализируем ситуацию: этот метод хорош тем, что разделяет логику выборки/вывода данных и логику оформления отчета. Нам не нужно вести сложный учет индексов колонок «на лету».

Ниже представлен готовый алгоритм постобработки табличного документа:


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

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

Критически важный нюанс: сохранение сетки отчета с помощью СоздатьФорматСтрок()

Когда мы программно объединяем ячейки или динамически меняем ширину колонок в шапке, мы можем столкнуться с неприятным эффектом: сетка основного документа «поплывет». Изменение ширины колонок в шапке начнет влиять на ширину колонок в табличной части (строках данных), искажая внешний вид всего отчета.

Выясним причину этого поведения. По умолчанию табличный документ имеет общую сетку колонок для всех строк. Чтобы разорвать эту зависимость и задать для конкретной строки индивидуальный формат колонок, необходимо использовать метод СоздатьФорматСтрок().

Правило разработки: каждый раз после вывода строки шапки (или группы строк), которая содержит объединенные ячейки или требует уникальной ширины колонок, обязательно вызывайте метод СоздатьФорматСтрок() для этой области.

Посмотрим, как применить это на практике:


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

// Создаем индивидуальный формат колонок для этой строки
ОбластьСтроки.СоздатьФорматСтрок();

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

Программное оформление и визуальные эффекты

Чтобы удовлетворить требования самого взыскательного руководителя и придать заголовкам профессиональный вид, настроим оформление ячеек напрямую из кода 1С. Рассмотрим основные свойства области ячеек, которые помогут нам управлять стилем.

1. Управление цветом фона

Мы можем использовать как стандартную палитру веб-цветов 1С, так и задавать абсолютно любой цвет в формате RGB (Красный, Зеленый, Синий):


// Использование предопределенного веб-цвета
ОбластьЗаголовка.ЦветФона = WebЦвета.СиневатоСерый;

// Задание произвольного RGB-цвета (например, приятный мятный оттенок)
ОбластьЗаголовка.ЦветФона = Новый Цвет(170, 240, 209);

2. Оформление шрифтов и цвета текста

Для выделения заголовков сделаем текст контрастным и полужирным:


// Делаем шрифт жирным, сохраняя остальные свойства текущего шрифта
ОбластьЗаголовка.Шрифт = Новый Шрифт(ОбластьЗаголовка.Шрифт, , , Истина);

// Устанавливаем белый цвет текста для темных фонов
ОбластьЗаголовка.ЦветТекста = WebЦвета.Белый;

3. Выравнивание и перенос текста

Чтобы длинный текст заголовка красиво смотрелся в объединенной ячейке, настроим его центрирование по обеим осям и включим автоматический перенос:


ОбластьЗаголовка.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
ОбластьЗаголовка.ВертикальноеПоложение = ВертикальноеПоложение.Центр;
ОбластьЗаголовка.РазмещениеТекста = РазмещениеТекстаТабличногоДокумента.Переносить;

4. Управление границами ячеек

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


ТонкаяЧернаяЛиния = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
ОбластьЗаголовка.Обвести(ТонкаяЧернаяЛиния, ТонкаяЧернаяЛиния, ТонкаяЧернаяЛиния, ТонкаяЧернаяЛиния);

Комплексный пример реализации

Объединим все вышеперечисленные методики в одну готовую процедуру, которую вы сможете перенести в свой отчет и адаптировать под структуру ваших данных:


Процедура СформироватьКрасивуюШапку(ТабДок, СписокГрупп)
    
    Макет = ПолучитьМакет("Макет");
    
    // Выводим фиксированную левую часть шапки (например, "Номенклатура", "Артикул")
    ОбластьШапкаЛево = Макет.ПолучитьОбласть("ШапкаЛево");
    ТабДок.Вывести(ОбластьШапкаЛево);
    
    СтрокаШапки = ТабДок.ВысотаТаблицы; // Запоминаем строку, где будет объединенный заголовок
    
    // Цикл вывода динамических колонок
    Для Каждого Группа Из СписокГрупп Цикл
        
        КолонкаНачала = ТабДок.ШиринаТаблицы + 1;
        
        // Выводим подколонки группы (например, "План", "Факт", "Отклонение")
        Для Каждого ИмяКолонки Из Группа.Колонки Цикл
            ОбластьДинКолонка = Макет.ПолучитьОбласть("ДинамическаяКолонка");
            ОбластьДинКолонка.Параметры.Заголовок = ИмяКолонки;
            ТабДок.Присоединить(ОбластьДинКолонка);
        КонецДля;
        
        КолонкаКонца = ТабДок.ШиринаТаблицы;
        
        // Объединяем и оформляем общий заголовок над выведенной группой
        ОбластьЗаголовка = ТабДок.Область(СтрокаШапки, КолонкаНачала, СтрокаШапки, КолонкаКонца);
        ОбластьЗаголовка.Объединить();
        
        // Заполнение данных и применение стилей
        ОбластьЗаголовка.Текст = Группа.ИмяГруппы;
        ОбластьЗаголовка.ЦветФона = Группа.Цвет; // Предположим, цвет хранится в структуре группы
        ОбластьЗаголовка.ЦветТекста = WebЦвета.Белый;
        ОбластьЗаголовка.Шрифт = Новый Шрифт(ОбластьЗаголовка.Шрифт, , , Истина);
        ОбластьЗаголовка.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
        ОбластьЗаголовка.ВертикальноеПоложение = ВертикальноеПоложение.Центр;
        
        // Восстанавливаем границы
        ТонкаяЛиния = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
        ОбластьЗаголовка.Обвести(ТонкаяЛиния, ТонкаяЛиния, ТонкаяЛиния, ТонкаяЛиния);
        
    КонецДля;
    
    // Защищаем сетку таблицы от деформации
    ОбластьВсегоЗаголовка = ТабДок.Область(СтрокаШапки, 1, СтрокаШапки, ТабДок.ШиринаТаблицы);
    ОбластьВсегоЗаголовка.СоздатьФорматСтрок();
    
КонецПроцедуры

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

← На главную