Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Волшебство программирования на 1С:Предприятие 7.7 и 8.0. Выпуск 108


Компания "СофтПоинт" приглашает Вас посетить 17-ю ежегодную ИТ выставку
Softool 2006, которая будет проходить с 26 по 29 сентября в павильоне N69,
ВВЦ, г. Москва. Будем ждать Вас на нашем стенде В36, где Вы сможете увидеть
демонстрацию механизма репликации для 1С 7.7 и 8.0 и прослушать два доклада
в рамках конференции "ИТ в России".
Подробнее о нашем участии в выставке Softool 2006 Вы можете прочитать здесь:
http://www.softpoint.ru/info_id55.htm
У Вас есть возможность получить бесплатные пригласительные билеты на
выставку Softool 2006. Билеты можно получить в нашем офисе заранее или
непосредственно перед выставкой.
По всем вопросам обращайтесь к нашим менеджерам по тел. (495) 101-17-41.


Волшебство программирования на 1С:Предприятие 7.7 и 8.0
Выпуск 108 / 14.09.2006

v8: Глобальное перетаскивание
Автор: TormozIT

Как только я узнал о существовании перетаскивания, я очень удивился тому факту, что оно так мало используется в типовых конфигурациях. И решил я реализовать свой взгляд на эффективное использование этого механизма.

Для начала немного общих моментов о самом механизме.


Самое понятие "перетаскивание" (Drag&Drop) подразумевает интерактивную передачу значения от источника приемнику.
Событий перетаскивания всего 4:
- НачалоПеретаскивания
- ОкончаниеПеретаскивания
- ПроверкаПеретаскивания
- Перетаскивание
Для первой пары событий необходимо установить флажок в настройках элемента управления "Разрешить начало перетаскивания". Для второй пары - "Разрешить перетаскивание".
Перетаскивание реализовано для двух видов элементов управления: ТабличноеПоле и ПолеТабличногоДокумента. Для поля табличного документа есть некоторые ограничения. Во-первых, в режиме ТолькоПросмотр обрабатываются только первая пара событий, т.е. в этом случае оно не может выступать в качестве приемника. Во-вторых, начало перетаскивания может быть вызвано только для одной прямоугольной области.

У каждого типа обработчика события перетаскивания есть параметр ПараметрыПеретаскивания.
Этот параметр представляет собой структуру из 3-х элементов:
- Действие
- ДопустимыеДействия
- Значение

Начнем с последнего параметра - Значение. Он при стандартном начале перетаскивания в разных случаях имеет различный тип. Если источником является элемент управления типа ТабличноеПоле, то  значение перетаскивания будет иметь тип строки значения табличного поля в одиночном режиме выделения и тип Массив в случае множественного режима выделения, где элементами массива будут строки значения табличного поля. В случае поля табличного документа тип значения будет ТабличныйДокумент и будет содержать одну выделенную прямоугольную область.

Параметр Действие отвечает за внешний вид курсора и используется для управления типом перетаскивания. Он может принимать 4 значения:
- Выбор
- Копирование
- Отмена
- Перемещение
При перетаскивании левой кнопкой мыши по умолчанию Действие содержит Перемещение. Если пользователя дополнительно удерживает нажатой клавишу <CTRL>, то Действие содержит Копирование. Если претаскивание производится правой кнопкой мыши, то по умолчанию Действие содержит Выбор независимо от состояния клавиши <CTRL>. При этом, когда вы освободите правую кнопку мыши в приемнике, по умолчанию будет выведено всплывающее меню выбора, содержащее все доступные действия перетаскивания и его отмену.

Параметр ДопустимыеДействия предназначен для передачи приемнику допустимых типов перетаскивания и может принимать также 4, но уже других значения:
- Копирование
- КопированиеИПеремещение
- НеОбрабатывать
- Перемещение

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

Как перетаскивать из табличного документа?


Для начала убедитесь, что для нужного поля табличного документа установлен флаг "Разрешить начало перетаскивания". Теперь выделите ОДНУ любую прямоугольную область табличного документа и подведите курсор мыши к ее любой границе так, чтобы курсор принял форму стрелки (обычного указателя). Вот только с этого момента можно перетаскивать.

Основные идеи глобального перетаскивания.


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

Описание моего примера реализации


Используется Книга знаний: v8: Методика переопределения и вызова обработчиков событий формы

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

2) В модуль каждой формы, элементы которой должны выступать в роли приемника перетаскивания, следует поместить унифицированные обработчики событий
// Процедура - обработчик события "Перетаскивание" всех элементов формы типа ТабличноеПоле
//
Процедура ЛксТабличноеПолеПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)

    ЛксПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка);
    [Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "Перетаскивание", Элемент.Имя));]    

КонецПроцедуры // ЛксТабличноеПолеПеретаскивание()

