Для УП:
Код 1C v 8.3
&НаКлиенте
. . . .
ФМ= Новый ФиксированнаяСтруктура( "КлючСвязи" , Элементы. ДанныеБезКоррекции. ТекущиеДанные. КлючСвязи) ;
Элементы. СписокПодразделений. ОтборСтрок= ФМ;
Код 1C v 8.3
Функция ПолучитьЗаписиСогласноОтбору(ТабличноеПолеИсточник)
ОтборСтрок = ТабличноеПолеИсточник. ОтборСтрок;
ПостроительЗапроса = Новый ПостроительЗапроса;
ПостроительЗапроса. ИсточникДанных = Новый ОписаниеИсточникаДанных( ТабличноеПолеИсточник. Значение) ;
Для Каждого ЭлементОтбора Из ОтборСтрок Цикл
Если ЭлементОтбора. Использование Тогда
НовыйОтбор = ПостроительЗапроса. Отбор. Добавить( ЭлементОтбора. Имя) ;
НовыйОтбор. Использование = Истина ;
НовыйОтбор. ВидСравнения = ЭлементОтбора. ВидСравнения;
НовыйОтбор. ЗначениеС = ЭлементОтбора. ЗначениеС;
НовыйОтбор. ЗначениеПо = ЭлементОтбора. ЗначениеПо;
НовыйОтбор. Значение = ЭлементОтбора. Значение;
КонецЕсли ;
КонецЦикла ;
Таблица = ПостроительЗапроса. Результат. Выгрузить( ) ;
МассивСтрок = Новый Массив;
Для Каждого Стр ИЗ Таблица Цикл
СтруктураПоиска = Новый Структура;
Для Каждого Колонка Из Таблица. Колонки Цикл
СтруктураПоиска. Вставить( Колонка. Имя, Стр[Колонка. Имя]) ;
КонецЦикла ;
НайденыеСтроки = ТабличноеПолеИсточник. Значение. НайтиСтроки( СтруктураПоиска) ;
Если НайденыеСтроки. Количество( ) > 0 Тогда
МассивСтрок. Добавить( НайденыеСтроки[0 ]) ;
КонецЕсли ;
КонецЦикла ;
Возврат МассивСтрок;
КонецФункции
Для Обычных форм:
Код 1C v 8.х ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("ДокСсылка", ДанныеПоШК.Объект);
НайденныеСтроки = ПакетДокументов.НайтиСтроки(ПараметрыОтбора);
// Подробнее
СтруктураОтбора = Новый Структура("ВидДокумента, Контрагент", ПФ, ?(Контр = Неопределено, Справочники.Контрагенты.ПустаяСсылка(), Контр));
ПакетДокументов = ЗадачаОбъект.ПакетДокументов;
МассивСтрок = ПакетДокументов.НайтиСтроки(СтруктураОтбора);
Если МассивСтрок.Количество() Тогда
Для Каждого СтрокаМассива Из МассивСтрок Цикл
СтрокаМассива.ДобавленоПользователем = Истина;
СтрокаМассива.Пользователь = ПараметрыСеанса.ТекущийПользователь;
СтрокаМассива.ДатаВремя = ТекущаяДата();
КонецЦикла;
КонецЕсли;
//или
ТЧ = ПромежуточнаяНакладная.Выгрузить();
ТЧ.Свернуть("СхемаПродажи");
СтрокаСПустойСП = ТЧ.НайтиСтроки(Новый Структура("СхемаПродажи", Справочники.СхемыПродаж.ПустаяСсылка()));
Если ТЧ.Количество() - СтрокаСПустойСП.Количество() > 1 Тогда
Если Вопрос("Сбросить все схемы в строках?", РежимДиалогаВопрос.ДаНет) = КодВозвратаДиалога.Нет Тогда
НесколькоСхем = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
Для каждого СтрокаПН из ПромежуточнаяНакладная Цикл
Если СтрокаПН.Номенклатура.ВидНоменклатуры.ТипНоменклатуры <> Перечисления.ТипыНоменклатуры.Услуга Тогда
СтрокаПН.СхемаПродажи = СхемаПродажи;
КонецЕсли;
КонецЦикла;
Для одной организации надо было реализовать документы, где вместо табличной части надо использовать дерево и все это на управляемых формах. Но дерево нельзя сохранить в базе в текущем виде. Пришлось использовать табличную часть документа для хранения данных дерева. И при открытии формы получать данные из ТЧ и выводить их в дерево. Далее все манипуляции производить с деревом и при сохранении документа помещать данные в обратно в ТЧ.
Поиск по интернету не дал нужного варианта, пришлось реализовавыть свой механизм, используя информацию которая была на просторах интернета.
Для реализации такого механизма в ТЧ был добавлен реквизит “КлючСвязи” (обязательный реквизит) с типом число, куда помещался “НомерСтроки” (стандартный реквизит ТЧ) родителя (верхний уровень). А самый верхний элемент дерева имеет “КлючСвязи” равный 0.
На картинке ниже видно структуру дерева и структуру ТЧ
Нагрузка на сервер осуществляется при окрытии и при сохранении документа. А с деревом работают уже на клиенте.
На рабочей базе обрабатывается около 200 строк в одном документе.
Открытие и сохранение документа происходит моментально. С большем количеством строк не тестировалось.
Чтобы алгорит правильно работал, у рекизита фомы с типом дерево значений должны быть все реквизиты табличной части, кроме “КлючСвязи” и “НомерСтроки”. Иначе платформа выдаст ошибку. В дерево можо добавлять свои реквизиты отличные от ТЧ, они будут использоваться только в дереве.
Ниже приведен код преобразования дерева в таблицу и обратно .
Код 1C v 8.2 УП &НаКлиенте
Процедура КомандаТаблицуВДерево(Команда)
КомандаТаблицуВДеревоНаСервере( ) ;
КонецПроцедуры
&НаСервере
Процедура КомандаТаблицуВДеревоНаСервере()
Дерево = ТаблицаВДерево( РеквизитФормыВЗначение( "Объект" ) , "Товары" ) ;
ЗначениеВРеквизитФормы( Дерево, "ДеревоЗначений" ) ;
Элементы. ДеревоЗначений. Обновить( ) ;
КонецПроцедуры
&НаКлиенте
Процедура КомандаДеревоВТаблицу(Команда)
КомандаДеревоВТаблицуНаСервере( ) ;
КонецПроцедуры
&НаСервере
Процедура КомандаДеревоВТаблицуНаСервере()
Объект. Товары. Очистить( ) ;
ДОбъект = РеквизитФормыВЗначение( "Объект" ) ;
ДеревоВТаблицу( ДОбъект, РеквизитФормыВЗначение( "ДеревоЗначений" ) , "Товары" ) ;
ЗначениеВРеквизитФормы( ДОбъект, "Объект" ) ;
КонецПроцедуры
Формирование дерева из таблицы значений
Код 1C v 8.2 УП
&НаСервере
Функция ТаблицаВДерево(ДокОбъект, НаименованиеТабличнойЧастиДокумента, КлючСвязи = NULL, ЭлементРодитель = NULL) Экспорт
КолонкиТаблицы = ДокОбъект. Метаданные( ) . ТабличныеЧасти[НаименованиеТабличнойЧастиДокумента]. Реквизиты;
ДеревоЗначений2 = Новый ДеревоЗначений;
Для каждого Кол из КолонкиТаблицы Цикл
Если Кол. Имя = "НомерСтроки" ИЛИ Кол. Имя = "КлючСвязи" Тогда
Продолжить;
Иначе
ДеревоЗначений2 . Колонки. Добавить( Кол. Имя, Новый ОписаниеТипов( Кол. Тип) ) ;
КонецЕсли ;
КонецЦикла ;
Если КлючСвязи = NULL И ЭлементРодитель = NULL Тогда
ИсточникВыборки = ДеревоЗначений2 . Строки;
КлючСвязи = 0 ;
Иначе
ИсточникВыборки = ЭлементРодитель. Строки;
КонецЕсли ;
Фильтр = Новый Структура( "КлючСвязи" , КлючСвязи) ;
М = ДокОбъект[НаименованиеТабличнойЧастиДокумента]. НайтиСтроки( Фильтр) ;
Если М. Количество( ) = 0 Тогда
Возврат ДеревоЗначений2 ;
КонецЕсли ;
Для каждого Стр из М Цикл
Элемент = ИсточникВыборки. Добавить( ) ;
Для каждого Кол из КолонкиТаблицы Цикл
Если Кол. Имя = "НомерСтроки" ИЛИ Кол. Имя = "КлючСвязи" Тогда
Продолжить;
Иначе
Элемент[Кол. Имя] = Стр[Кол. Имя];
КонецЕсли ;
КонецЦикла ;
ТаблицаВДерево( ДокОбъект, НаименованиеТабличнойЧастиДокумента, Стр. НомерСтроки, Элемент) ;
КонецЦикла ;
Возврат ДеревоЗначений2 ;
КонецФункции
Формирование таблицы из дерева
Код 1C v 8.2 УП
&НаСервере
Процедура ДеревоВТаблицу(ДокОбъект, ДеревоЗначений, НаименованиеТабличнойЧастиДокумента, СтрокаДерева = NULL, КлючСвязи = NULL) Экспорт
Если СтрокаДерева = NULL И КлючСвязи = NULL Тогда
ПервыйВызов = Истина ;
ДокОбъект[НаименованиеТабличнойЧастиДокумента]. Очистить( ) ;
ИсточникВыборки = ДеревоЗначений. Строки;
КлючСвязи = 0 ;
Иначе
ПервыйВызов = Ложь ;
ИсточникВыборки = СтрокаДерева. Строки;
КонецЕсли ;
Для каждого Стр из ИсточникВыборки Цикл
НС = ДокОбъект[НаименованиеТабличнойЧастиДокумента]. Добавить( ) ;
Для каждого Кол из ДокОбъект. Метаданные( ) . ТабличныеЧасти[НаименованиеТабличнойЧастиДокумента]. Реквизиты Цикл
Если Кол. Имя = "КлючСвязи" Тогда
НС. КлючСвязи = КлючСвязи
ИначеЕсли Кол. Имя = "НомерСтроки" Тогда
Продолжить;
Иначе
НС[Кол. Имя] = Стр[Кол. Имя];
КонецЕсли ;
КонецЦикла ;
Если НЕ Стр. Строки. Количество( ) = 0 Тогда
ДеревоВТаблицу( ДокОбъект, , НаименованиеТабличнойЧастиДокумента, Стр, НС. НомерСтроки) ;
КонецЕсли ;
КонецЦикла ;
КонецПроцедуры
Хочу поделиться с посетителями сайта своим подходом к преобразованию таблицы значений в дерево значений и обратно.
Вообще, при разработке отраслевой задачи, была необходимость почти во всех документах, выводить информацию в виде дерева и хранить ее в табличных частях документа, а также в интерактивной обработке данных в виде дерева.
Отсюда появился небольшой модуль для расширения возможности работы с деревом значений, хотя и с некоторыми оговорками.
Основной идеей является использование двух ключевых реквизитов/колонок КлючСтроки и КлючСвязи.
Однако они не всегда необходимы. Код, на мой взгляд достаточно "высушен".
Код 1C v 8.х
Функция ПолучитьНовыйКлючСтрокиДерева(Дерево, СписокКлючей = Неопределено) Экспорт
Если СписокКлючей = Неопределено Тогда
СписокКлючей = Новый СписокЗначений;
СписокКлючей. Добавить( 0 ) ;
КонецЕсли ;
Для Каждого СтрокаДерева Из Дерево. Строки Цикл
СписокКлючей. Добавить( СтрокаДерева. КлючСтроки) ;
ПолучитьНовыйКлючСтрокиДерева( СтрокаДерева, СписокКлючей) ;
СписокКлючей. СортироватьПоЗначению( НаправлениеСортировки. Убыв) ;
МаксКлюч = СписокКлючей[0 ]. Значение + 1 ;
КонецЦикла ;
Возврат МаксКлюч;
КонецФункции
Процедура ОбновитьКлючиСвязиВДеревеЗначений(Дерево) Экспорт
Для Каждого СтрокаДерева Из Дерево. Строки Цикл
Попытка
СтрокаДерева. КлючСвязи = СтрокаДерева. Родитель. КлючСтроки;
Исключение
СтрокаДерева. КлючСвязи = 0 ;
КонецПопытки ;
ОбновитьКлючиСвязиВДеревеЗначений( СтрокаДерева) ;
КонецЦикла ;
КонецПроцедуры
Процедура ОбновитьКлючиСтрокВДеревеЗначений(Дерево, КлючСтроки = 1) Экспорт
Для Каждого СтрокаДерева Из Дерево. Строки Цикл
СтрокаДерева. КлючСтроки = КлючСтроки;
КлючСтроки = КлючСтроки + 1 ;
ОбновитьКлючиСтрокВДеревеЗначений( СтрокаДерева, КлючСтроки) ;
КонецЦикла ;
КонецПроцедуры
Функция ВыгрузитьДеревоЗначенийВТаблицуЗначений(Дерево, Таблица = Неопределено) Экспорт
Если Таблица = Неопределено Тогда
Таблица = Новый ТаблицаЗначений;
Для Каждого Колонка Из Дерево. Колонки Цикл
Таблица. Колонки. Добавить( Колонка. Имя, Колонка. ТипЗначения) ;
КонецЦикла ;
КонецЕсли ;
Для Каждого СтрокаДерева Из Дерево. Строки Цикл
ЗаполнитьЗначенияСвойств( Таблица. Добавить( ) , СтрокаДерева) ;
ВыгрузитьДеревоЗначенийВТаблицуЗначений( СтрокаДерева, Таблица) ;
КонецЦикла ;
Возврат Таблица;
КонецФункции
Функция ВыгрузитьТаблицуЗначенийВДеревоЗначений(Таблица, КлючСтроки = "КлючСтроки" , КлючСвязи = "КлючСвязи" ) Экспорт
Дерево = Новый ДеревоЗначений;
Для Каждого Колонка Из Таблица. Колонки Цикл
Дерево. Колонки. Добавить( Колонка. Имя, Колонка. ТипЗначения) ;
КонецЦикла ;
Для Каждого СтрокаТаблицы Из Таблица Цикл
СтрокаГруппировки = Дерево. Строки. Найти( СтрокаТаблицы[КлючСвязи], КлючСтроки, Истина ) ;
Если СтрокаГруппировки = Неопределено Тогда
ЗаполнитьЗначенияСвойств( Дерево. Строки. Добавить( ) , СтрокаТаблицы) ;
Иначе
ЗаполнитьЗначенияСвойств( СтрокаГруппировки. Строки. Добавить( ) , СтрокаТаблицы) ;
КонецЕсли ;
КонецЦикла ;
Возврат Дерево;
КонецФункции
Процедура УстановитьЗначениеКолонкиДерева(Дерево, Колонка, Значение) Экспорт
Для каждого СтрокаДерева Из Дерево. Строки Цикл
СтрокаДерева[Колонка] = Значение;
УстановитьЗначениеКолонкиДерева( СтрокаДерева, Колонка, Значение) ;
КонецЦикла ;
КонецПроцедуры
Процедура СкопироватьПодчиненныеСтроки(СтрокаПриемник, СтрокаИсточник)
Для каждого Строка Из СтрокаИсточник. Строки Цикл
НоваяСтрока = СтрокаПриемник. Строки. Добавить( ) ;
НоваяСтрока. КлючСвязи = СтрокаПриемник. КлючСтроки;
ЗаполнитьЗначенияСвойств( НоваяСтрока, Строка) ;
СкопироватьПодчиненныеСтроки( НоваяСтрока, Строка) ;
КонецЦикла ;
КонецПроцедуры
Процедура ПеренестиСтрокиДереваЗначений(СтрокаПриемник, ВыделенныеСтроки) Экспорт
Если НЕ СтрокаПриемник = Неопределено Тогда
МассивСтрок = Новый Массив;
Для Каждого СтрокаПереноса Из ВыделенныеСтроки Цикл
МассивСтрок. Добавить( СтрокаПереноса) ;
НоваяСтрока = СтрокаПриемник. Строки. Добавить( ) ;
СкопироватьПодчиненныеСтроки( НоваяСтрока, СтрокаПереноса) ;
ЗаполнитьЗначенияСвойств( НоваяСтрока, СтрокаПереноса) ;
НоваяСтрока. КлючСвязи = СтрокаПриемник. КлючСтроки;
КонецЦикла ;
Для Каждого СтрокаДерева Из МассивСтрок Цикл
Если СтрокаДерева. Родитель = Неопределено Тогда
СтрокаДерева. Строки. Удалить( СтрокаДерева) ;
Иначе
СтрокаДерева. Родитель. Строки. Удалить( СтрокаДерева) ;
КонецЕсли ;
КонецЦикла ;
КонецЕсли ;
КонецПроцедуры
Александр Синцов (Sintson)