helpf.pro
Регистрация
 +8 
Распечатать

1С 8.3 : Дерево значений в таблицу значений или в табличную часть и обратно

Для одной организации надо было реализовать документы, где вместо табличной части надо использовать дерево и все это на управляемых формах. Но дерево нельзя сохранить в базе в текущем виде. Пришлось использовать табличную часть документа для хранения данных дерева. И при открытии формы получать данные из ТЧ и выводить их в дерево. Далее все манипуляции производить с деревом и при сохранении документа помещать данные в обратно в ТЧ.

Поиск по интернету не дал нужного варианта, пришлось реализовавыть свой механизм, используя информацию которая была на просторах интернета.

Для реализации такого механизма в ТЧ был добавлен реквизит “КлючСвязи” (обязательный реквизит) с типом число, куда помещался “НомерСтроки” (стандартный реквизит ТЧ) родителя (верхний уровень). А самый верхний элемент дерева имеет “КлючСвязи” равный 0.

На картинке ниже видно структуру дерева и структуру ТЧ

Нагрузка на сервер осуществляется при окрытии и при сохранении документа. А с деревом работают уже на клиенте.

На рабочей базе обрабатывается около 200 строк в одном документе.

Открытие и сохранение документа происходит моментально. С большем количеством строк не тестировалось.

Чтобы алгорит правильно работал, у рекизита фомы с типом дерево значений должны быть все реквизиты табличной части, кроме “КлючСвязи” и “НомерСтроки”. Иначе платформа выдаст ошибку. В дерево можо добавлять свои реквизиты отличные от ТЧ, они будут использоваться только в дереве.

Ниже приведен код преобразования дерева в таблицу и обратно.

Код 1C v 8.2 УП
 &НаКлиенте
Процедура КомандаТаблицуВДерево(Команда)
КомандаТаблицуВДеревоНаСервере();
КонецПроцедуры


&НаСервере
Процедура КомандаТаблицуВДеревоНаСервере()
Дерево = ТаблицаВДерево(РеквизитФормыВЗначение("Объект"), "Товары");//Товары - имя табличной части
ЗначениеВРеквизитФормы(Дерево, "ДеревоЗначений");//ДеревоЗначений - реквизит формы с типом дерево значений
Элементы.ДеревоЗначений.Обновить();
КонецПроцедуры


&НаКлиенте
Процедура КомандаДеревоВТаблицу(Команда)
КомандаДеревоВТаблицуНаСервере();
КонецПроцедуры


&НаСервере
Процедура КомандаДеревоВТаблицуНаСервере()
Объект.Товары.Очистить();
ДОбъект = РеквизитФормыВЗначение("Объект");
ДеревоВТаблицу(ДОбъект, РеквизитФормыВЗначение("ДеревоЗначений"), "Товары");
ЗначениеВРеквизитФормы(ДОбъект, "Объект");
КонецПроцедуры

Формирование дерева из таблицы значений

Код 1C v 8.2 УП
 //ФОРМИРОВАНИЕ ДЕРЕВА ИЗ ТАБЛИЦЫ
&НаСервере
Функция ТаблицаВДерево(ДокОбъект, НаименованиеТабличнойЧастиДокумента, КлючСвязи = NULL, ЭлементРодитель = NULL) Экспорт
//ПОДГОТОВКА КОЛОНОК ДЕРЕВА
КолонкиТаблицы = ДокОбъект.Метаданные().ТабличныеЧасти[НаименованиеТабличнойЧастиДокумента].Реквизиты;
ДеревоЗначений2 = Новый ДеревоЗначений;
Для каждого Кол из КолонкиТаблицы Цикл
Если Кол.Имя = "НомерСтроки" ИЛИ Кол.Имя = "КлючСвязи" Тогда
Продолжить;
Иначе
ДеревоЗначений2.Колонки.Добавить(Кол.Имя, Новый ОписаниеТипов(Кол.Тип));
КонецЕсли;
КонецЦикла;//ДеревоЗначений.Строки.Очистить();

