HelpF.pro

Примеры работы с Деревом значений в УП

Так как работа с ДеревомЗначений и ТаблицейЗначений в данном контексте практически не отличается, в примере будет использоваться ДеревоЗначений, все тоже самое за исключением иерархии применимо и к ТаблицеЗначений. Как известно, в платформе 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);
ЭлементКоллекции = Родитель;
Родитель = ЭлементКоллекции.ПолучитьРодителя();
КонецЦикла;

КонецЕсли;

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

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

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

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

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

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

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

Источник
Опубликовано на сайте: https://HelpF.pro
Прямая ссылка: https://HelpF.pro/faq/view/1149.html