gifts2017

Управляемая форма 1С 8.2(8.3) – работа с деревом значений и таблицей значений. Часть II (Реализация DRAG and DROP)

Опубликовал Дмитрий К (ll13) в раздел Программирование - Практика программирования

Реализация механизма Drag and Drop (или, проще говоря, “Перетаскивания”) для ДереваЗначений, расположенного на управляемой форме управляемого приложения 1С 8.2

Эта статья является продолжением статьи «Управляемая форма 1С 8.2(8.3) – Работа с деревом значений и таблицей значений. Часть I (Основы)», она будет посвящена реализации механизма Drag and Drop (или, проще говоря, “Перетаскивания”) для ДереваЗначений, расположенного на управляемой форме управляемого приложения 1С 8.2

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

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


http://www.obrabotki.com/1s-tree-table-managedforms-2/

Скачать файлы

Наименование Файл Версия Размер
Пример к статье 11
.rar 4,42Kb
24.06.15
11
.rar 4,42Kb Скачать

См. также

Подписаться Добавить вознаграждение
В этой теме еще нет сообщений.