1С 8.3 Дерево значений — Программист 1С Минск. Автоматизация бизнеса.
Дерево Значений в 1С 8.3 — это иерархический динамически набор любого типа. По своим функциям и структуре (колонки и строки) очень схожа с Таблицей Значений, но есть виртуальная колонка «Родитель». Дерево значений рекомендуется использовать для работы именно с иерархической информацией . Каждая строка дерева значений имеет свойства «Родитель» и «Строки», а также может иметь любое количество подчиненных строк. Операции с помощью встроенного функционала (сортировка, раскраска строк, поиск, итоги, различные отборы ) могут производится с учетом подчиненных строк / уровней иерархии.
&НаСервере
Процедура ЗаполнениеРеквизитаФормыДеревоЗначений ()
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// ДеревоЗначений = Новый ДеревоЗначений; — если без реквизита
ДЗ_Корень = ДеревоЗначений . Строки . Добавить ();
ДЗ_Корень . Наименование = «Самый верхний уровень» ;
ДЗ_1уровень = ДЗ_Корень . Строки . Добавить ();
ДЗ_1уровень . Наименование = «1-ая папка (группа)» ;
ЭлементДЗ_1 = ДЗ_1уровень . Строки . Добавить ();
ЭлементДЗ_1 . Наименование = «Первый (вложенный) элемент» ;
ДЗ_2уровень = ДЗ_Корень . Строки . Добавить ();
ДЗ_2уровень . Наименование = «2-ая папка (группа)» ;
ЭлементДЗ_1 = ДЗ_2уровень . Строки . Добавить ();
ЭлементДЗ_1 . Наименование = «Первый (вложенный) элемент» ;
ЭлементДЗ_2 = ДЗ_2уровень . Строки . Добавить ();
ЭлементДЗ_2 . Наименование = «Второй (вложенный) элемент» ;
// Преобразование ДеревоЗначений в реквизит формы (табличное поле)
ЗначениеВРеквизитФормы ( ДеревоЗначений , «ДеревоЗначНаФорме» );
&НаСервере
Процедура ЗаполнениеРеквизитаФормыДеревоЗначенийИзЗапроса ()
Запрос = Новый Запрос ;
Запрос . Текст = «ВЫБРАТЬ
| Материалы.Ссылка КАК Наименование
| Материалы.Родитель КАК Родитель
|ИЗ
| Справочник.Материалы КАК Материалы
|УПОРЯДОЧИТЬ ПО
| Наименование ИЕРАРХИЯ
|ИТОГИ ПО
| Родитель» ;
//Внимание! Если правильно не указать вид обхода результата выборки по запросу,
//то мы получим обычную таблицу значений
ДеревоЗначений = Запрос . Выполнить (). Выгрузить ( ОбходРезультатаЗапроса . ПоГруппировкамСИерархией );
// Заполнение дерева значений из результата запроса
// колонка «Материалы» – это элемент справочника, колонка «Родитель» – это группа
ЗначениеВРеквизитФормы ( ДеревоЗначений , «ДеревоЗначНаФорме» ); // Преобразование в реквизит формы (табличное поле)
&НаСервере
Процедура ПоискСтрокиВДеревеЗначений () // найдём 1-ю строку со значением «Элемент №1» в дереве значений
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// Поиск строки. (если строка не найдена, вернёт «Неопределено»)
НайденнаяСтрокаДЗ = ДеревоЗначений . Строки . Найти ( «Первый (вложенный) элемент» , «Наименование» , Истина);
// Анализ результата поиска
Если НайденнаяСтрокаДЗ = Неопределено Тогда
Сообщить ( «Строка не найдена» );
Иначе // вренёт первую найденную строку
Сообщить ( «Найдена: » + НайденнаяСтрокаДЗ . Наименование + » (» + НайденнаяСтрокаДЗ . Родитель . Наименование + «)» );
КонецЕсли;
&НаСервере
Процедура ПоискВсехСтрокВДеревеЗначений ()
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// Создаем структуру для поиска (условие)
НаименованиеДляПоиска = «Первый (вложенный) элемент» ;
ПараметрыОтбора = Новый Структура ;
ПараметрыОтбора . Вставить ( «Наименование» , НаименованиеДляПоиска );
// Поиск всех строк содержащих наименование «Первый (вложенный) элемент»
МассивСтрок_ДЗ = ДеревоЗначений . Строки . НайтиСтроки ( ПараметрыОтбора , Истина);
// Проверка найдены ли строки
Если МассивСтрок_ДЗ . Количество () = 0 Тогда
Сообщить ( «Ни одной строкис наименованием » + НаименованиеДляПоиска + » не найдено!» );
КонецЕсли;
// Перебор строк
Для Каждого Строка_ДЗ Из МассивСтрок_ДЗ Цикл
Если Строка_ДЗ . Родитель = Неопределено Тогда
Сообщить ( «Корень дерева значений: » + Строка_ДЗ . Наименование );
Иначе
Сообщить ( Строка_ДЗ . Наименование + » — » + Строка_ДЗ . Родитель . Наименование );
КонецЕсли
&НаСервере
Процедура УдалениеСтрокиИзДереваЗначений ()
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// С помощью данных методов возможно удаление конкретных строк
// Важно! При удалении либо очистки строки — все её подчинённые строки удалятся
// 1.Очистка всех строк
ДеревоЗначений . Строки . Очистить ();
// 2. Удаление по конкретному индексу
ДеревоЗначений . Строки . Удалить ( 0 );
// 3.Или удаление по конкретному наименованию
НайтиСтроку = ДеревоЗначений . Строки . Найти ( » Легированная сталь » , «Наименование» );
Если НЕ НайтиСтроку = Неопределено Тогда
ДеревоЗначений . Строки . Удалить ( НайтиСтроку );
КонецЕсли;
ЗначениеВРеквизитФормы ( ДеревоЗначений , «ДеревоЗначНаФорме» ); // Преобразование в реквизит формы (табличное поле)
Источник
Обход дерева значений
Доброго всем. Что-то никак не придумаю красивое решение.
Имеется дерево значений.
Нужно обойти его так, чтобы обработать информацию на самых нижних уровнях, затем на один уровень выше, потом еще на уровень выше и так до конца. Т.е. для приведенного примера нужно:
Обработать строки на третьем уровне: Ст1-1-1, Ст1-1-2 и Ст1-2-1.
Далее обработать все строки второго уровня: Ст1-1, Ст1-2, Ст2-1, Ст2-2 и Ст3-1
И в последнюю очередь все строки первого уровня: Ст1, С2, Ст3
Вот как такую рекурсию написать?
(2) Да ну. А мужики то и не знали.
+(1) А если очень хочется, можно сначала обычным обходом собрать дерево в массив массивов (по уровням), а после уже обработать.
(не вашим и не нашим) Можно запомнить порядок обхода элементов при рекурсии и после, в обратном цикле, — обработать
Функция Обрабошить(СтрокаДерева)
Для каждого Строка из СтрокаДерева.Строки Цикл
Обрабошить(Строка);
Строка.УгаУга = «ЫцЫц»;//вот тут код обработки делай после рекурсивного вызова
(8) Нормально можно рекурсией сделать (если конечно не 100500 строк.
Я бы еще добавил условие окончание рекурсии, что то в этом роде:
Процедура Обрабошить(СтрокаДерева) Если СтрокаДерева.Строки.Количество() = 0 Тогда Возврат; КонецЕсли; .
Но порядок в рекурсии конечно будет не такой как ты хотел, но подчиненные узлы обработаются раньше своих родителей.
(10) Сделать чтобы подчиненные узлы обрабатывались раньше родительских у меня не составляе трудностей.
Я бы тогда сделал массив.
Обошел бы рекурсией и записал в массив
Ссылку на строку и уровень в структуру. Потом в двойном вложенном цикле обошел по номерам уровней. Всё очень просто.
Рекурсий 1 — нижние строки:
Для Каждого Подчиненный Из Подчиненные Цикл
Если Подчиненный.ЭтоГруппа Тогда
Иначе
Если Подчиненный.Строки.Количество() = 0 Тогда
Подчиненный.Заказать = Подчиненный.РекомендуетсяЗаказать;
Подчиненный.СуммаВес = Подчиненный.Заказать * Подчиненный.ВесЕдиница;
КонецЕсли;
КОнецЕсли;
УстановитьАвторасчетЗаказа(Подчиненный,УстановитьРасчет);
КонецЦикла;
Рекурсия 2 — итоги по звеньям дерева на основании более нижних:
Для Каждого Подчиненный Из Подчиненные Цикл
Если Подчиненный.Строки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
Подчиненный.Заказать = Подчиненный.Строки.Итог(«Заказать»);
Подчиненный.РекомендуетсяЗаказать = Подчиненный.Строки.Итог(«РекомендуетсяЗаказать»);
(18) За что? По сабжу ничего. Простой рекурсией не решить. в (7) и (17) обработка узлов от конца к корню, а не по уровням.
(20) Сам разуй, а лучше пройдись отладчиком, обработка дерева в (0) будет след:
Ст1-1-1
Ст1-1-2
Ст1-1
Ст1-2-1
Ст1-2
Ст1
Ст2-1
Ст2-2
С2
Ст3-1
Ст3
А надо:
Ст1-1-1
Ст1-1-2
Ст1-2-1
Ст1-1
Ст1-2
Ст2-1
Ст2-2
Ст3-1
Ст1
Ст2
Ст3
(22) ептить. на какая разница. результат есть.
У автора элементарнейшая задача и не надо ее делать через зад.
(24) в дал две рабочих процедуры. рекурсии
Одна для просчета на нижних строка чо хоч.
Вторая как обратная — как раз для групп дерева делает итоги и расчеты. Причем по всем группам. любых уровней.
например мы что то в дереве посчитали, теперь хотим чтобы итоги были в группах. так как они автоматом в дереве никогда не будут.
а автора таже хрень: он что то там считает по строкам, потом хочет по группам получить итоги этих строк — больше чем 146 процентов.
(0) можно добавить какую-то колонку в дерево, в которую записывать уровень в строках, а потом юзать НайтиСтроки(, Истина), кторая выгребет все подчиненные. ТОлько для этого надо точно знать количество уровней.
Процедура УстановитьРазворотСтрок(ДеревоПодбора, ДеревоПодбораНаФорме, УровеньРазворотаДерева) Экспорт
Для Каждого СтрокаДерева0 Из ДеревоПодбора.Строки Цикл
Если СтрокаДерева0.Уровень() < ЛокальныйУровеньРазворота Тогда
Если НЕ ДеревоПодбораНаФорме.Развернут(СтрокаДерева0) И СтрокаДерева0.Строки.Количество() > 0 Тогда
ДеревоПодбораНаФорме.Развернуть(СтрокаДерева0, Истина);
КонецЕсли;
Иначе
Если ДеревоПодбораНаФорме.Развернут(СтрокаДерева0) И СтрокаДерева0.Строки.Количество() > 0 Тогда
ДеревоПодбораНаФорме.Свернуть(СтрокаДерева0);
КонецЕсли;
КонецЕсли;
УстановитьРазворотСтрок(СтрокаДерева0, ДеревоПодбораНаФорме, УровеньРазворотаДерева)
КонецЦикла;
Источник
Рекурсия в 1С и управление деревом значений
Термин «рекурсия» используется во многих областях знаний. В программировании рекурсия – вызов процедуры (функции) из нее же самой. Статья рассказывает об использовании рекурсии в 1С Предприятии для работы с деревом значений.
Термин «рекурсия» используется во многих областях знаний. В программировании рекурсия – вызов процедуры (функции) из нее же самой. Различают простую и сложную рекурсию. При простой рекурсии некоторая процедура А вызывает сама себя, пока не выполниться заданное условие выхода, или же бесконечно. В случае сложной рекурсии процедура А вызывает процедуру Б, которая опять вызывает процедуру А, и так далее до выполнения условия выхода или бесконечно. В сложной рекурсии может участвовать и больше двух процедур или функций. Организовать рекурсию средствами встроенного языка 1С Предприятия очень легко. Вот пример простой рекурсии: Процедура ПроцедураА ()
ПроцедураА ();
КонецПроцедуры А это сложная рекурсия: Процедура ПроцедураА ()
ПроцедураБ ();
КонецПроцедуры
Процедура ПроцедураБ ()
ПроцедураА ();
КонецПроцедуры Оба фрагмента кода приведены исключительно для примера. При попытке их выполнить возникнет бесконечный цикл и, как результат, произойдет зависание системы, поскольку не задано условие выхода. Создадим рекурсию с условием выхода: Процедура ВывестиЧисла ( пЧисло )
Если пЧисло Сообщить ( Строка ( пЧисло ));
пЧисло = пЧисло + 1 ;
ВывестиЧисла ( пЧисло );
Иначе
Возврат;
КонецЕсли;
КонецПроцедуры
ВывестиЧисла ( 1 ); Этот фрагмент кода выведет в окно служебных сообщений 1С Предприятия числа от 1 до 100. После этого выполниться условие выхода и программа будет завершена. Процедура вызовет сама себя ровно 100 раз. Количество таких вызовов процедуры или функции называется глубиной рекурсии. Реализация рекурсивных вызовов функций и процедур в практически применяемых языках и средах программирования, использует механизм стека вызовов — адрес возврата и локальные переменные функции записываются в стек, благодаря чему каждый следующий рекурсивный вызов этой функции пользуется своим набором локальных переменных и за этот счёт работает корректно. Оборотной стороной этого довольно простого по структуре механизма является то, что рекурсивные вызовы не бесплатны — на каждый рекурсивный вызов требуется некоторое количество оперативной памяти компьютера, и при чрезмерно большой глубине рекурсии может наступить переполнение стека вызовов. Вследствие этого обычно рекомендуется избегать рекурсивных программ, которые приводят к слишком большой глубине рекурсии. Пример с выводом чисел естественно не является оптимальным, он приведен только в целях демонстрации. На практике в этом случае гораздо удобнее использовать цикл. Рекурсию следует использовать там, где с помощью циклов решать задачу нецелесообразно. В 1С Предприятии 8.х рекурсия может быть использована для решения задач управления деревом значений. Например, мы интерактивно изменяем пометку элемента, который находиться на одном из верхних уровней дерева значений. В таком случае пометки должны программно устанавливаться (или сниматься) и для всех подчиненных ему элементов, находящихся на более низких уровнях дерева. Если максимальное количество уровней дерева известно, то эта задача может быть решена следующим образом: Процедура ИзменитьПометкиПодчиненных ( пГлавный )
Подчиненные1 = пГлавный . Строки ;
// Первый уровень подчиненных
Для Каждого Подчиненный1 Из Подчиненные1 Цикл
Подчиненный1 . Пометка = пГлавный . Пометка ;
Подчиненные2 = Подчиненный1 . Строки ;
// Второй уровень подчиненных
Для Каждого Подчиненный2 Из Подчиненные2 Цикл
Подчиненный2 . Пометка = пГлавный . Пометка ;
Подчиненные3 = Подчиненный2 . Строки ;
Источник