Если КлючСвязи = NULL И ЭлементРодитель = NULL Тогда
//ПЕРВЫЙ ВЫЗОВ ПРОЦЕДУРЫ (КОРНЕВЫЕ ЭЛЕМЕНТЫ)
ИсточникВыборки = ДеревоЗначений2.Строки;
КлючСвязи = 0; // ЭЛЕМЕНТ ВЕРХНЕГО УРОВНЯ ИМЕЕТ НОМЕР СТРОКИ РОДИТЕЛЯ 0 (ОБЯЗАТЕЛЬНЫЙ РЕКВИЗИТ)
Иначе
//ВНУТРЕННИЙ ВЫЗОВ ПРОЦЕДУРЫ (ПОДЧИНЕННЫЕ ЭЛЕМЕНТЫ)
ИсточникВыборки = ЭлементРодитель.Строки;
КонецЕсли;
Фильтр = Новый Структура("КлючСвязи", КлючСвязи);
М = ДокОбъект[НаименованиеТабличнойЧастиДокумента].НайтиСтроки(Фильтр);
Если М.Количество() = 0 Тогда
Возврат ДеревоЗначений2;
КонецЕсли;
Для каждого Стр из М Цикл
Элемент = ИсточникВыборки.Добавить();
Для каждого Кол из КолонкиТаблицы Цикл
Если Кол.Имя = "НомерСтроки" ИЛИ Кол.Имя = "КлючСвязи" Тогда
Продолжить;
Иначе
Элемент[Кол.Имя] = Стр[Кол.Имя];
КонецЕсли;
КонецЦикла;
ТаблицаВДерево(ДокОбъект, НаименованиеТабличнойЧастиДокумента, Стр.НомерСтроки, Элемент); //ДОБАВЛЕНИЕ ПОДЧИНЁННЫХ ЭЛЕМЕНТОВ В ДЕРЕВО
КонецЦикла;
Возврат ДеревоЗначений2;
КонецФункции

Формирование таблицы из дерева

Код 1C v 8.2 УП
 //ФОРМИРОВАНИЕ ТАБЛИЦЫ ИЗ ДЕРЕВА
&НаСервере
Процедура ДеревоВТаблицу(ДокОбъект, ДеревоЗначений, НаименованиеТабличнойЧастиДокумента, СтрокаДерева = NULL, КлючСвязи = NULL) Экспорт
Если СтрокаДерева = NULL И КлючСвязи = NULL Тогда
//ПЕРВЫЙ ВЫЗОВ ПРОЦЕДУРЫ (КОРНЕВЫЕ ЭЛЕМЕНТЫ)
ПервыйВызов = Истина;
ДокОбъект[НаименованиеТабличнойЧастиДокумента].Очистить();
ИсточникВыборки = ДеревоЗначений.Строки;
КлючСвязи = 0; // ЭЛЕМЕНТ ВЕРХНЕГО УРОВНЯ ИМЕЕТ НОМЕР СТРОКИ РОДИТЕЛЯ 0 (ОБЯЗАТЕЛЬНЫЙ РЕКВИЗИТ)
Иначе
//ВНУТРЕННИЙ ВЫЗОВ ПРОЦЕДУРЫ (ПОДЧИНЕННЫЕ ЭЛЕМЕНТЫ)
ПервыйВызов = Ложь;
ИсточникВыборки = СтрокаДерева.Строки;
КонецЕсли;
Для каждого Стр из ИсточникВыборки Цикл
НС = ДокОбъект[НаименованиеТабличнойЧастиДокумента].Добавить();
Для каждого Кол из ДокОбъект.Метаданные().ТабличныеЧасти[НаименованиеТабличнойЧастиДокумента].Реквизиты Цикл
Если Кол.Имя = "КлючСвязи" Тогда
НС.КлючСвязи = КлючСвязи
ИначеЕсли Кол.Имя = "НомерСтроки" Тогда
Продолжить;
Иначе 
НС[Кол.Имя] = Стр[Кол.Имя];
КонецЕсли;
КонецЦикла;
Если НЕ Стр.Строки.Количество() = 0 Тогда
ДеревоВТаблицу(ДокОбъект,,НаименованиеТабличнойЧастиДокумента, Стр, НС.НомерСтроки);
КонецЕсли;
КонецЦикла;
КонецПроцедуры 
Разместил:   Версии: | 8.2 УП | 8.3 |  Дата:   Прочитано: 76986
 +8 
