Реквизит формы в значение 1с дерево значений

Содержание:

1.     Что такое Дерево значений в 1С

2.     Как создать дерево значений в 1C 8.3 

1.   Что такое Дерево значений в 1С

Дерево значений в 1С (тип значения «ДеревоЗначений») – это Универсальная коллекция значений в системе 1С, где Элементы упорядочены по Индексу (нумерация начинается с 0). Каждое значение Элемента содержит в себе Коллекцию подчиненных Строк, где у каждой Строки коллекции указывается Родитель – Элемент, находящийся на уровень выше. У корневого Элемента (элемент первого уровня) Родитель отсутствует. Доступ к Элементам осуществляется через Индекс, по номеру которого можно получить доступ к значению Элемента и коллекции подчиненных ему Строк.

Описание из Синтакс-помощника: используется для доступа к свойствам и методам дерева значений 1С в целом. Объект, представляющий собой древовидную структуру, обладает сходной функциональностью с таблицей значений, а также обладает возможностью добавлять подчиненные строки к какой-либо строке дерева.

Внимание! В толстом клиенте (обычное приложение) передача значений данного типа с клиента на сервер и обратно приводит к возникновению исключения.

Доступность: сервер, толстый клиент, внешнее соединение, мобильное приложение (сервер), мобильный автономный сервер.

Сериализуется: данный объект может быть сериализован в/из XDTO. Тип XDTO, соответствующий данному объекту, определяется в пространстве имен {http://v8.1c.ru/8.1/data/core}. Имя типа XDTO: ValueTree.  

2.     Как создать дерево значений в 1C 8.3

Так как Дерево значений в 1С 8.3 является усложненной конструкцией с точки зрения программной реализации, и достаточно ресурсоемкой, её не часто используют в разработках. Однако, она очень удобна для реализации нестандартных задач, в том числе, когда требуется отобразить множество значений с возможностью группировки по Родителю.

Необходимо однозначно разделять Дерево значений как объявленную переменную (через конструктор «Новый ДеревоЗначений») и как Реквизит Формы 1С 8.3 (обратите внимание, что ДЗ нельзя выбрать как тип данных Реквизита Объекта).

Если объявленное (далее – ОП) ДЗ можно читать НаКлиенте, передавать НаСервере для обработки и возвращать обратно, то ДЗ как Реквизит Формы 1С 8.3 (далее – РФ) будет читабельным только НаКлиенте. НаСервере даже при попытке чтения дерево выдаст Исключение, а изменять данные, конечно же, не позволит вообще.

Далее рассмотрим поведение одинаковых действий при условии объявления переменной (в рамках одной процедуры/функции) и условиях добавленного реквизита формы 1С 8.3. Варианты работы с глобальными переменными, экспортными или не экспортными переменными модуля мы рассматривать не будем, так как применение зависит от контекста задачи и Вашей веры в объявление глобальных и внеконтекстных переменных.

У ДЗ как РФ есть свое преимущество: вы можете задать колонки и тип данных в самом РФ и программно обращаться к данным из любой процедуры или функции модуля формы (не забывая о директивах компиляции). Для ДЗ как ОП требуется описать все необходимые колонки (для начинающих это может быть проблематично, если нет четкого представления того, что это за «зверь» такой), а также понимать, что по окончании процедуры/функции кончается и жизненный цикл переменной (конечно, если мы не объявили ее глобальной, но это уже совсем другая история).

Пример описания ДЗ программе 1С Предприятие 8:

Пример описания ДЗ в 1С

Как видно из примера, в ДЗ задаются колонки, где будут размещаться данные, но чтобы добавить это данные, необходимо обратиться к Коллекции Строк: ДеревоДанных.Строки.Добавить(). Таким образом добавляются строки первого уровня, после чего в строку первого уровня добавляем коллекцию строк и так далее. При этом, используя метод Добавить(), Родитель присваивается автоматически, но, конечно, его можно изменить. Так и строится дерево, однако не стоит забывать, что чем больше данных, тем больше потребление ресурсов.

Пример ДЗ как РФ:

ДЗ в программе 1С Предприятие 8

Добавление данных происходит, в сущности, таким же образом, как при описании, но есть программные различия. Опишем основные:

программные различия ОП РФ

*Пример преобразования:

Пример преобразования

** Пример работы «преобразование-запись-преобразование»:

преобразование-запись-преобразование

Развернутое дерево значений по своей сути напоминает Результат запроса с группировками, где чем больше группировок, тем больше совокупное количество строк.

Поэтому если требуется результат запроса (где данные сгруппированы) загрузить в ДЗ, необходимо:

1.     (необязательно) преобразовать из реквизита формы;

2.     загрузить результат;

3.     преобразовать в реквизит формы.

загрузить результат в 1С

При необходимости загрузки данных в ДЗ из табличной части 1С можно воспользоваться несколькими способами:

1. Запись с помощью циклов: тут нужно помнить, что есть строки «корневые», и надо их каким-то образом найти, чтобы правильно построить связь Корень-Подчиненный.

2. Загрузить с помощью Запроса (и здесь есть два варианта):

a.      выгрузить табличную часть 1С во временную переменную, передать ее как параметр, сформировать результат с использованием иерархии и загрузить результат в дерево;

 выгрузить табличную часть 1С

b.     сформировать запрос, в который передаем как параметр ссылку принятого к обработке документа в 1С 8.3, после чего формируем результат с использованием иерархии и загружаем его в дерево.

 сформировать запрос в 1С

*Варианты 2а и 2b кажутся похожими. Однако разница между ними есть. Она заключается в производительности, которая зависит от контекста использования (количество данных, количество пользователей, нагрузка на сервер и другое). С одной стороны, при использовании директивы НаСервере у нас уже есть табличная часть 1С (конечно, на стороне сервера, но она уже загружена), которую мы можем без потерь и других действий передать в Запрос и выполнить его. С другой стороны, обращаясь по ссылке в результате выполнения Запроса, система повторно обратится к БД, но, возможно, сделает это быстрее, чем в первом случае. Этот момент требует исследования уже на конкретной БД.

Для записи данных в табличную часть 1С или Таблицу значений потребуется построить цикл, который будет выполнять запись в Приемник по следующим правилам:

1. обход дерева выполняется от Корня к Подчиненным до последнего уровня вложенности;

2. если у Корня есть Подчиненные элементы, то количество результирующих строк в Таблице высчитывается по формуле: , где n – количество элементов на заданном уровне, m — количество уровней (глубина вложенности дерева);

3. рекомендуется записывать Корень – Подчиненный элемент, в связи с этим требуется запись рекурсивным методом.

Пример рекурсивной записи из ДЗ в Табличную часть Товары:

Пример рекурсивной записи из ДЗ

Для чтения данных все немного проще: читать можно как НаКлиенте, так и НаСервере. Разница только в том, что для директивы НаКлиенте потребуется сначала вызвать метод ПолучитьЭлемент(), чего не требуется для серверной директивы. Внимание! Не забудьте, что чтение в процедуре/функции с директивой НаКлиентеНаСервереБезКонтекста компилируется одновременно на клиенте и на сервере, а это значит, что описав Чтение как для клиента при вызове исполнения из процедуры/функции с директивой сервера, программа выдаст исключение (и наоборот). При необходимости вызова чтения как НаКлиенте, так и НаСервере рекомендуется создавать обработчики с соответствующими директивами.

Кроме всего прочего, ДЗ можно использовать в особо изощренном способе работы. Допустим, поставили задачу, что необходимо иметь на форме две таблицы, таблица слева – дерево, в котором есть все уровни, кроме последнего; справа – таблица, в которой отображаются данные последнего уровня вложенности. Таким образом активация строки в Дереве приведет к отображению всех подчиненных элементов.

Реализованный пример такой задачи:

Реализованный пример ДЗ

*Естественно, текущие данные тестовые. Задачей предполагалось, что корневых уровней может быть до 15, второй уровень – примерно так же, а вот на последнем уровне может быть до 50 строк. В такой компоновке удобно видеть все элементы нижнего уровня, переключаясь между Родителями.

Использование Дерева значений — это достаточно нетривиальный и филигранный способ, который имеет свои плюсы (особенно когда группы товаров можно сворачивать). Использовать его для больших таблиц (где более 100 строк) можно, но важно исследовать производительность в каждом конкретном случае.

Специалист компании ООО «Кодерлайн»

Каплин Иван Александрович

Как заполнить Реквизит УФ Дерево значений.

Я
   simol

01.09.12 — 19:33

В процедура модуля формы обработки на сервере сформировал необходимое дерево значений.

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

Команда

   ДеревоЗначений = Новый ДеревоЗначений;

   ЭтаФорма.ЗначениеВРеквизитФормы(ДеревоЗначений, «ДеревоЗадач»);

не проходит

Недопустимое значение параметра (параметр номер ‘2’)

Как его «погладить», чтобы заработало?

  

Партнерская программа EFSOL Oblako

   Wobland

1 — 01.09.12 — 19:34

а есть такой реквизит у формы?

   simol

2 — 01.09.12 — 19:36

(1) Да есть

http://screencast.com/t/IIZ0Ak4K

После ввода кавычек в ЭтаФорма.ЗначениеВРеквизитФормы(ДеревоЗначений, »

автоподбор срабатывает.

   Wobland

3 — 01.09.12 — 19:39

у меня вот целиком объект передавался. наверное, потому, что проблемы были с отдельным реквизитом. сдаюсь

&НаСервере

Процедура СлучайноЗаполнить()

   док=РеквизитФормыВЗначение(«Объект»);

   СерверныйМодуль.ЗаполнитьСлучайно(док);

   ЗначениеВРеквизитФормы(док, «Объект»);

КонецПроцедуры

   simol

4 — 01.09.12 — 19:42

(3)Какая-то особенность дерева я думаю

   Wobland

5 — 01.09.12 — 19:49

Доступность:

Сервер, толстый клиент, внешнее соединение.

Внимание! В толстом клиенте (обычное приложение) передача значений данного типа с клиента на сервер и обратно приводит к возникновению исключения.

   simol

6 — 01.09.12 — 19:50

(5)Я на сервере

   simol

7 — 01.09.12 — 19:53

(0)Непосредственное заполнение через ПолучитьЭлементы() вместо «.Строки» получилось, то хотел бы сначала Дерево подготовить, а потом его загрузить в реквизит формы.

   Wobland

8 — 01.09.12 — 19:54

(4) со строкой то же самое

ЗначениеВРеквизитФормы(стр, «Реквизит1»)

   Wobland

9 — 01.09.12 — 19:57

УТ11:

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

   Дерево = ЗначениеИзФайла(ИмяВременногоФайла);



   ЗначениеВРеквизитФормы(Дерево, «ДеревоКлассификатора»);

КонецПроцедуры

   simol

10 — 01.09.12 — 19:57

(9)Щас поищу УТ11 и гляну

   simol

11 — 01.09.12 — 20:03

Нашел в «Библиотеке электронных документов» код

   ЗначениеВРеквизитФормы(ДеревоПомеченных, «СписокПомеченныхНаУдаление»);

где ДеревоПомеченных — дерево значений, а СписокПомеченныхНаУдаление — реквизит формы дерево значений

играю в найди 10 отличий

   Wobland

12 — 01.09.12 — 20:03

оттуда же. задача исполнителя, форма задачи по предмету

&НаСервере

Процедура ЗаполнитьДеревоЗадач()

   
   Дерево = РеквизитФормыВЗначение(«ДеревоЗадач»);

   Дерево.Строки.Очистить();

   
   ДобавитьЗадачиПоПредмету(Дерево, Параметры.ЗначениеОтбора);

   
   ЗначениеВРеквизитФормы(Дерево, «ДеревоЗадач»);

   
КонецПроцедуры

   Wobland

13 — 01.09.12 — 20:03

(11) я нашёл. у тебя Новый Дерево

   simol

14 — 01.09.12 — 20:04

(13)Да, тоже это понял, спасибо

   Wobland

15 — 01.09.12 — 20:04

(13) хотя, вон в (9) тоже на месте создавалось…

   Wobland

16 — 01.09.12 — 20:04

(14) что спасибо? понял что-то? я ни черта ;)

   simol

17 — 01.09.12 — 20:06

Вместо

ДеревоЗначений = Новый ДеревоЗначений;

Сейчас проверю

ДеревоЗначений = РеквизитФормыВЗначение(«ДеревоЗадач»);

   Wobland

18 — 01.09.12 — 20:06

(17) если поймёшь, расскажешь, как работает (9)?

   simol

19 — 01.09.12 — 20:27

(18) попробовал (17) Так работает, секрет (9) неясен, может там предварительно сохраняли пустое дерево для ускорения работы.

   Wobland

20 — 01.09.12 — 20:29

(19)    ИмяВременногоФайла = ПолучитьИмяВременногоФайла();

   Макет = Справочники.ЕдиницыИзмерения.ПолучитьМакет(«КлассификаторЕдиницИзмерения»);

   Макет.Записать(ИмяВременногоФайла);

   Дерево = ЗначениеИзФайла(ИмяВременногоФайла);

Макет — двоичные данные. верю, что из них получается дерево. как и в случае с Новый Дерево ;)

   simol

