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