При разработке отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с требованием пользователей (особенно бухгалтеров) сделать шапку отчета более компактной и читаемой — есть инструментарий для отладки кода и запросов СКД. Типичная ситуация: у нас есть горизонтальная группировка, например, по приемам пищи (Завтрак, Обед), а внутри нее — группировка по блюдам (Каша, Суп, Чай). По умолчанию СКД будет дублировать заголовок родительской группировки над каждой колонкой вложенной. Наша задача — сделать так, чтобы заголовок "Завтрак" был написан один раз и объединял все относящиеся к нему колонки блюд.
Рассмотрим, почему стандартными средствами настроек это сделать практически невозможно и разберем пошагово элегантный программный способ решения этой задачи.
В СКД нет прямой галочки "Объединять заголовки по горизонтали". Если колонки формируются динамически (их количество заранее неизвестно), статические макеты оформления часто "разваливаются" или не подходят для гибких отчетов. Мы проанализируем метод, который основан на постобработке уже сформированного ТабличногоДокумента.
Для того чтобы наша программа поняла, какие именно ячейки в итоговом документе нужно объединить, мы должны пометить их специальным маркером. В качестве маркера выберем любую редкую текстовую комбинацию, например, {ОБЪЕДИНИТЬ}.
Рассмотрим наиболее правильный способ добавления маркера — через Выражение представления в наборе данных СКД. Это позволит нам сохранить оригинальное значение поля (ссылку) для работы расшифровки, изменив только визуальный текст.
ПриемПищи).
Строка(ПриемПищи) + "{ОБЪЕДИНИТЬ}"
Важный нюанс: если поле имеет тип, отличный от строки (например, СправочникСсылка или Дата), обязательно используем функцию Строка(), иначе система выдаст ошибку "Неверные параметры +".
Теперь нам нужно программно сформировать отчет, чтобы получить доступ к табличному документу до того, как он будет показан пользователю. Для этого в модуле объекта отчета найдем (или создадим) обработчик события (поможет инструмент для отладки кода 1С в режиме «Предприятие») ПриКомпоновкеРезультата.
Разберем код, который отключает стандартный вывод и инициализирует ручной процесс:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отключаем автоматический вывод
ДокументРезультат.Очистить();
// Инициализируем настройки и процессор вывода
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Здесь будет вызываться наш механизм объединения
МаркерОбъединения = "{ОБЪЕДИНИТЬ}";
ОбъединитьЯчейкиВТабличномДокументе(ДокументРезультат, МаркерОбъединения);
ЗаменитьТекстВТабличномДокументе(ДокументРезультат, МаркерОбъединения, "");
КонецПроцедуры
Проанализируем логику работы вспомогательной функции. Нам нужно пройти по ячейкам табличного документа, найти те, что содержат наш маркер, и, если соседние ячейки имеют одинаковый текст, объединить их.
Рассмотрим пример реализации функции поиска и объединения:
Процедура ОбъединитьЯчейкиВТабличномДокументе(ТабДок, Маркер)
КоличествоСтрок = ТабДок.ВысотаТаблицы;
КоличествоКолонок = ТабДок.ШиринаТаблицы;
// Проходим циклом по шапке (обычно это первые 10-20 строк)
// Для оптимизации можно ограничить диапазон поиска
Для НомерСтроки = 1 По КоличествоСтрок Цикл
Для НомерКолонки = 1 По КоличествоКолонок Цикл
ТекущаяОбласть = ТабДок.Область(НомерСтроки, НомерКолонки);
ТекстЯчейки = ТекущаяОбласть.Текст;
Если Найти(ТекстЯчейки, Маркер) > 0 Тогда
// Нашли начало потенциального объединения
НачалоОбъединения = НомерКолонки;
КонецОбъединения = НомерКолонки;
// Проверяем следующие ячейки справа
Для К = НомерКолонки + 1 По КоличествоКолонок Цикл
СледующаяОбласть = ТабДок.Область(НомерСтроки, К);
Если СледующаяОбласть.Текст = ТекстЯчейки Тогда
КонецОбъединения = К;
Иначе
Прервать;
КонецЕсли;
КонецЦикла;
Если КонецОбъединения > НачалоОбъединения Тогда
ТабДок.Область(НомерСтроки, НачалоОбъединения, НомерСтроки, КонецОбъединения).Объединить();
// Сдвигаем счетчик колонок, чтобы не обрабатывать уже объединенные
НомерКолонки = КонецОбъединения;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецДля;
КонецПроцедуры
После того как ячейки объединены, текст {ОБЪЕДИНИТЬ} больше не нужен — он будет только мешать пользователю. Нам необходимо выполнить глобальную замену этого текста на пустую строку во всем документе.
Процедура ЗаменитьТекстВТабличномДокументе(ТабДок, ЧтоИскать, НаЧтоЗаменить)
// Используем метод НайтиТекст для быстрого поиска и замены
НайденнаяОбласть = ТабДок.НайтиТекст(ЧтоИскать);
Пока НайденнаяОбласть <> Неопределено Цикл
НайденнаяОбласть.Текст = СтрЗаменить(НайденнаяОбласть.Текст, ЧтоИскать, НаЧтоЗаменить);
НайденнаяОбласть = ТабДок.НайтиТекст(ЧтоИскать);
КонецЦикла;
КонецПроцедуры
Частая проблема при программном выводе СКД — "пропадание" возможности кликнуть на поле и открыть связанный объект. Выясним причину: расшифровка отключается, если мы выводим в ячейку просто текст вместо значения. Однако, используя предложенный метод с Выражением представления, мы решаем эту проблему:
Текст ячейки будет находиться наша строка с маркером.ПараметрРасшифровки по-прежнему будет содержаться ссылка на объект, так как Процессор Вывода заполнил его автоматически.Важно убедиться, что при вызове ПроцессорКомпоновки.Инициализировать вы передаете переменную ДанныеРасшифровки, полученную из параметров процедуры ПриКомпоновкеРезультата. Без этого интерактивность отчета будет потеряна.
Если задача стоит не в физическом объединении ячеек, а только в визуальном скрытии дублей, можно применить более простой, но менее эстетичный способ. В Условном оформлении для повторяющихся полей группировки можно задать условие: если значение в текущей колонке совпадает с предыдущим, установить цвет текста, равный цвету фона (белый). Также можно убрать правую или левую границу ячейки. Это создаст иллюзию единого пространства, хотя технически ячейки останутся раздельными.
Мы рассмотрели наиболее надежный способ объединения заголовков горизонтальных группировок в СКД. Использование маркеров и программная постобработка ТабличногоДокумента позволяют создавать отчеты любой сложности, которые полностью удовлетворяют требования пользователей к оформлению. Помните о необходимости приведения данных к строковому типу при использовании маркеров и всегда проверяйте работоспособность расшифровки после программного вмешательства в результат компоновки.