При разработке отчетов в системе компоновки данных (СКД) разработчики часто сталкиваются с задачей сопоставления данных. Например, требуется вывести продажи текущего и прошлого года или дебиторскую и кредиторскую задолженность параллельно, в двух самостоятельных таблицах. Однако по умолчанию при добавлении в структуру отчета двух независимых таблиц или группировок система выводит их строго последовательно — одна под другой.
Выясним причину такого поведения платформы и подробно разберем все возможные способы решения этой задачи: от программного формирования отчета до манипуляций с запросом и интерфейсом формы.
В типовом компоновщике макета и процессоре вывода СКД элементы верхнего уровня структуры всегда генерируются последовательно сверху вниз. В интерфейсе настройки структуры отчета разработчик не может указать горизонтальное или параллельное расположение двух несвязанных ветвей группировок. Поэтому для расположения таблиц бок о бок требуются обходные инженерные решения.
Рассмотрим основной способ решения задачи, предложенный в обсуждении. Он заключается в перехвате процесса формирования отчета в модуле отчета в событии ПриКомпоновкеРезультата. Мы формируем две независимые таблицы во временные табличные документы, а затем объединяем их в единый ДокументРезультат методами Вывести() и Присоединить().
Разберем по шагам алгоритм реализации:
ПриКомпоновкеРезультата и отключаем стандартную обработку: СтандартнаяОбработка = Ложь;.Присоединить() не переносит ширину столбцов автоматически.Посмотрим на пример программного кода, демонстрирующий базовое формирование таблицы через процессор компоновки:
// Получаем схему из макета
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
// Инициализируем настройки
КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных();
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных));
КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
Настройки = КомпоновщикНастроек.Настройки;
// Устанавливаем параметры отчета при необходимости
// Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Параметр1", ЗначениеПараметра1);
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
// Формируем макет компоновщика
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
// Выполняем компоновку
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
// Выводим результат в промежуточный табличный документ
ТабДок1 = Новый ТабличныйДокумент();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок1);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
Аналогичным образом формируем второй табличный документ — ТабДок2. Теперь объединим оба документа в итоговый ДокументРезультат, склеивая их построчно:
ДокументРезультат.Очистить();
МаксСтрок = Макс(ТабДок1.ВысотаТаблицы, ТабДок2.ВысотаТаблицы);
Для НомерСтроки = 1 По МаксСтрок Цикл
// Обрабатываем левую таблицу
Если НомерСтроки <= ТабДок1.ВысотаТаблицы Тогда
Обл1 = ТабДок1.Область(НомерСтроки, 1, НомерСтроки, ТабДок1.ШиринаТаблицы);
ДокументРезультат.Вывести(Обл1);
Иначе
// Если левая таблица короче, выводим пустую строку соответствующей ширины
Обл1 = ДокументРезультат.Область(НомерСтроки, 1, НомерСтроки, ТабДок1.ШиринаТаблицы);
КонецЕсли;
// Присоединяем правую таблицу сбоку
Если НомерСтроки <= ТабДок2.ВысотаТаблицы Тогда
Обл2 = ТабДок2.Область(НомерСтроки, 1, НомерСтроки, ТабДок2.ШиринаТаблицы);
ДокументРезультат.Присоединить(Обл2);
КонецЕсли;
КонецЦикла;
// Корректируем ширину колонок для правой таблицы
Смещение = ТабДок1.ШиринаТаблицы;
Для НомерКолонки = 1 По ТабДок2.ШиринаТаблицы Цикл
Ширина = ТабДок2.Область(1, НомерКолонки).ШиринаКолонки;
ДокументРезультат.Область(, Смещение + НомерКолонки).ШиринаКолонки = Ширина;
КонецЦикла;
Важный момент: метод Присоединить() не переносит исходную ширину колонок. Если не скорректировать свойство ШиринаКолонки вручную в цикле, колонки правой таблицы сожмутся до стандартной системной ширины.
Если требуется сохранить стандартный функционал СКД (типовую работу расшифровок, пользовательские настройки колонок, печать без переопределения модулей), задачу можно решить на уровне текста запроса схемы компоновки данных.
Проанализируем этот подход по шагам:
ВТ_Таблица1 и ВТ_Таблица2).При таком подходе данные обеих выборок визуально отображаются на одной строке. Если одна таблица содержит больше строк, чем другая, в незаполненных ячейках отобразятся значения NULL, что визуально дает ровно две расположенные рядом таблицы.
Если отчет предназначен исключительно для экранного анализа и не требует сквозного экспорта в один файл Excel или постраничной печати, можно решить задачу на уровне интерфейса.
Рассмотрим структуру элементов формы:
Поле табличного документа (например, ТабличныйДокументЛевый и ТабличныйДокументПравый).Такой подход обеспечивает независимую горизонтальную и вертикальную прокрутку каждой таблицы, сохраняет стандартные механизмы оформления и расшифровки 1С без сложного ручного объединения макетов.