21 — 01.09.12 — 20:30

(20)в УФ много странного,вроде уже нравится и на те, очередная непонятка….

(0) Чтобы подобное сработало, нужно чтобы структура (колонок и типов) у дерева на форме и загружаемого дерева совпадала 1 в 1

Дерево Значений в 1С 8.3 — это иерархический динамически набор любого типа. По своим функциям и структуре (колонки и строки) очень схожа с Таблицей Значений, но есть виртуальная колонка «Родитель». Дерево значений рекомендуется использовать для работы именно с иерархической информацией. Каждая строка дерева значений имеет свойства «Родитель» и «Строки», а также может иметь любое количество подчиненных строк. Операции с помощью встроенного функционала (сортировка, раскраска строк, поиск, итоги, различные отборы) могут производится с учетом подчиненных строк / уровней иерархии.

Оглавление:

Заполнение реквизита формы Дерева Значений в 1С 8.3:

&НаСервере
Процедура ЗаполнениеРеквизитаФормыДеревоЗначений()// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
   
ДеревоЗначений = РеквизитФормыВЗначение(«ДеревоЗначНаФорме»);
   
// ДеревоЗначений = Новый ДеревоЗначений; — если без реквизитаДЗ_Корень = ДеревоЗначений.Строки.Добавить();
   
ДЗ_Корень.Наименование = «Самый верхний уровень»;ДЗ_1уровень = ДЗ_Корень.Строки.Добавить();
   
ДЗ_1уровень.Наименование = «1-ая папка (группа)»;ЭлементДЗ_1 = ДЗ_1уровень.Строки.Добавить();
   
ЭлементДЗ_1.Наименование = «Первый (вложенный) элемент»;ДЗ_2уровень = ДЗ_Корень.Строки.Добавить();
   
ДЗ_2уровень.Наименование = «2-ая папка (группа)»;ЭлементДЗ_1 = ДЗ_2уровень.Строки.Добавить();
   
ЭлементДЗ_1.Наименование = «Первый (вложенный) элемент»;ЭлементДЗ_2 = ДЗ_2уровень.Строки.Добавить();
   
ЭлементДЗ_2.Наименование = «Второй (вложенный) элемент»;// Преобразование ДеревоЗначений в реквизит формы (табличное поле)
   
ЗначениеВРеквизитФормы(ДеревоЗначений,«ДеревоЗначНаФорме»);

КонецПроцедуры

Заполнение реквизита формы Дерева Значений из Запроса в 1С 8.3:

&НаСервере
Процедура ЗаполнениеРеквизитаФормыДеревоЗначенийИзЗапроса()Запрос = Новый Запрос;
   
Запрос.Текст «ВЫБРАТЬ
    |  Материалы.Ссылка КАК Наименование
    |  Материалы.Родитель КАК Родитель
    |ИЗ
    |  Справочник.Материалы КАК Материалы
    |УПОРЯДОЧИТЬ ПО
    |  Наименование ИЕРАРХИЯ
    |ИТОГИ ПО
    |  Родитель»
;//Внимание! Если правильно не указать вид обхода результата выборки по запросу,
    //то мы получим обычную таблицу значений
   
ДеревоЗначений = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);// Заполнение дерева значений из результата запроса
    // колонка «Материалы» – это элемент справочника, колонка «Родитель» – это группа
   
ЗначениеВРеквизитФормы(ДеревоЗначений, «ДеревоЗначНаФорме»); // Преобразование в реквизит формы (табличное поле)КонецПроцедуры

Поиск строки в Дереве Значений в 1С 8.3:

&НаСервере
Процедура ПоискСтрокиВДеревеЗначений() // найдём 1-ю строку со значением «Элемент №1» в дереве значений

    // Преобразование реквизита формы в объект прикладного типа ДеревоЗначений

ДеревоЗначений = РеквизитФормыВЗначение(«ДеревоЗначНаФорме»);// Поиск строки… (если строка не найдена, вернёт «Неопределено»)
   
НайденнаяСтрокаДЗ = ДеревоЗначений.Строки.Найти(«Первый (вложенный) элемент», «Наименование», Истина);// Анализ результата поиска
   
Если НайденнаяСтрокаДЗ = Неопределено Тогда
       
Сообщить(«Строка не найдена»);
    Иначе
// вренёт первую найденную строку
       
Сообщить(«Найдена: «+НайденнаяСтрокаДЗ.Наименование + » (» + НайденнаяСтрокаДЗ.Родитель.Наименование + «)»);
    КонецЕсли;

КонецПроцедуры

Поиск всех строк в Дереве Значений в 1С 8.3:

&НаСервере
Процедура ПоискВсехСтрокВДеревеЗначений()// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
   
ДеревоЗначений = РеквизитФормыВЗначение(«ДеревоЗначНаФорме»);// Создаем структуру для поиска (условие)
   
НаименованиеДляПоиска = «Первый (вложенный) элемент»;
   
ПараметрыОтбора = Новый Структура;
   
ПараметрыОтбора.Вставить(«Наименование», НаименованиеДляПоиска);// Поиск всех строк содержащих наименование «Первый (вложенный) элемент»
   
МассивСтрок_ДЗ = ДеревоЗначений.Строки.НайтиСтроки(ПараметрыОтбора, Истина);// Проверка найдены ли строки
   
Если МассивСтрок_ДЗ.Количество() = 0 Тогда
       
Сообщить(«Ни одной строкис наименованием «+НаименованиеДляПоиска+» не найдено!»);
    КонецЕсли;
// Перебор строк
   
Для Каждого Строка_ДЗ Из МассивСтрок_ДЗ Цикл

        Если

Строка_ДЗ.Родитель = Неопределено Тогда
           
Сообщить(«Корень дерева значений: «+Строка_ДЗ.Наименование);
        Иначе
           
Сообщить(Строка_ДЗ.Наименование + » — » + Строка_ДЗ.Родитель.Наименование);
        КонецЕсли

    КонецЦикла;

КонецПроцедуры

Удаление строки из Дерева Значений в 1С 8.3:

&НаСервере
Процедура УдалениеСтрокиИзДереваЗначений()// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
   
ДеревоЗначений = РеквизитФормыВЗначение(«ДеревоЗначНаФорме»);
   
// С помощью данных методов возможно удаление конкретных строк
    // Важно! При удалении либо очистки строки — все её подчинённые строки удалятся

    // 1.Очистка всех строк

ДеревоЗначений.Строки.Очистить();// 2. Удаление по конкретному индексу
   
ДеревоЗначений.Строки.Удалить(0);// 3.Или удаление по конкретному наименованию
   
НайтиСтроку = ДеревоЗначений.Строки.Найти(«Легированная сталь«, «Наименование»);
    Если НЕ
НайтиСтроку = Неопределено Тогда
       
ДеревоЗначений.Строки.Удалить(НайтиСтроку);
    КонецЕсли;
ЗначениеВРеквизитФормы(ДеревоЗначений, «ДеревоЗначНаФорме»); // Преобразование в реквизит формы (табличное поле)КонецПроцедуры

Обход Дерева Значений (с помощью рекурсии) в 1С 8.3:

&НаСервере
Процедура ОбойтиДЗ_НаСервере()// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
   
ДеревоЗначений = РеквизитФормыВЗначение(«ДеревоЗначНаФорме»);
   
ОбходДЗ_Рекурсия(ДеревоЗначений);

КонецПроцедуры

&НаСервере
Процедура ОбходДЗ_Рекурсия(перДеревоЗначений)

    Для Каждого

Строка_Рек Из перДеревоЗначений.Строки Цикл

        Если

Строка_Рек.Строки.Количество()>0 Тогда
           
ОбходДЗ_Рекурсия(Строка_Рек);
        КонецЕсли;

    КонецЦикла;

КонецПроцедуры

Свертка всего Дерева Значений (на форме) в 1С 8.3:

&НаКлиенте
Процедура СверткаВсегоДереваЗначенийНаФорме()// ДеревоЗначНаФорме — на форме
   
КоллекцияЭлементовДерева=ДеревоЗначНаФорме.ПолучитьЭлементы();
   
//Свернуть дерево
   
Для Каждого СтрокаКоллекции Из КоллекцияЭлементовДерева Цикл
       
ИдСтроки=СтрокаКоллекции.ПолучитьИдентификатор();
       
Элементы.ДеревоЗначНаФорме.Свернуть(ИдСтроки); // Сворачиваем каждую строку тут
   
КонецЦикла;

КонецПроцедуры

Разворот всего Дерева Значений (на форме) в 1С 8.3:

&НаКлиенте
Процедура РазворотВсегоДереваЗначенийНаФорме()// ДеревоЗначНаФорме — на форме
   
КоллекцияЭлементовДерева=ДеревоЗначНаФорме.ПолучитьЭлементы();
   
//Развернуть дерево
   
Для Каждого СтрокаКоллекции Из КоллекцияЭлементовДерева Цикл
       
ИдСтроки=СтрокаКоллекции.ПолучитьИдентификатор();
       
Элементы.ДеревоЗначНаФорме.Развернуть(ИдСтроки);// Разворачиваем каждую строку тут
   
КонецЦикла;

КонецПроцедуры

Разворот текущей строки Дерева Значений (на форме) в 1С 8.3:

&НаКлиенте
Процедура РазворотТекСтрокиДереваЗначенийНаФорме() // Разворот текущей строки в дереве:СтрокаДЗ = Элементы.ДеревоЗначНаФорме.ТекущаяСтрока;
   
Элементы.ДеревоЗначНаФорме.Развернуть(СтрокаДЗ, Истина);// Определим, развернут ли узел дерева в указанной строке.
   
УзелРазвернут = Элементы.ДеревоЗначНаФорме.Развернут(СтрокаДЗ);
    Если
УзелРазвернут Тогда // Если узел Развернут, то Свернуть
       
Элементы.ДеревоЗначНаФорме.Свернуть(СтрокаДЗ);
    КонецЕсли;

КонецПроцедуры

Свернуть все выделенные строки Дерева Значений (на форме) в 1С 8.3:

&НаКлиенте
Процедура СвернутьВсеВыделенныеСтрокиДереваЗначенийНаФорме()

    Для Каждого

СтрокаДЗ Из Элементы.ДеревоЗначНаФорме.ВыделенныеСтроки Цикл
       