// Процедура - обработчик события "ПроверкаПеретаскивания" всех элементов формы типа ТабличноеПоле
//
Процедура ЛксТабличноеПолеПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)

    ЛксПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка);
    [Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПроверкаПеретаскивания", Элемент.Имя));]    

КонецПроцедуры // ЛксТабличноеПолеПроверкаПеретаскивания()

В событии ПриОткрытии таких форм уже обязательно нужно вызвать ЛксПриОткрытииФормы, которая кроме установки флажка "Разрешить перетаскивание" еще подключит эти обработчики для всех элементов управления формы типа ТабличноеПоле. Поле табличного документа имеет уже упомянутые ограничения, из-за которых пришлось отказаться от использования его в качестве приемника перетаскивания.

3) Перед использованием значение перетаскивания разворачивается в массив ссылок на объекты БД (в дальнейшем - массив перетаскивания). В случае если при разворачивании встречается строка таблицы значений или дерева значений (или табличной части) то она заменяется значением первой найденной колонки из массива ключевых колонок перетаскивания.

4) Если перетаскивание происходит на табличное поле, которое является списком ссылок, то происходит попытка найти в этом списке первый элемент массива перетаскивания, имеющий подходящий тип. Если в приемнике нельзя добавлять строки или не зажата клавиша <CTRL>, то производится попытка поиска по всем ссылочным колонкам значения табличного поля. После обнаружения ссылки курсор в табличном поле устанавливается на найденную строку. Остальные элементы массива перетаскивания игнорируются.

5) Если зажата клавиша <CTRL> и в табличном поле разрешено добавление строк и оно не является списком, то происходит попытка добавить каждый элемент массива перетаскивания в новую строку. Колонка для ключа перетаскивания подбирается по типу. Через дополнительный параметр можно включить проверку уникальности перед добавлением строки.

6) Форма, выполняющая роль кармана, содержит табличное поле вершины кармана, где отражается только одна ссылка, и сворачиваемое табличное поле самого кармана, которое предоставляет доступ к его полному содержимому. Карман представляет собой хранимый персональный для каждого пользователя список ссылок на объекты БД. Перетаскивать можно в и из как самого кармана так и его вершины.

Специальная реализация перетаскивания на типовую форму подбора 1С-ных конфигураций.


Сущность функционала заключается в заполении табличных полей формы подбора таким образом, чтобы они позволили увидеть показатели по ключу перетаскивания будь то ссылка-характеристика или ссылка-номенклатура. Это одно из самых приятных применений перетаскивания в глазах рядовых пользователей. Работать с типовой формой подбора станет на порядок удобнее и быстрее. Используется Книга знаний: v8: Методика переопределения и вызова обработчиков событий формы.

// Получаем таблицу ключей для перетаскивания.
// Порядок убывания приоритета.
//
// Возвращаемое значение:
//  лТаблицаКлючей - ТаблицаЗначений – с колонками имя, тип, путь к родителю номенклатуры, значение.
//
Функция ПолучитьТаблицуКлючейПеретаскивания()

    лТаблицаКлючей = Новый ТаблицаЗначений;
    лТаблицаКлючей.Колонки.Добавить("ИмяРеквизита");
    лТаблицаКлючей.Колонки.Добавить("ТипРеквизита");
    лТаблицаКлючей.Колонки.Добавить("ПутьКРодителюНоменклатуры");
    лТаблицаКлючей.Колонки.Добавить("ЗначениеРеквизита");
    
    НоваяСтрока = лТаблицаКлючей.Добавить();
    НоваяСтрока.ИмяРеквизита = "ХарактеристикаНоменклатуры";
    НоваяСтрока.ТипРеквизита = Тип("СправочникСсылка.ХарактеристикиНоменклатуры");
    НоваяСтрока.ПутьКРодителюНоменклатуры = ".Владелец.Родитель";
    
    НоваяСтрока = лТаблицаКлючей.Добавить();
    НоваяСтрока.ИмяРеквизита = "Номенклатура";
    НоваяСтрока.ТипРеквизита = Тип("СправочникСсылка.Номенклатура");
    НоваяСтрока.ПутьКРодителюНоменклатуры = ".Родитель";
    
    Возврат лТаблицаКлючей;

КонецФункции // ПолучитьСтруктуруКлючейПеретаскивания()

