Работа с деревом значений в 1С 8.3
Меню

Работа с деревом значений в 1С 8.3

Содержание статьи
  1. Размещение на форме и заполнение дерева значений
  2. Работа с заполненным деревом значений

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

Размещение на форме и заполнение дерева значений

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

Дерево значений
Дерево значений

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

На стороне сервера:

  1. Получение значения реквизита;
    
    ДеревоРек = РеквизитФормыВЗначение("Дерево");
    
  2. Добавление элементов с учетом иерархии;
    
    НоваяГруппа1 = ДеревоРек.Строки.Добавить();
    НоваяГруппа1.ЭлементДерева = "Продукты";
    НоваяГруппа1.НомерЭлемента = 1;
    НоваяГруппа2 = ДеревоРек.Строки.Добавить();
    НоваяГруппа2.ЭлементДерева = "Мебель";
    НоваяГруппа2.НомерЭлемента = 2;
    НовыйЭлемент1 = НоваяГруппа1.Строки.Добавить();   	
    НовыйЭлемент1.ЭлементДерева = "Кефир";
    НовыйЭлемент1.НомерЭлемента = 3;
    НовыйЭлемент2 = НоваяГруппа1.Строки.Добавить();   	
    НовыйЭлемент2.ЭлементДерева = "Молоко";
    НовыйЭлемент2.НомерЭлемента = 4;
    
  3. Возврат значения в элемент формы на клиенте для вывода пользователю.
    
    ЗначениеВРеквизитФормы(ДеревоРек,"Дерево");
    

На стороне клиента:

  1. Получение элементов дерева;
    
    Группа1 = Дерево.ПолучитьЭлементы();
    
  2. Добавление новых.
    
    Строка1 = Группа1.Добавить();
      	Строка1.ЭлементДерева = "hand made";
      	Строка1.НомерЭлемента = 10;
      	Группа1 = Строка1.ПолучитьЭлементы();
      	Подстрока1 = Группа1.Добавить();
      	Подстрока1.ЭлементДерева = "Шкатулка";
      	Подстрока1.НомерЭлемента = 12;
      	Подстрока2 = Группа1.Добавить();
      	Подстрока2.ЭлементДерева = "Фенечка";
      	Подстрока2.НомерЭлемента = 13;
    

Результат исполнения кода
Результат исполнения кода

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

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

Иерархическая таблица значений
Иерархическая таблица значений

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

  • На стороне клиента:
    
    Дерево.ПолучитьЭлементы().Очистить();
    
  • На сервере:
    
    ДеревоЗн = РеквизитФормыВЗначение("Дерево");
    ДеревоЗн.Строки.Очистить();
    ЗначениеВРеквизитФормы(ДеревоЗн, "Дерево");
    

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

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

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

На клиентской стороне:

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

На серверной стороне:

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

Иногда в процессе обхода строк нам может потребоваться удалить что-либо. Для этого используется метод «Удалить(_параметр_)», для которого в качестве параметра может использоваться индекс или непосредственно строка. Так как в процессе обхода вы рассматриваете все строки по отдельности, не составит труда удалить некоторые из них. Будьте внимательны, так как при удалении строки удаляются все вложенные элементы.

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

Целиком алгоритм состоит из:

  1. Вызов процедуры с указанием начального идентификатора;
    
    ПреобразоватьВТЗРекурсия(тДерево, тТаблица, Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000"));
    
  2. Цикл с добавлением данных в таблицу значений и проверкой на наличие вложенных элементов в дереве в каждой итерации. При их наличии снова начинается вызов рекурсивной процедуры.
    
    &НаСервере
    Процедура ПреобразоватьВТЗРекурсия(тДерево, тТаблица, ГУИД)
       Для Каждого тСтр Из тДерево.Строки Цикл
          нСтр = тТаблица.Добавить();
          нСтр.Колонка1 = тСтр.Колонка1;
          нСтр.Колонка2 = тСтр.Колонка2;
          нСтр.Родитель = ГУИД;
          нСтр.ГУИД = Новый УникальныйИдентификатор();
     
          Если тСтр.Строки.Количество()>0 Тогда
             ПреобразоватьВТЗРекурсия(тСтр, тТаблица, нСтр.ГУИД);
          КонецЕсли;
       КонецЦикла;
    КонецПроцедуры
    

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


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

Развернутое дерево значений
Развернутое дерево значений

Также могут случаться ситуации, когда нужно свернуть имеющееся дерево. Для сворачивания конкретной строки можно воспользоваться методом «Свернуть(_Строка_)», аналогичным по синтаксису вышеописанному «Развернуть()». Чтобы полностью свернуть все дерево, придется воспользоваться рекурсивной функцией. Ее код достаточно прост и поддерживает общую методологию работы с деревом значений:


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

Результат запроса Свернуть дерево
Результат запроса Свернуть дерево

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

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

Рассказать друзьям
Предыдущая статья статья
Выпуск продукции в 1С 8.3 Бухгалтерии
Следующая статья статья
Внешняя обработка 1С: запуск, параметры, вызов
Комментарии