Элементы.ДеревоЗначНаФорме.Свернуть(СтрокаДЗ);
    КонецЦикла;

КонецПроцедуры

💡 Шаблоны (готовые модели) кода 1С 8.3 с тегом #ДеревоЗначений:

📰 Актуальные новости с тегом #ДеревоЗначений:

  • В версии 8.3.22 анонсирован дополнительный контроль заполнения значений в УФ. Проверка заполненности колонок дерева и таблицы значений

Copyright©, «Программист 1С в г.Минске», 14.10.2020

Перепечатка текста и фотографий разрешена при наличии прямой ссылки на источник

  • Главная
  • О сайте
  • Главная
  • Содержание

Рукопашный бой Карташ

Категории

—>

рубрики: Работа с формами | Дата: 12 ноября, 2016
Скачать обработку с примерами из статьи: professia1c_TreeValue.epf
Платформа: 8.3; Тип формы: управляемая.

В этой статье рассмотрим как можно выгружать результат запроса в
дерево значений на форме. Разберем этот вопрос как для обычных,
так и для управляемых форм.
В некоторм роде эта статья пересекается со статьей про
иерархический обход результата запроса
Поэтому и пример возьмем такой же. То есть когда нам надо сделать запрос к таблице:

Период Склад Товар Цена
01.01.2016 Центральный Ручка 30
01.01.2016 Офис Карандаш 15
05.01.2016 Центральный Ручка 45
10.01.2016 Офис Карандаш 25
15.01.2016 Центральный Степлер 150
17.01.2016 Офис Дырокол 200

и разместить результат на форме в виде дерева значений вот в таком виде:

Центральный
Ручка
01.01.2016 30
05.01.2016 45
Степлер
15.01.2016 150
Офис
Карандаш
01.01.2016 15
10.01.2016 25
Дырокол
17.01.2016 200

А теперь рассмотрим как это можно сделать на управляемых и на обычных формах.

Управляемые формы

Для демонстрации создадим внешнюю обработку. Добавим форму. В реквизитах формы
создаем реквизит с типом ДеревоЗначений. Уже в этот реквизит добавляем
колонки реквизита (имена должны совпадать с именами полей в запросе).
Перетаскиваем наше дерево значений на форму. Ну и конечно добавим команду, которая
будет запускать заполнение дерева.

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



&НаСервере
Процедура ЗаполнитьДеревоНаСервере()

    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |	ДАТАВРЕМЯ(2016, 1, 1) КАК Период,
    |	""Центральный"" КАК Склад,
    |	""Ручка"" КАК Товар,
    |	30 КАК Цена
    |ПОМЕСТИТЬ ВТ_Цена
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |..............................
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |	ВТ_Цена.Период КАК Период,
    |	ВТ_Цена.Склад КАК Склад,
    |	ВТ_Цена.Товар КАК Товар,
    |	ВТ_Цена.Цена КАК Цена
    |ИЗ
    |	ВТ_Цена КАК ВТ_Цена
    |ИТОГИ ПО
    |	Склад,
    |	Товар";

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

&НаКлиенте
Процедура ЗаполнитьДерево(Команда)
    ЗаполнитьДеревоНаСервере();
КонецПроцедуры

Здесь стоит обратить внимание на два момента. Первое — это то, что имена полей
запроса и полей дерева значений должны совпадать.
И второе — это метод
ЗначениеВРеквизитФормы(), который помещает сформированное дерево
значений в реквизит формы.
После выполнения кода в форме получаем вот такое дерево значений:

Обычные формы

Создадим тестовую обработку и добавим реквизит с типом ДеревоЗначений.

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

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



Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |	...............................
    |	........";

    Результат = Запрос.Выполнить();
    ДеревоНоменклатуры = Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

    ЭлементыФормы.фДеревоНоменклатуры.СоздатьКолонки();

КонецПроцедуры

Для тех кто первый раз сталкивается с такой задачей основная трудность — это
догадаться о необходимости применения метода СоздатьКолонки()
к табличному полю формы, т.к. без него поле остается пустым.
Запускаем выполнение обработки и получаем следующую картину

Так как работа с ДеревомЗначений и ТаблицейЗначений в данном контексте практически не отличается, в примере будет использоваться ДеревоЗначений, все тоже самое за исключением иерархии применимо и к ТаблицеЗначений. Как известно, в платформе 1С 8.1 не составляло никакого труда связать дерево значений с табличным полем на форме, единственное что при этом нужно было не забыть так это СоздатьКолонки(). В управляемом приложении 1С 8.2 сделать это не так просто как кажется на первый взгляд.
Обращаю внимание, что ДеревоЗначений доступно только на сервере, в толстом клиенте и внешнем соединение. В данных самой управляемой формы для моделирования дерева используется тип ДанныеФормыДерево. Для преобразования ДеревоЗначений <-> ДанныеФормыДерево используются методы управляемой формы ЗначениеВРеквизитФормы() и РеквизитФормыВЗначение(). Для непосредственного отображения дерева используется элемент формы типа ТаблицаФормы связанный через реквизит ПутьКДанным с реквизитом формы типа ДанныеФормыДерево. Если Вам не очень понятна вышеописанная связь объектов, не огорчайтесь, ниже рассмотрим практический пример и все встанет на свои места.

Задача: Имеется дерево значений, необходимо отобразить его на управляемой форме.
Создаем новую внешнюю обработку ( Скачивать файлы может только зарегистрированный пользователь! ), добавляем управляемую форму и создаем обработчик ПриСозданииНаСервере(). Никаких реквизитов и элементов “вручную” не добавляем, будем делать это программно.

Код 1C v 8.2 УП

 &НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

// Создание и заполнение "обычного" объекта прикладного типа ДеревоЗначений,
// который будет отображен на управляемой форме
ДеревоОбъект = Новый ДеревоЗначений;
ДеревоОбъект.Колонки.Добавить("Узел", Новый ОписаниеТипов("Строка"));
Для к1 = 1 По 3 Цикл
СтрокаУ1 = ДеревоОбъект.Строки.Добавить();
СтрокаУ1.Узел = "Узел"+к1;
Для к2 = 1 По 3 Цикл
СтрокаУ2 = СтрокаУ1.Строки.Добавить();
СтрокаУ2.Узел = СтрокаУ1.Узел+к2;
Для к3 = 1 По 3 Цикл
СтрокаУ3 = СтрокаУ2.Строки.Добавить();
СтрокаУ3.Узел = СтрокаУ2.Узел+к3;
КонецЦикла;
КонецЦикла;
КонецЦикла;

// Создание Реквизита формы типа ДанныеФормыДерево
МассивДобавляемыхРеквизитов = Новый Массив;
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Дерево",
Новый ОписаниеТипов("ДеревоЗначений")));
Для Каждого Колонка Из ДеревоОбъект.Колонки Цикл
МассивДобавляемыхРеквизитов.Добавить(
Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, "Дерево"));
КонецЦикла;
ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);

// Преобразование объекта прикладного типа ДеревоЗначений
// в реквизит управляемой формы (данные формы)
ЗначениеВРеквизитФормы(ДеревоОбъект, "Дерево");

// Создание элемента формы типа ТаблицаФормы для отображения дерева
ЭлементДерево = Элементы.Добавить("Дерево", Тип("ТаблицаФормы"));
ЭлементДерево.ПутьКДанным = "Дерево";
ЭлементДерево.Отображение = ОтображениеТаблицы.Дерево;

Для Каждого Колонка Из ДеревоОбъект.Колонки Цикл
НовыйЭлемент = Элементы.Добавить(Колонка.Имя, Тип("ПолеФормы"),
ЭлементДерево);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ПутьКДанным = "Дерево." + Колонка.Имя;
КонецЦикла;

КонецПроцедуры