// Процедура - обработчик события "Перетаскивание" элемента формы "НоменклатураДляПодбора"
//
Процедура ЛксНоменклатураДляПодбораПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)

    лЗначение = ПараметрыПеретаскивания.Значение;
    лТаблицаКлючей = ПолучитьТаблицуКлючейПеретаскивания();
    
    Если Ложь
      ИЛИ ЛксПолучитьТипСтрокиТабличнойЧасти(лЗначение) <> Неопределено
      ИЛИ ТипЗнч(лЗначение) = Тип("СтрокаТаблицыЗначений")
      ИЛИ ТипЗнч(лЗначение) = Тип("Структура")
      ИЛИ ТипЗнч(лЗначение) = Тип("Соответствие") 
    Тогда
        Для Каждого лСтрока Из лТаблицаКлючей Цикл
             Попытка
                лСтрока.ЗначениеРеквизита = лЗначение[лСтрока.ИмяРеквизита];
                Если НЕ ЗначениеНеЗаполнено(лСтрока.ЗначениеРеквизита) Тогда 
                    Прервать;
                КонецЕсли;
            Исключение
            КонецПопытки;
        КонецЦикла;
        
    ИначеЕсли ТипЗнч(лЗначение) = Тип("ТабличныйДокумент") Тогда
        Для Каждого лСтрока Из лТаблицаКлючей Цикл
            Для НомерКолонки = 1 по лЗначение.ШиринаТаблицы Цикл
                Для Номерстроки = 1 по лЗначение.ВысотаТаблицы Цикл 
                    Расшифровка = лЗначение.Область(НомерСтроки, НомерКолонки).Расшифровка;
                    Если ТипЗнч(Расшифровка) = лСтрока.ТипРеквизита Тогда 
                        лСтрока.ЗначениеРеквизита = Расшифровка;
                        Если НЕ ЗначениеНеЗаполнено(лСтрока.ЗначениеРеквизита) Тогда 
                            Прервать;
                        КонецЕсли;
                    КонецЕсли;
                КонецЦикла;
                Если НЕ ЗначениеНеЗаполнено(лСтрока.ЗначениеРеквизита) Тогда
                    Прервать;
                КонецЕсли;
            КонецЦикла;
            Если НЕ ЗначениеНеЗаполнено(лСтрока.ЗначениеРеквизита) Тогда
                Прервать;
            КонецЕсли;
        КонецЦикла;
        
    Иначе
        Для Каждого лСтрока Из лТаблицаКлючей Цикл
            Если ТипЗнч(лЗначение) = лСтрока.ТипРеквизита Тогда 
                лСтрока.ЗначениеРеквизита = лЗначение;
                Если НЕ ЗначениеНеЗаполнено(лСтрока.ЗначениеРеквизита) Тогда 
                    Прервать;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;

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

КонецПроцедуры // ЛксНоменклатураДляПодбораПеретаскивание()

// Процедура - обработчик события "ПроверкаПеретаскивания" элемента формы "НоменклатураДляПодбора"
//
Процедура ЛксНоменклатураДляПодбораПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)

    ЛксПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка);
    //Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПроверкаПеретаскивания", "НоменклатураДляПодбора"));    

КонецПроцедуры // ЛксНоменклатураДляПодбораПроверкаПеретаскивания()

// Процедура - обработчик события "Перетаскивание" элемента формы "СправочникНоменклатура"
//
Процедура ЛксСправочникНоменклатураПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)

    ЛксПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка);
    Если ЭлементыФормы.СправочникНоменклатура.ТекущаяСтрока <> Неопределено Тогда 
        УстановитьТекущегоРодителя(ЭлементыФормы.СправочникНоменклатура.ТекущаяСтрока.Родитель);
    КонецЕсли;
    //Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "Перетаскивание", "СправочникНоменклатура"));    

КонецПроцедуры // ЛксСправочникНоменклатураПеретаскивание()

// Процедура - обработчик события "ПроверкаПеретаскивания" элемента формы "СправочникНоменклатура"
//
Процедура ЛксСправочникНоменклатураПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)

    ЛксПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка);
    //Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПроверкаПеретаскивания", "СправочникНоменклатура"));    

КонецПроцедуры // ЛксСправочникНоменклатураПроверкаПеретаскивания()

// Процедура - обработчик события "ПриОткрытии" элемента формы ""
//
Процедура ЛксПриОткрытии()

    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПриОткрытии", ""));    
    ЛксПриОткрытииФормы(ЭлементыФормы, ЭтаФорма);

КонецПроцедуры // ЛксПриОткрытии()

// Процедура - обработчик события "ПередОткрытием" элемента формы "".
//
Процедура ЛксПередОткрытием(Отказ, СтандартнаяОбработка)

    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПриОткрытии", "");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПроверкаПеретаскивания", "СправочникНоменклатура");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "Перетаскивание",         "СправочникНоменклатура");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "ПроверкаПеретаскивания", "НоменклатураДляПодбора");
    ЛксУстановитьДействиеФормы(ЭтаФорма, "Перетаскивание",         "НоменклатураДляПодбора");    
    Выполнить(ЛксПолучитьСтароеДействиеФормы(ЭтаФорма, "ПередОткрытием", ""));    

КонецПроцедуры // ЛксПередОткрытием()

ЛксУстановитьДействиеФормы(ЭтаФорма, "ПередОткрытием", "");


Официальный сайт рассылки - www.mista.ru
Волшебный форум -
www.forum.mista.ru
Книга знаний - www.kb.mista.ru

С уважением,
Станислав Митичкин (Волшебник)
stasmit@mail.ru



В избранное