Распечатать
Возможно, вас также заинтересует
Внутреннее устройство PostgreSQL, в помощь администраторам 1С 1
Понимание архитектуры используемой СУБД очень важно для правильной эксплуатации, но местами переоценено: администратору, DevOps-специалисту или разработчику прикладных систем вовсе необязательно знать подробности внутреннего устройства B-дерева или
ДеревоЗначений в ТекстовыйДокумент 3
// Выводит данные ДереваЗначений в ТекстовыйДокумент, пригодный к рассмотрению в отладчике, окне сообщений и показу. // // Параметры: // рВетка - дерево значений, подлежащее выводу. Может иметь почти любую глубину иерархии, количество и тип ко
Как открыть внешнюю обработку или отчет программно 1С УП? 7
В версии 8.2 и старше: приложение не работает непосредственно с локальными файлами, расположенными на компьютере. Файлы должны находиться на сервере. Поэтому для открытия внешней обработки нужно выполнить следующую последовательность действий:
Как отобразить дерево значений на управляемой форме 0
Создадим новую внешнюю обработку. Добавляем управляемую форму и создаем обработчик ПриСозданииНаСервере(). Никаких реквизитов и элементов “вручную” не добавляем, будем делать это программно. НаСервере Процедура ПриСозданииНаСервере(Отказ, Станда
Как удалить строку или очистить дерево значений 2
Помните, что при при удалении/очистке строки, все подчиненные строки удаляются. Очистить дерево значений: Дерево.Строки.Очистить(); НаСервере Процедура ОчиститьНаСервере() тДерево = РеквизитФормыВЗначение("Дерево"); тДерево.Строки.О
Посмотреть все результаты поиска похожих
Комментарии
vligm
19.11.2023 08:05Комментарий: 5
vligm

Большое спасибо за разработку. Очень помогло!

mag1111
18.08.2022 14:59Комментарий: 4
mag1111

Добрый дел, хочу на кнопку повесить заполнение табличной части и потом преобразовать в дерево.

Подскажите пожалуйста, как правильно оформить реквизиты и табличную часть ?

webresurs
13.08.2019 10:26Комментарий: 3
webresurs

сделал по другому в модуль менеджере добавил

Код 1C v 8.3
 

Функция Печать(МассивОбъектов, ОбъектыПечати) Экспорт
...................
СоотвНумерации = Новый Соответствие;
СоотвНумерации.Вставить(0, 0); //для нулевого уровня будет нулевой счетчик (до начала цикла)
ПрошлыйУровень = 0;//флаг уровня прошлой итерации цикла по выборке
Для Каждого ТекСтрока Из  ДокПечать Цикл
         ОбластьСтрокаОписания = Макет.ПолучитьОбласть("СтрокаОписания");
..............  
Обнуление = ?(ПрошлыйУровень < ТекСтрока.КлючСвязи, Истина, Ложь);//проверка условия сброса счетчика
ОбластьСтрокаОписания.Параметры.НомерСтроки = ГенераторИерархическогоНомера(ТекСтрока.КлючСвязи, СоотвНумерации, Обнуление); //формирование номера
ПрошлыйУровень = ТекСтрока.КлючСвязи;//запись текущего уровня выборки для следующей итерации цикла
..................
КонецФункции





&НаСервере
Функция ГенераторИерархическогоНомера(Уровень, КоллекцияНомеров, Обнуление)
    ТекОктетНомера = КоллекцияНомеров.Получить(Уровень);
    Префикс = "";
    
    //расчет префикса
Для н = 0 По Уровень - 1 Цикл
Если ЗначениеЗаполнено(Строка(КоллекцияНомеров.Получить(н))) Тогда
        Префикс = Префикс + Строка(КоллекцияНомеров.Получить(н)) + ".";
  Иначе
КонецЕсли;
    КонецЦикла;
    //Увеличение тек. номера на единицу или сброс в единицу
    Если Обнуление Тогда
        ТекОктетНомера = 1;
    Иначе
        ТекОктетНомера = КоллекцияНомеров.Получить(Уровень) + 1;
    КонецЕсли;
    КоллекцияНомеров.Удалить(Уровень);
    КоллекцияНомеров.Вставить(Уровень, ТекОктетНомера);
    
    Возврат Префикс + Строка(ТекОктетНомера) + " ";
КонецФункции
webresurs
25.07.2019 11:50Комментарий: 2
webresurs

Подскажите как в "Формирование дерева из таблицы значений" еще получить и записать уровень ?

- надо для печатной формы, иерархической нумерации

kuzyara
06.08.2016 13:39Комментарий: 1
kuzyara
Код 1C v 8.2 УП
  &НаСервере
Процедура ПреобразоватьТЗВДЗ(Дерево, Таблица, ИД=0)
   Отбор = Новый Структура;
   Отбор.Вставить("ИДРодителя", ИД);
   НайденныеСтроки = Таблица.НайтиСтроки(Отбор);
   Для Каждого ТекСтр Из НайденныеСтроки Цикл
      НовСтр = Дерево.Строки.Добавить();
 ЗаполнитьЗначенияСвойств(НовСтр, ТекСтр);
      ПреобразоватьТЗВДЗ(НовСтр, Таблица, ТекСтр["ИДЗаписи"]);
   КонецЦикла;
КонецПроцедуры
Вы не можете отправить комментарий анонимно, пожалуйста войдите или зарегистрируйтесь.