Механизм Drag and D_rop (или проще говоря “Перетаскивания”) для ДереваЗначений расположенного на управляемой форме управляемого приложения
Основная сложность реализации механизма перетаскивания заключается в том, что у строки ДереваЗначений платформа не позволяет просто изменить родителя, т.е. переподчинить строку. Единственный способ это сделать – создать новую строку вместе со всеми подчиненными строками, т.е. полностью скопировать всю ветку дерева вместе со всей иерархией и подчинить ее требуемой строке-родителю, после чего удалить исходную ветку. Данная задача распадается на две подзадачи:
1). Перед перетаскиванием необходимо проверить корректность данной операции, узел дерева нельзя переносить в узлы подчиненные ему самому, т.е. родительский узел нельзя переносить в дочерние, т.к. это приведет к “бесконечной рекурсии” и “падению” платформы. Это реализуется с помощью обработчика события ЭлементДеревоПроверкаПеретаскивания(…)
2). Если перетаскивание возможно, то при помощи обработчика ЭлементДеревоПеретаскивание(…) запускается рекурсивная функция, которая создает новую ветку дерева, подчиненную требуемому родителю, а исходную удаляет.
Обращаю особое внимание на то, что в платформе 8.2 реализован механизм множественного выбора элементов, поэтому вышеуказанные операции необходимо произвести для всех выбранных пользователем элементов. ( Скачивать файлы может только зарегистрированный пользователь! )

Код 1C v 8.2 УП

 &НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

// Создание и заполнение "обычного" объекта прикладного типа ДеревоЗначений,
// который будет отображен на управляемой форме

// Здесь необходимо расположить код из предыдущей статьи
// «Работа с деревом значений и таблицей значений. Часть I (Основы)»
// .....................................................

// Добавим обработчики и установим свойства
ЭлементДерево.МножественныйВыбор=Истина;
ЭлементДерево.РазрешитьПеретаскивание=Истина;
ЭлементДерево.РазрешитьНачалоПеретаскивания=Истина;
ЭлементДерево.УстановитьДействие("ПроверкаПеретаскивания",
"ЭлементДеревоПроверкаПеретаскивания");
ЭлементДерево.УстановитьДействие("Перетаскивание",
"ЭлементДеревоПеретаскивание");

КонецПроцедуры

&НаКлиенте
Функция ПроверитьВозможностьПереноса(ПереносимыйЭлемент, Знач НовыйРодитель)

Пока НЕ НовыйРодитель = Неопределено Цикл
Если ПереносимыйЭлемент = НовыйРодитель Тогда
Возврат Ложь;
КонецЕсли;
НовыйРодитель = НовыйРодитель.ПолучитьРодителя();
КонецЦикла;

Возврат Истина;

КонецФункции

&НаКлиенте
Функция СкопироватьСтрокуДерева(РеквизитДерево, Приемник, Источник)

Перем НоваяСтрока, ОбратныйИндекс, КолПодчиненныхСтрок;

// Источник может быть уже перенесен
// Это происходит если выделены несколько элементов
// одной и той же ветви дерева на разных уровнях иерархии
Если Источник = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;

Если Приемник = Неопределено Тогда
// Добавляем в корень
НоваяСтрока = РеквизитДерево.ПолучитьЭлементы().Добавить();
Иначе
НоваяСтрока = Приемник.ПолучитьЭлементы().Добавить();
КонецЕсли;

ЗаполнитьЗначенияСвойств(НоваяСтрока, Источник);

КолПодчиненныхСтрок = Источник.ПолучитьЭлементы().Количество();
Для ОбратныйИндекс = 1 По КолПодчиненныхСтрок Цикл
ПодчиненнаяСтрока = Источник.ПолучитьЭлементы()
[КолПодчиненныхСтрок - ОбратныйИндекс];
СкопироватьСтрокуДерева(РеквизитДерево, НоваяСтрока, ПодчиненнаяСтрока);
КонецЦикла;

Если Источник.ПолучитьРодителя() = Неопределено Тогда
РеквизитДерево.ПолучитьЭлементы().Удалить(Источник);
Иначе
Источник.ПолучитьРодителя().ПолучитьЭлементы().Удалить(Источник);
КонецЕсли;

Возврат НоваяСтрока;

КонецФункции

&НаКлиенте
Процедура ЭлементДеревоПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания,
СтандартнаяОбработка, Строка, Поле)

// Узел нельзя переносить в узлы подчиненные ему самому
// т.е. родительский узел нельзя переносить в дочерние.
// Проверим это условие для всех выделенных элементов

СтандартнаяОбработка = Ложь;

РеквизитДерево = ЭтаФорма["Дерево"];

ИДНовыйРодитель = Строка;
// Если НовыйРодитель = Неопределено => Корень дерева
НовыйРодитель = ?(ИДНовыйРодитель = Неопределено, Неопределено,
РеквизитДерево.НайтиПоИдентификатору(ИДНовыйРодитель));

МассивИДПереносимыхЭлементов = ПараметрыПеретаскивания.Значение;

Для каждого ИДПереносимыйЭлемент из МассивИДПереносимыхЭлементов Цикл

ПереносимыйЭлемент = РеквизитДерево.НайтиПоИдентификатору(
ИДПереносимыйЭлемент);

Если НЕ ПроверитьВозможностьПереноса(ПереносимыйЭлемент,
НовыйРодитель) Тогда
ПараметрыПеретаскивания.Действие=ДействиеПеретаскивания.Отмена;
Прервать;
КонецЕсли;
КонецЦикла;

КонецПроцедуры

&НаКлиенте
Процедура ЭлементДеревоПеретаскивание(Элемент, ПараметрыПеретаскивания,
СтандартнаяОбработка, Строка, Поле)

СтандартнаяОбработка=Ложь;

РеквизитДерево = ЭтаФорма["Дерево"];

ИДПриемник = Строка;
// Если ИДПриемник = Неопределено => Корень дерева
Приемник = ?(ИДПриемник = Неопределено, Неопределено,
РеквизитДерево.НайтиПоИдентификатору(ИДПриемник));

МассивИДИсточник = ПараметрыПеретаскивания.Значение;

Для Каждого ИДИсточник Из МассивИДИсточник Цикл
Источник = РеквизитДерево.НайтиПоИдентификатору(ИДИсточник);
НоваяСтрока = СкопироватьСтрокуДерева(РеквизитДерево, Приемник, Источник);
// Производится копирование в корень
// Для "красоты" развернем вновь созданную ветвь
Если Приемник = Неопределено и НоваяСтрока<>Неопределено Тогда
Элементы["Дерево"].Развернуть(НоваяСтрока.ПолучитьИдентификатор(),
Истина);
КонецЕсли;
КонецЦикла;

// Для "красоты" развернем ветвь-родителя
Если НЕ Приемник = Неопределено Тогда
Элементы["Дерево"].Развернуть(ИДПриемник, Истина);
КонецЕсли;

КонецПроцедуры

Реализовать трехпозиционный флажок в ДеревеЗначений на управляемой форме
который работает по следующему алгоритму:
* Если у элемента ДереваЗначений нет подчиненных элементов, то флажок может быть либо “включен”, либо “выключен”.
* Если у элемента есть подчиненные, то флажок “включен”, если ВКЛЮЧЕНЫ флажки у ВСЕХ подчиненных элементов, “выключен” если ВЫКЛЮЧЕНЫ флажки у ВСЕХ подчиненных элементов.
Если у некоторых подчиненных элементов флажки включены, а у некоторых выключены, то флажок родительского элемента имеет значение “неопределенно”.
* При включении флажка у родительского элемента, включаются флажки ВСЕХ подчиненных, при выключении флажка у родительского элемента, выключаются флажки ВСЕХ подчиненных.
Возьмем из первой статьи процедуру построения дерева значений и доработаем ее, добавив в дерево еще одну колонку, которая будет содержать элемент управления флажок и реализуем для него обработчик события “ПриИзменении”. Весь алгоритм сводится к обработке изменения флажка: у всех подчиненных элементов необходимо включить/выключить флажки в зависимости от состояния флажка текущего элемента, а у всех родителей текущего элемента (которые расположены на верхних уровнях иерархии) проставить флажки в состояния “включен”/”выключен”/”неопределенно” в соответствии с вышеописанным алгоритмом. ( Скачивать файлы может только зарегистрированный пользователь! )

