Просматривал утром статистику посещений блога, наткнулся на переход с форума Инфостарта, из темы про сохранение дерева значений в табличный документ. Самый простой способ - рекурсивный обход строк дерева, автор так и поступил. Но тема перекликается с моей предыдущей статьей о произвольной иерархии СКД, только использование внешних наборов данных в ней не рассматривается. Поэтому решил исправить данный недостаток и набросать небольшой пример вывода дерева значений с помощью системы компоновки данных.
При использовании дерева значений в качестве внешнего набора данных для схемы компоновки связи дочерних строк с родительскими не передаются. Поэтому, чтобы сохранить эти связи, в дерево необходимо добавить служебные поля для хранения идентификатора строки и идентификатора родителя. Заполнять эти поля стоит в процессе формирования дерева.
Для демонстрации создам обработку, содержащую дерево значений, которое будет редактироваться на форме и табличный документ для вывода результата.
Реализуем заполнение служебных полей. ИД родителя для корневой строки буду считать равным нулю, поэтому все остальные ИД строк сохраняю с увеличением на единицу.
&НаКлиенте
Процедура Т_ПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
Если НоваяСтрока Тогда
ТекущиеДанные = Элемент.ТекущиеДанные;
ТекущиеДанные.Ид = ТекущиеДанные.ПолучитьИдентификатор() + 1;
ТекущиеДанныеРодитель = ТекущиеДанные.ПолучитьРодителя();
ТекущиеДанные.РодительИд = ?(ТекущиеДанныеРодитель = Неопределено, 0, ТекущиеДанныеРодитель.ПолучитьИдентификатор() + 1);
КонецЕсли;
КонецПроцедуры
Теперь сделаем вывод дерева в компоновку. Сначала хотел показать, как настроить схему компоновки в редакторе, но потом решил добавить немного универсальности и генерировать ее программно на основании дерева значений.&НаСервере
Процедура СформироватьТабличныйДокументНаСервере()
ТабДокумент = Новый ТабличныйДокумент;
ДанныеДерева = РеквизитФормыВЗначение("Т");
ИсточникиДанных = Новый Структура("ДанныеДерева", ДанныеДерева);
СхемаКомпоновки = ПолучитьСхемуКомпоновкиПоДереву(ДанныеДерева);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, СхемаКомпоновки.НастройкиПоУмолчанию);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ИсточникиДанных);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДокумент);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
&НаСервере
Функция ПолучитьСхемуКомпоновкиПоДереву(ДанныеДерева, ВыбранныеПоляДерева = Неопределено, ПолеИД = "ИД", ПолеРодительИД = "РодительИД")
Если ВыбранныеПоляДерева = Неопределено Тогда
ВыбранныеПоляДерева = Новый Массив;
КонецЕсли;
ЗаполнитьВыбранныеПоляДерева = НЕ ВыбранныеПоляДерева.Количество();
СхемаКомпоновки = Новый СхемаКомпоновкиДанных;
НастройкиКомпоновки = СхемаКомпоновки.НастройкиПоУмолчанию;
ИсточникДанных = СхемаКомпоновки.ИсточникиДанных.Добавить();
ИсточникДанных.Имя = "ИсточникДанных";
ИсточникДанных.ТипИсточникаДанных = "Local";
НаборДанных = СхемаКомпоновки.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
НаборДанных.ИмяОбъекта = "ДанныеДерева";
НаборДанных.Имя = "НаборДанных";
НаборДанных.ИсточникДанных = "ИсточникДанных";
Для Каждого КолонкаДерева Из ДанныеДерева.Колонки Цикл
ИмяПоля = КолонкаДерева.Имя;
ЗаголовокПоля = КолонкаДерева.Заголовок;
ПолеНабора = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
ПолеНабора.Заголовок = ЗаголовокПоля;
ПолеНабора.Поле = ИмяПоля;
Если ЗаполнитьВыбранныеПоляДерева И НЕ (ИмяПоля = ПолеИД ИЛИ ИмяПоля = ПолеРодительИД)Тогда
ВыбранныеПоляДерева.Добавить(Новый Структура("Имя, Заголовок", ИмяПоля, ЗаголовокПоля));
КонецЕсли;
КонецЦикла;
СвязьНабора = СхемаКомпоновки.СвязиНаборовДанных.Добавить();
СвязьНабора.НаборДанныхИсточник = "НаборДанных";
СвязьНабора.НаборДанныхПриемник = "НаборДанных";
СвязьНабора.ВыражениеИсточник = ПолеИД;
СвязьНабора.ВыражениеПриемник = ПолеРодительИд;
СвязьНабора.НачальноеВыражение = "0";
ВыбранныеПоля = НастройкиКомпоновки.Выбор.Элементы;
Для Каждого ПолеДерева Из ВыбранныеПоляДерева Цикл
ПолеОтчет = ВыбранныеПоля.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ПолеОтчет.Поле = Новый ПолеКомпоновкиДанных(ПолеДерева.Имя);
ПолеОтчет.Заголовок = ПолеДерева.Заголовок;
КонецЦикла;
СтруктураГруппировки = НастройкиКомпоновки.Структура;
ЭлементГруппировки = СтруктураГруппировки.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
ЭлементГруппировки.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
Возврат СхемаКомпоновки;
КонецФункции// ПолучитьСхемуКомпоновкиПоДереву()
&НаКлиенте
Процедура СформироватьТабличныйДокумент(Команда)
СформироватьТабличныйДокументНаСервере();
КонецПроцедуры
Проверяем результат, заполняем дерево:Получаем табличный документ:
Сама обработка, включает макет схемы компоновки для демонстрации настроек.
Очень интересно, как это автору удалось скормить в процессор компоновки данных дерево значений, когда он их отродясь не воспринимал.
ОтветитьУдалитьИз руководстве разработчика "Набор данных – объект используется для вывода в отчет информации из некоторого объекта встроенного языка: таблицы значений, результата запроса, текущего документа и т. п." https://its.1c.ru/db/v8317doc#bookmark:dev:TI000000553
УдалитьНичего насчет ограничения по типу не сказано.
Руководство это теория. На практике - не работает и никогда не работало. Не дезинформируйте читателей.
УдалитьКак насчет скачать и проверить? Ссылка в конце публикации.
УдалитьСсылка не работает, ещё позавчера убедился. Тупо виснет.
Удалитьhttps://yadi.sk/d/KX-C4MoQrwTTLw
УдалитьОгромное спасибо за статью!!!
ОтветитьУдалитьТак намного легче и проще чем свой вывод рисовать!
Тоже спасиба! За идею, как дерево с СКД дружить.
ОтветитьУдалить