28/02/2019

ОТБОРЫ В ДЕРЕВЕ ЗНАЧЕНИЙ

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

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

Рассмотрим на примере отбор в документе Установка цен номенклатуры. Нам нужно выбрать номенклатуру, у которой не поменялась новая цена по отношению к старой; а также выбрать номенклатуру, у которой не установлена новая цена. Заранее хочу заметить, что мы не будем очищать дерево значений, мы лишь будем скрывать ненужные нам строки.

Для начала добавить на форму документа меню Отборы и три кнопки «Без новой цены», «Нет изменений цены», «Без отборов». Последняя кнопка будет использоваться для отключения всех отборов. Применять одновременно несколько отборов не предусмотрено. Создадим две булевых переменных ОтборПоЦенеНоль и ОтборНетИзмененияЦены. В дерево цен добавим реквизит «Отбор» тип число, непосредственно для установки отбора по этому реквизиту.
Кнопки отбора
Создадим процедуру обработки нажатия кнопки «Без новой цены».
&НаКлиенте
Процедура ОтборБезНовойЦены(Команда)
	// Отключение всех отборов 
	ОтключитьОтборы("ОтборПоЦенеНоль");
	ОтборПоЦенеНоль = не ОтборПоЦенеНоль;
	ЭлементыДерева = ДеревоЦен.ПолучитьЭлементы();
	// Обработка дерева значений 
	ОбойтиДеревоРекурсивно(ЭлементыДерева,"НетНовойЦены",Истина,не ОтборПоЦенеНоль);	
	
	ОтборУстановитьНаСервере(не ОтборПоЦенеНоль);
	// Установка картинки у кнопки для отображения включен отбор или нет
	Если ОтборПоЦенеНоль Тогда
		Элементы.ДеревоЦенКоманднаяПанель.ПодчиненныеЭлементы.ГруппаОтборы.ПодчиненныеЭлементы.
                         ДеревоЦенОтборБезНовойЦены.Картинка = БиблиотекаКартинок.ВыполненоУспешно;
	Иначе	
		Элементы.ДеревоЦенКоманднаяПанель.ПодчиненныеЭлементы.ГруппаОтборы.ПодчиненныеЭлементы.
                         ДеревоЦенОтборБезНовойЦены.Картинка = БиблиотекаКартинок.ПустаяКартинка;
	КонецЕсли;
КонецПроцедуры
Процедура для отключения необходимого отбора.
&НаКлиенте
Процедура ОтключитьОтборы(ТекущийОтбор = "")
	Отключать = Ложь;
	Если ОтборПоЦенеНоль и ТекущийОтбор <> "ОтборПоЦенеНоль" Тогда
		Элементы.ДеревоЦенКоманднаяПанель.ПодчиненныеЭлементы.ГруппаОтборы.ПодчиненныеЭлементы.
                         ДеревоЦенОтборБезНовойЦены.Картинка = БиблиотекаКартинок.ПустаяКартинка;
		Отключать = Истина;	
		ОтборПоЦенеНоль = Ложь;
	КонецЕсли;
	
	Если ОтборНетИзмененияЦены и ТекущийОтбор <> "ОтборНетИзмененияЦены" Тогда
		Элементы.ДеревоЦенКоманднаяПанель.ПодчиненныеЭлементы.ГруппаОтборы.ПодчиненныеЭлементы.
                         ДеревоЦенОтборНетИзмененияЦены.Картинка = БиблиотекаКартинок.ПустаяКартинка;
		Отключать = Истина;	
		ОтборНетИзмененияЦены = Ложь;
	КонецЕсли;
	Если Отключать Тогда
		ЭлементыДерева = ДеревоЦен.ПолучитьЭлементы();
		ОбойтиДеревоРекурсивно(ЭлементыДерева,"",Истина,Истина);	
		ОтборУстановитьНаСервере(Истина);	
	КонецЕсли;
КонецПроцедуры
Процедура ОбойтиДеревоРекурсивно используется для определения элементов, который будут показаны по заданному условию.
&НаКлиенте
Процедура ОбойтиДеревоРекурсивно(ЭлементыДерева,УсловиеОтбора,СкрыватьРодителя,ОтключитьОтбор)
	Для Каждого ЭлементДерева Из ЭлементыДерева Цикл
		Если ЭлементДерева.ИндексКартинки = 2 Тогда 	// Это Подчиненные
			Для каждого ВидЦены Из ВыбранныеЦены Цикл
// Обходим все виды цен, которые выбраны в документе
				Если не ВидЦены.Выбрана Тогда
					Продолжить;
				КонецЕсли;
				
				Если УсловиеОтбора = "НетНовойЦены" Тогда
// проверяем, что в колонке Новая цена стоит 0.
					Если (ЭлементДерева[ВидЦены.ИмяКолонки] = 0 или ЭлементДерева.Отбор = 1) 
                                              и не ОтключитьОтбор  Тогда
						ЭлементДерева.Отбор = 1;
						СкрыватьРодителя = Ложь;
					иначе
						ЭлементДерева.Отбор = 0;
					КонецЕсли;
				ИначеЕсли УсловиеОтбора = "НетИзмененияЦены" Тогда	
// проверяем что колонках Новая цена и Старая цена одинаковые значения
					Если (ЭлементДерева[ВидЦены.ИмяКолонки] = 
                                             ЭлементДерева["СтараяЦена" + ВидЦены.ИмяКолонки] 
					     или ЭлементДерева.Отбор = 1) и не ОтключитьОтбор  Тогда
						ЭлементДерева.Отбор = 1;
						СкрыватьРодителя = Ложь;
					иначе
						ЭлементДерева.Отбор = 0;
					КонецЕсли;
// Эта ветка для отключения отборов
				ИначеЕсли УсловиеОтбора = "" Тогда	
					ЭлементДерева.Отбор = 0;
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
// Рекурсивно вызываем эту процедуру для обхода всей иерархии
		ОбойтиДеревоРекурсивно(ЭлементДерева.ПолучитьЭлементы(),УсловиеОтбора,СкрыватьРодителя,ОтключитьОтбор);
// Для самого верхнего элемента. Если хоть один из подчиненных элементов будет показан при отборе, тогда будет показан и родитель
		Если ЭлементДерева.ИндексКартинки = 0 Тогда
			Если не СкрыватьРодителя и не ОтключитьОтбор Тогда
				ЭлементДерева.Отбор = 1;
				СкрыватьРодителя = Истина;
			Иначе
				ЭлементДерева.Отбор = 0;
			КонецЕсли;   
		КонецЕсли;
		
    КонецЦикла;
КонецПроцедуры
Процедура ОтборУстановитьНаСервере необходима непосредственно для установки видимости выбранных строк с помощью условного оформления.
&НаСервере
Процедура ОтборУстановитьНаСервере(ОтключитьОтбор)
	Для каждого текЭлементУО Из УсловноеОформление.Элементы Цикл
	  //проверяем, что элемент УО - это установка видимости строки
		Если Найти(текЭлементУО.Представление, "ДеревоЦенВидимостьСтрок") > 0  Тогда
	  		текЭлементФормы      =             Элементы["ДеревоЦен"];
	  		текЭлементУО.Поля.Элементы.Очистить();
	  		ДобавитьПодчиненныеЭлементыДляУО(текЭлементФормы, текЭлементУО);

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