Код 1C v 8.2 УП

 &НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

// Создание и заполнение "обычного" объекта прикладного типа ДеревоЗначений,
// который будет отображен на управляемой форме
ДеревоОбъект = Новый ДеревоЗначений;
ДеревоОбъект.Колонки.Добавить("Узел", Новый ОписаниеТипов("Строка"));
ДеревоОбъект.Колонки.Добавить("Пометка", Новый ОписаниеТипов("Число"));
Для к1 = 1 По 3 Цикл
СтрокаУ1 = ДеревоОбъект.Строки.Добавить();
СтрокаУ1.Узел = "Узел"+к1;
Для к2 = 1 По 3 Цикл
СтрокаУ2 = СтрокаУ1.Строки.Добавить();
СтрокаУ2.Узел = СтрокаУ1.Узел+к2;
Для к3 = 1 По 3 Цикл
СтрокаУ3 = СтрокаУ2.Строки.Добавить();
СтрокаУ3.Узел = СтрокаУ2.Узел+к3;
КонецЦикла;
КонецЦикла;
КонецЦикла;

// Создание Реквизита формы типа ДанныеФормыДерево
МассивДобавляемыхРеквизитов = Новый Массив;
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Дерево",
Новый ОписаниеТипов("ДеревоЗначений")));
Для Каждого Колонка Из ДеревоОбъект.Колонки Цикл
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы(Колонка.Имя,
Колонка.ТипЗначения, "Дерево"));
КонецЦикла;
ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);

// Преобразование объекта прикладного типа ДеревоЗначений
// в реквизит управляемой формы (данные формы)
ЗначениеВРеквизитФормы(ДеревоОбъект, "Дерево");

// Создание элемента формы типа ТаблицаФормы для отображения дерева
ЭлементДерево = Элементы.Добавить("Дерево", Тип("ТаблицаФормы"));
ЭлементДерево.ПутьКДанным = "Дерево";
ЭлементДерево.Отображение = ОтображениеТаблицы.Дерево;

Для Каждого Колонка Из ДеревоОбъект.Колонки Цикл
НовыйЭлемент = Элементы.Добавить(Колонка.Имя, Тип("ПолеФормы"),
ЭлементДерево);
НовыйЭлемент.ПутьКДанным = "Дерево." + Колонка.Имя;
Если НЕ Колонка.Имя = "Пометка" Тогда
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
Иначе
НовыйЭлемент.Вид = ВидПоляФормы.ПолеФлажка;
НовыйЭлемент.ТриСостояния = Истина;
НовыйЭлемент.УстановитьДействие("ПриИзменении",
"ФлажокПриИзменении");
КонецЕсли;
КонецЦикла;

КонецПроцедуры

&НаКлиенте
Процедура ФлажокПриИзменении(Элемент)

ИДТекущейСтроки = Элементы["Дерево"].ТекущаяСтрока;

Если ИДТекущейСтроки <> Неопределено Тогда

ЭлементКоллекции = ЭтаФорма["Дерево"].НайтиПоИдентификатору(
ИДТекущейСтроки);

Если ЭлементКоллекции.Пометка = 2 Тогда
ЭлементКоллекции.Пометка = 0;
КонецЕсли;

УстановкаФлажков(ЭлементКоллекции, ЭлементКоллекции.Пометка);

Родитель = ЭлементКоллекции.ПолучитьРодителя();
Пока Родитель <> Неопределено Цикл
Родитель.Пометка = ?(УстановленноДляВсех(ЭлементКоллекции),
ЭлементКоллекции.Пометка, 2);
ЭлементКоллекции = Родитель;
Родитель = ЭлементКоллекции.ПолучитьРодителя();
КонецЦикла;

КонецЕсли;

КонецПроцедуры

&НаКлиенте
Процедура УстановкаФлажков(ЭлементКоллекции, ЗначениеПометки)

ПодчинЭлементы = ЭлементКоллекции.ПолучитьЭлементы();
Для Каждого ТекЭлемент Из ПодчинЭлементы Цикл
ТекЭлемент.Пометка = ЗначениеПометки;
УстановкаФлажков(ТекЭлемент, ТекЭлемент.Пометка);
КонецЦикла;

КонецПроцедуры

&НаКлиенте
Функция УстановленноДляВсех(ЭлементКоллекции)

СоседниеЭлементы =
ЭлементКоллекции.ПолучитьРодителя().ПолучитьЭлементы();
Для Каждого ТекЭлемент Из СоседниеЭлементы Цикл
Если ТекЭлемент.Пометка <> ЭлементКоллекции.Пометка Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;

КонецФункции

Источник

Дерево значений 1С – это универсальная коллекция значений, в которой данные можно расположить в иерархическом порядке в виде дерева. По сути, дерево значений в 1С 8.3 — это таблица значений, где у строк могут быть подчиненные строки. Одна строка дерева значений может иметь несколько подчиненных строк, но в тоже время она может иметь только одну строку, которой подчинена, строку-родителя, или не иметь родителя вообще. Строка без родителя – это строка верхнего уровня, или первая строка.

В программном модуле дерево значений создается при помощи конструктора Новый.

ДеревоРегионов = Новый ДеревоЗначений;

Дерево значений, также как и таблица значений может работать только в серверном контексте или на толстом клиенте, на тонком клиенте с деревом значений можно работать только тогда, когда оно создано в виде реквизита управляемой формы 1С.

То есть, такой код, при выполнении на тонком клиенте, работать не будет:

&НаКлиенте
Процедура СоздатьДерево(Команда)
   ДеревоРегионов = Новый ДеревоЗначений;
КонецПроцедуры

Поэтому, желательно, деревья значений создавать в методах, которые работают в серверном контексте.

&НаСервере
Процедура СоздатьДеревоНаСервере()
	ДеревоРегионов = Новый ДеревоЗначений;
КонецПроцедуры

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

Колонки дерева значений 1С

Само по себе дерево значений не имеет смысла, для того, чтобы можно было с ним работать у этого дерева нужно создать колонки. Для этого, нужно использовать свойство дерева значений Колонки,  которое имеет тип КоллекцияКолонокДереваЗначений, у объекта данного типа имеется ряд методов, с которыми вы можете познакомиться в синтакс-помощнике, а нас конкретно интересует метод Добавить. Этот метод добавляет новые колонки в дерево значений.  Он имеет следующий синтаксис:

Добавить(<Имя>, <Тип>, <Заголовок>, <Ширина>)

Где Имя – это имя колонки (уникальное в рамках этого дерева); Тип – в этом параметре описывают возможные типы колонки, делается при помощи объекта ОписаниеТипов; Заголовок – название колонки и Ширина  — ширина колонки в символах.

Например, добавим нашему дереву регионов три колонки:

ТипСтрока = Новый ОписаниеТипов("Строка");
ТипЧисло  = Новый ОписаниеТипов("Число");

ДеревоРегионов.Колонки.Добавить("Регион",ТипСтрока);
ДеревоРегионов.Колонки.Добавить("РуководительРегиона",ТипСтрока,"Руководитель региона");
ДеревоРегионов.Колонки.Добавить("Бюджет",ТипЧисло);

Мы добавили три колонки, две из которых имеют тип строка, а одна имеет тип число.

Строки дерева значений 1С

