Интерактивный отбор дерева значений

markers 52 3 2

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

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

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

Давай уже код:
В начале (при создании на сервере), нам необходимо скопировать структуру оригинального дерева, вызываем процедуру СоздатьНовоеПустоеДеревоКопированием

&НаКлиентеНаСервереБезКонтекста
Функция ИмяКопииДереваЗаказа()
	
	Возврат "КопияДереваЗаказа";
	
КонецФункции

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

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

&НаСервере
Процедура СкопироватьДеревоЗаказа(ДеревоИсточник, ИмяРеквизитаНазначение)
	
	СоздатьНовоеПустоеДеревоКопированием();
	ДеревоКопия = ДеревоИсточник.Скопировать();
	ЗначениеВРеквизитФормы(ДеревоКопия, ИмяРеквизитаНазначение);	
	
КонецПроцедуры

Теперь добавляем команды которые будут отбирать значения. Сами команды кидаем на командную панель (так как только там работает "Пометка"). Этих команд отбора может быть несколько:

&НаКлиенте
Процедура ОтобратьНеУдовлетворенныйСпрос(Команда)
	УстановитьОтборДереваЗаказаНаКлиенте(Элементы.ТаблицаЗаказаОтобратьНеУдовлетворенныйСпрос); // Передаем элемент кнопки, которая вызвала данную команду
	
КонецПроцедуры

Все эти команды отбора вызывают главное - процедуру отбора:

&НаКлиенте
Процедура УстановитьОтборДереваЗаказаНаКлиенте(Элемент)
	
	Элемент.Пометка = Не Элемент.Пометка;
	УстановитьОтборДереваЗаказа();
	
КонецПроцедуры

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

		КонецЕсли;		
		
	КонецЦикла;	
	
	Для Каждого Родитель Из РодителиКУдалению Цикл
		
		ДеревоЗаказа.Строки.Удалить(Родитель);
		
	КонецЦикла;
	
	ЗначениеВРеквизитФормы(ДеревоЗаказа, "ТаблицаЗаказа"); // Передаем на форму, наше обновленное дерево
	
КонецПроцедуры

Завершение
Вуаля! Отборы прекрасно работают и делают это достаточно быстро!
И домашнее задание вам: Если вы предполагаете изменение дерева (когда установлен отбор), вам необходимо синхронизировать данные с копией дерева, которое хранит исходные данные (добавлять позиции или менять значения полей).

Мозг + источники идей из разных мест

1
Орфографическая ошибка в Вуаля: Вуаля

Комментарии

markers
#1, 18 июля 2020 12:41

Тут изучая список методов 1С, обнаружил для себя метод "КопироватьДанныеФормы", который можно использовать в данной задаче вместо РеквизитФормыВЗначение. Правда он доступен только на сервере и возможно, по факту делает тоже самое что и у меня код, но вы имейте ввиду.


См. также

ИнтерактивноеИзменениеВыгрузки_СформироватьДеревоЗначений (БСП)

ДеревоМетаданныхКонфигурации (БСП)

ИнтерактивноеИзменениеВыгрузкиОчисткаОбщегоОтбора (БСП)

МассивИзДереваЗначенийНаСервере

Вывод данных СКД в таблицу значений (дерево)

Отбор по таблице значений

ИнтерактивноеИзменениеВыгрузкиОчисткаДетально (БСП)

ИнтерактивноеИзменениеВыгрузкиОписаниеДополненияОбщегоОтбора (БСП)

ИнтерактивноеИзменениеВыгрузкиОписаниеДетальногоОтбора (БСП)

Модератору