Строки дерева значений 1С бывают двух видов. Это строки верхнего (или первого) уровня. Те строки, у которых нет ни каких родителей, и которые ни кому не подчинены.  И подчиненные строки – это строки более низких уровней. У подчиненных строк заполнено свойство Родитель, в котором указывается родительская строка, т.е. та строка, которой подчинена эта текущая строка (у строк верхнего уровня свойство Родитель пустое). Для того, чтобы создать строку верхнего (или первого) уровня, нужно воспользоваться свойством Строки дерева значений. Это свойство имеет тип КоллекцияСтрокДереваЗначений. И у объекта этого типа есть метод Добавить, который создает новую строку верхнего (первого) уровня. Причем, этот метод является функцией, которая возвращает строку дерева значений. А у этой строки мы, как к свойствам, можем обращаться к колонкам дерева значений.

СтрокаВерхнего = ДеревоРегионов.Строки.Добавить();
СтрокаВерхнего.Регион = "Приволжский округ";
СтрокаВерхнего.РуководительРегиона = "Петров";
СтрокаВерхнего.Бюджет = 1000000;

СтрокаВерхнего = ДеревоРегионов.Строки.Добавить();
СтрокаВерхнего.Регион = "Сибирский округ";
СтрокаВерхнего.РуководительРегиона = "Борисов";
СтрокаВерхнего.Бюджет = 1000000;

В этом коде добавлено две строки верхнего уровня дерева регионов.

Для того, чтобы добавить строку следующего уровня (второго, третьего и т.д.) нужно воспользоваться свойством Строки уже созданной строки.

Например, так мы создаем две строки второго уровня:

СтрокаВторогоОдин = СтрокаВерхнего.Строки.Добавить();
СтрокаВторогоОдин.Регион = "Удмуртия";
СтрокаВторогоОдин.РуководительРегиона = "Бречалов";
СтрокаВторогоОдин.Бюджет = 500000;

СтрокаВторогоДва = СтрокаВерхнего.Строки.Добавить();
СтрокаВторогоДва.Регион = "Татарстан";
СтрокаВторогоДва.РуководительРегиона = "Шаймиев";
СтрокаВторогоДва.Бюджет = 500000;

А так, мы создаем строки третьего уровня (две для Удмуртии и одну для Татарстана):

СтрокаТретьегоОдин = СтрокаВторогоОдин.Строки.Добавить();

СтрокаТретьегоОдин.Регион = "Завьяловский район";
СтрокаТретьегоОдин.РуководительРегиона = "Иванов";
СтрокаТретьегоОдин.Бюджет = 100000;

СтрокаТретьегоДва = СтрокаВторогоОдин.Строки.Добавить();

СтрокаТретьегоДва.Регион = "Ярский район";
СтрокаТретьегоДва.РуководительРегиона = "Сидоров";
СтрокаТретьегоДва.Бюджет = 100000;


СтрокаТретьегоТри  = СтрокаВторогоДва.Строки.Добавить();

СтрокаТретьегоТри.Регион = "Мензилинский район";
СтрокаТретьегоТри.РуководительРегиона = "Шайхметов";
СтрокаТретьегоТри.Бюджет = 100000;

Обход дерева значений 1С

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

Для Каждого СтрПервогоУровня из ДеревоРегионов.Строки Цикл 
	Сообщить(СтрПервогоУровня.Регион + "/" + СтрПервогоУровня.Руководитель);
КонецЦикла;

Поскольку свойство Строки дерева значений является коллекцией, то к ней применим цикл Для Каждого Цикл. Где в значении очередного элемента коллекции находится строка верхнего уровня (первого) дерева значений, у этой строки можно обращаться к колонкам как к свойствам.

Если нам нужно обойти строку следующего уровня, то в этот раз следует уже циклом Для каждого Цикл обходить свойство Строки текущей строки дерева значений.

Для Каждого СтрПервогоУровня из ДеревоРегионов.Строки Цикл 
	Сообщить(СтрПервогоУровня.Регион + "/" + СтрПервогоУровня.Руководитель);
	Для Каждого стрВторогоУровня из СтрПервогоУровня.Строки Цикл 
		Сообщить(стрВторогоУровня.Регион + "/" + стрВторогоУровня.Руководитель);
	КонецЦикла;	
КонецЦикла;	

Проблема в том,  что мы не можем знать настоящую вложенность дерева значений 1С, поэтому для обхода деревьев лучше применять рекурсивный вызов метода.

&НаСервере
Процедура ВывестиДерево(СтрокиДерева)
	
	Для Каждого стрДерева из СтрокиДерева Цикл 
		
		Сообщить(стрДерева.Регион + "/" + стрДерева.РуководительРегиона + "/");
		Если стрДерева.Строки.Количество() <> 0 Тогда 
			ВывестиДерево(стрДерева.Строки);
		КонецЕсли;	
	КонецЦикла;	
	
КонецПроцедуры

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

Теперь нам достаточно эту процедуру вызвать в том месте, где мы создаем и заполняем дерево.

ВывестиДерево(ДеревоРегионов.Строки);
Дерево значений 1С

Ну и для того, чтобы наш список выглядел более наглядно, будем при выводе строк второго и третьего уровня добавлять тире.  Для этого создадим функцию, которая добавляет тире, количество которых зависит от уровня вложенности. А узнать уровень вложенности строки можно при помощи метода строки дерева значений Уровень(), который возвращает уровень вложенности строки начиная с 0.

&НаСервере
Процедура ВывестиДерево(СтрокиДерева)
	
	Для Каждого стрДерева из СтрокиДерева Цикл 
		Пробелы = СформироватьТире(стрДерева.Уровень());
		
		Сообщить(Пробелы + стрДерева.Регион + "/" + стрДерева.РуководительРегиона + "/");
		Если стрДерева.Строки.Количество() <> 0 Тогда 
			ВывестиДерево(стрДерева.Строки);
		КонецЕсли;	
	КонецЦикла;	
	
КонецПроцедуры	

Функция  СформироватьТире(Уровень)
	
	Если Уровень = 0 Тогда 
		Возврат "";
	КонецЕсли;	
	
	Пробелы = "";
	Для н = 1 по Уровень Цикл 
		Пробелы = Пробелы + " - ";
	КонецЦикла;	
	
	Возврат Пробелы;
	
КонецФункции
Дерево значений 1С

Дерево значений 1С на управляемой форме

Для того, чтобы на управляемой форме создать дерево значений, нужно добавить реквизит на управляемую форму и присвоить  тип этому реквизиту ДеревоЗначений.

Дерево значений на управляемой форме 1С

Само по себе такое дерево бессмысленно. Нужно добавить ему колонки.  Если мы хотим дереву значений на форме добавить колонку, то необходимо сначала выделить дерево на форме, а потом нажать на кнопку «Добавить колонку реквизита».

Дерево значений на управляемой форме 1С

Можно создать колонки с различными типами, и поместить дерево на форму в виде таблицы.

Дерево значений на управляемой форме 1С

В моей учебной конфигурации имеется справочник Регионы, который является иерархическим (иерархия элементов).

Иерархический справочник на управляемой форме 1С

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

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	               |	Регионы.Ссылка КАК Регион,
	               |	Регионы.ВидРегиона КАК ВидРегиона
	               |ИЗ
	               |	Справочник.Регионы КАК Регионы
	               |
	               |УПОРЯДОЧИТЬ ПО
	               |	Регионы.Ссылка ИЕРАРХИЯ";
	
КонецПроцедуры

Заполнить это дерево можно несколькими способами. В первом способе, мы в  рекурсивной процедуре  обходим выборку из запроса, и если у этой выборки имеется выборка вложенных записей, то вызываем эту же процедуру.

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	               |	Регионы.Ссылка КАК Регион,
	               |	Регионы.ВидРегиона КАК ВидРегиона
	               |ИЗ
	               |	Справочник.Регионы КАК Регионы
	               |
	               |УПОРЯДОЧИТЬ ПО
	               |	Регионы.Ссылка ИЕРАРХИЯ";
	

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

&НаСервере
Процедура ЗаполнитьДерево(СтрокиДерева, Выборка)
	
	Пока Выборка.Следующий() Цикл 
		НовСтрока = СтрокиДерева.Добавить();
		НовСтрока.Регион = Выборка.Регион;
		НовСтрока.ВидРегиона = Выборка.ВидРегиона;
		
		ВыборкаПодчиненная = Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
		
		Если ВыборкаПодчиненная.Количество() <> 0 Тогда 
		
			ЗаполнитьДерево(НовСтрока.Строки,ВыборкаПодчиненная);
		
		КонецЕсли;
		
	КонецЦикла;	
	
КонецПроцедуры	

Второй способ  проще в плане набора кода, но он неоптимальный с точки зрения производительности: мы просто получим выгрузку из запроса и загрузим выгрузку в дерево значений на форме.

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	               |	Регионы.Ссылка КАК Регион,
	               |	Регионы.ВидРегиона КАК ВидРегиона
	               |ИЗ
	               |	Справочник.Регионы КАК Регионы
	               |
	               |УПОРЯДОЧИТЬ ПО
	               |	Регионы.Ссылка ИЕРАРХИЯ";
	
	
	Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

	ЗначениеВРеквизитФормы(Дерево,"ДеревоЗначений");
	
КонецПроцедуры

Как в результате первого способа и второго, у нас будет заполнена дерево значений на управляемой форме.

Дерево значений на управляемой форме 1С

Также с деревом значений на форме можно работать напрямую. Дерево значений на управляемой форме конвертируется в объект  ДанныеФормыДерево, который моделирует работу дерева на управляемой форме.  Для того, чтобы обратиться к элементам  верхнего уровня  этого объекта нам необходимо воспользоваться методом  ПолучитьЭлементы(), который возвращает объект имеющий тип ДанныеФормыКоллекцияЭлементовДерева, этот тип является коллекцией, и как любую коллекцию его можно обойти циклом и получить элемент этой коллекции, а уже у элемента этой коллекции посредством метода ПолучитьЭлементы() можно получить подчиненные ему строки и т.д.

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

&НаКлиенте
Процедура ОбойтиИОчиститьДеревоНаФорме(ЭлементыДерева)
	
	Для Каждого стрДерева из ЭлементыДерева Цикл 
		стрДерева.ВидРегиона = ПредопределенноеЗначение("Перечисление.ВидРегиона.ПустаяСсылка");
		ПодСтроки = стрДерева.ПолучитьЭлементы();
		Если  ПодСтроки.Количество() > 0 Тогда 
			ОбойтиИОчиститьДеревоНаФорме(ПодСтроки);
		КонецЕсли;
		
	КонецЦикла;	
КонецПроцедуры	

&НаКлиенте
Процедура Очистить(Команда)
	ОбойтиИОчиститьДеревоНаФорме(Регионы.ПолучитьЭлементы());
КонецПроцедуры

Дерево значений на управляемой форме 1С

Соответствия в 1С

Массивы в 1С

Список значений в 1С

Структура в 1С

Более подробно о работе с другими интересными объектами языка программирования в 1С читайте в моей книге «Программировать в 1С за 11 шагов»

Книга «Программировать в 1С за 11 шагов»

Изучайте программирование в 1С в месте с моей книги «Программировать в 1С за 11 шагов»

  1. Книга написана понятным и простым языком — для новичка.
  2. Книга посылается на электронную почту в формате PDF. Можно открыть на любом устройстве!
  3. Научитесь понимать архитектуру 1С;
  4. Станете писать код на языке 1С;
  5. Освоите основные приемы программирования;
  6. Закрепите полученные знания при помощи задачника;

Книга «Основы разработки в 1С: Такси»

Отличное пособие по разработке в управляемом приложении 1С, как для начинающих разработчиков, так и для опытных программистов.

  1. Очень доступный и понятный язык изложения
  2. Книга посылается на электронную почту в формате PDF. Можно открыть на любом устройстве!
  3. Поймете идеологию управляемого приложения 1С
  4. Узнаете, как разрабатывать управляемое приложение;
  5. Научитесь разрабатывать управляемые формы 1С;
  6. Сможете работать с основными и нужными элементами управляемых форм
  7. Программирование под управляемым приложением станет понятным

Промо-код на скидку в 15% — 48PVXHeYu


Если Вам помог этот урок решить какую-нибудь проблему, понравился или оказался полезен, то Вы можете поддержать мой проект, перечислив любую сумму:

можно оплатить вручную:

Яндекс.Деньги — 410012882996301

Вступайте в мои группы:

Вконтакте: https://vk.com/1c_prosto
Фейсбуке: https://www.facebook.com/groups/922972144448119/
ОК: http://ok.ru/group/52970839015518
Твиттер: https://twitter.com/signum2009

Дерево значений в управляемой форме

Свойства и методы универсальных коллекции значений типа дерево значений как и  таблицы значений не доступны в тонком клиенте. Их нужно создавать на сервере, а затем методом контекста формы  ЗначениеВРеквизитФормы(<Значение>, <ИмяРеквизита>)    преобразовать  значение объекта в   реквизит управляемой формы  с указанным именем ИмяРеквизита

Мне дали задание  –  создать форму списка заказа в виде дерева значений, как показано на рис 1

Форма создается очень просто в конфигураторе  ( см рис 2)

Рис 2 Управляемая форма с деревом значений

Однако, у меня не получилось  на сервере создавать дерево значений в путем выгрузки результата запроса по группировкам в дерево таким образом :
Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
У меня возникала  ошибка при вызове метода контекста формы:
ЗначениеВРеквизитФормы(Дерево, “ДеревоЗаказов”);
Причина ошибки была в том, что структура колонок реквизита формы ДеревоЗаказов не соответствовала структуре объекта  дерево, полученного в результате выгрузки запроса. Я не стал глубоко об этом думать и решил создавать дерево значений  в цикле. Программный код показан ниже:

&НаСервере
Процедура ЗаполнитьДеревоНаСервере()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Заказ.Ссылка КАК Ссылка,
| НАЧАЛОПЕРИОДА(Заказ.ДатаПриема, ЧАС) КАК Время
|ИЗ
| Документ.Заказ КАК Заказ
|ГДЕ
| Заказ.ДатаПриема МЕЖДУ &ДатаНач И &ДатаКон
|
|УПОРЯДОЧИТЬ ПО
| Заказ.ДатаПриема
|ИТОГИ ПО
| Время";

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

Для создания полной копии исходного дерева значений можно использовать метод метод скопировать:

НовоеДеревоСостава =  ДеревоСостава.Скопировать();

Следующая процедура предназначена для заполнения реквизита формы типа «ДеревоЗначений»
Параметры:
КоллекцияЭлементовДерева – реквизит формы, который имеет тип «ДеревоЗначений» . Реквизит заполняется значениями из второго параметра процедуры.
ДеревоЗначений – ДеревоЗначений – параметр содержит данные для заполнения.

 &НаСервере 
Процедура ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(КоллекцияЭлементовДерева, ДеревоЗначений) Экспорт
Для Каждого Строка Из ДеревоЗначений.Строки Цикл
ЭлементДерева = КоллекцияЭлементовДерева.Добавить();
ЗаполнитьЗначенияСвойств(ЭлементДерева, Строка);
Если Строка.Строки.Количество() > 0 Тогда
заполнитьКоллекциюЭлементовДереваДанныхФормы(ЭлементДерева.ПолучитьЭлементы(), Строка);
КонецЕсли;
КонецЦикла;
КонецПроцедуры

Пример вызова процедуры:

КоллекцияЭлементовДерева =Элементы.Дерево.ПолучитьЭлементы();
КоллекцияЭлементовДерева.Очистить();
ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(КоллекцияЭлементовДерева, ДеревоРезультатСКД);

Понравилась статья? Поделить с друзьями:
  • Реквизит это обязательный элемент управления
  • Реквизитов на внешнеэкономических контрактах
  • Реквизитом платежа может быть номер телефона
  • Реквизитом чека не является наименование чек
  • Реквизиты 6188 ифнс 18 по ростовской области