Часть
1. Основы Visual Basiс
|
||||||
03.04.2005 | ||||||
Глава
18.
|
||||||
Технология
Drag&Drop (перетаскивание на форме).
События перетаскивания. Автоматическое и ручное перетаскивание. Метод Drag. |
||||||
При работе с приложениями Windows часто используется такой прием, когда юзер может нажать над объектом левую кнопку мыши, и не отпуская ее переместить мышь в другое место. При этом образ объекта следует за курсором мыши. При отпускании кнопки объект перемещается в новое место (если это предусмотрено программистом). Такая технология называется Drag & Drop - перетаскивание (или перетащил и оставил).
Использование этой технологии,
по-моему является роскошью, однако придает программе профессиональный вид, а
иногда даже делает интерфейс более удобным для пользователя.
Реализовать это довольно просто. Но прежде всего надо уяснить себе следующее:
Объект может быть взят только оттуда и перетащен только туда, как это определил
программист. Иными словами, для реализации этой технологии должен быть объект-источник
Drag и объект-приемник Drop и с каждым объектом, чтобы он поддерживал Drag&Drop,
необходимо поработать отдельно.
Для реализации этой технологии
мы имеем небогатый выбор событий. Их всего два, но этого вполне достаточно,
чтобы внести неразбериху в твой проект, если в нем уже имеются процедуры событий
обработки мыши или клавиатуры. Поэтому, как мне ни грустно это говорить, тебе
надо внимательно с ними ознакомиться.
Теперь можно начинать чего-нибудь потаскать. Начнем с малого, а именно с автоматического перетаскивания.
Автоматическое перетаскивание. |
Автоматическое
перетаскивание - наиболее простая и наиболее худшая реализация технологии Drag&Drop.
Делается это элементарно. У многих объектов имеется свойство DragMode.
Оно определяет режим перетаскивания для объекта и может принимать два значения:
.DragMode=0 , т. e. вручную. и .DragMode=1 , т.е. автоматически.
По умолчанию оно в проекте всегда установлено состояние 0, то бишь ручное, и
это правильно. Но мы идем идиотским путем (а его нужно пройти обязательно),
поэтому установим свойство DragMode=1. Это можно сделать в окне свойств, а можно
программно.
Давайте создадим новый exe-прокт и посмотрим, как это все работает. Положим
на форму Text1, Text2 и Text3 со свойствами Multiline=True.
Сейчас мы попытаемся организовать перетаскивание содержимого Text1 и Tex2 в
Text3. И это нам удастся. Пишем код. Начнем со стандартного (хоть тут и нет
переменных)
Option
Explicit
В загрузке формы установим
автоматический режим свойства DragMode для Text1 и Text2 и заполним их
текстом, а Text3 очистим:
Private Sub
Form_Load()
Text1.DragMode = 1
Text2.DragMode = 1
Text1.Text = "Это какой-то текст, записанный в Text1"
Text2.Text = "А это другой текст, записанный в Text2"
Text3.Text = ""
Да,
чуть не забыл. Нам дана крутая возможность во время перетаскивания менять изображение
курсора мышки. Обалдеть можно. Хотя, на самом деле, это важно. Юзер должен контролировать
состояние перетаскивания. Ну и на этом спасибо. Курсор меняется с помощью свойства
.DragIcon. Это свойство определяет значок, который будет использоваться
в качестве указателя мыши при операции перетаскивания. Ты можешь в окне свойств
установить свойству DragIcon какую-нибудь иконку - файл с расширением
.ico. Мы для ясности сделаем это программно.
Text1.DragIcon = LoadPicture(App.Path & "\Move.ico")
Text2.DragIcon = LoadPicture(App.Path & "\Move.ico")
Но при программной загрузке
картинок их всегда надо таскать с проектом, а при загрузке картинок в окне свойств
они становятся частью проектов и отдельно их хранить не надо.
Все. Процедура Form_Load закончена.
End
Sub
Теперь логика процесса следующая.
Мы будем использовать для создания процедуры событие DragDrop, а поскольку
оно возникает по окончании процесса перетаскивания, то процедуру надо создавать
в Text3. Ведь именно там конечный пункт нашего процесса.
Private Sub
Text3_DragDrop(Source As Control, X As
Single, Y As Single)
Координаты мыши X и Y нас
сейчас мало интересуют, все равно VB сам определит, перетащили мы объект на
Text3 или нет. А вот аргумент Source мы используем. С его помощью и ключевого
слова TypeOf мы проведем проверку типа объекта (то что мы перетаскиваем
Text в Text, а не Text в Picture) и присобачив к нему свойство .Text
изменим содержимое Text3. Это и будет результат перетаскивания.
If
TypeOf
Source Is TextBox Then
Text3.Text = Source.Text
End If
End Sub
Теперь ты можешь опробовать
результат, запустив проект и поперетаскивать в Text3 и Text1 и Text2. Если ты
не смог написать эти пятнадцать строк кода самостоятельно, то скачать исходник
примера можешь здесь.
Откровенно говоря в данном случае ключевое слово TypeOf притянуто за
уши, так как других объектов на форме нет. Однако, проверять, соответствует
ли тип данных передатчика типу данных приемника все-таки надо.
Можно вместо этого проверять конкретно каждый элемент и присваивать
значение того, которого захотим. Для идентификации элемента есть простенькое
свойство Tag. Смысл его в том, что по нему с помощью аргумента Source
мы можем однозначно идентифицировать объект-источник. В отличие от других свойств,
значение свойства Tag не используется языком Visual Basic, но его можно
использовать для идентификации объектов. Этому свойству мы можем присвоить любое
имя-идентификатор, главное, чтоб они не были одинаковыми. Для этого в процедуру
Form_Load допишем две строчки:
Text1.Tag = "Text один"
Text2.Tag = "002"
Теперь наша процедура Text3_DragDrop
будет выглядеть следующим образом:
Private Sub
Text3_DragDrop(Source
As Control, X As Single, Y As
Single)
If Source.Tag = "Text один"
Or Source.Tag = "002" Then
Text3.Text = Source.Text
End If
End Sub
Опять же, если чего не получилось,
скачать эту фигню можно здесь.
Теперь рассмотрим результаты
нашей деятельности. Юзер кайфует, радостно перетаскивая текст из одного объекта
в другой. Это несомненно хорошо. Потом юзеру надоедает это делать и он с удивлением
обнаруживает тот факт, что отредактировать-то текст он не может ни в Text1,
ни в Text2. Это несомненно плохо. А дело в том, что инициируемые юзером события
мыши или клавиатуры KeyDown, KeyPress, KeyUp, MouseDown, MouseMove и MouseUp
распознаваться НЕ БУДУТ!
Видя такое дело, нам целесообразно перейти к более сложному, но и более контролируему
делу - ручному перетаскиванию.
Метод Drag - ручное перетаскивание. |
Этот метод начинает, завершает
или отменяет операцию перетаскивания любого из элементов управления кроме Line,
Menu, Shape, Timer и CommonDialog. Он позволит нам не блокировать объект для
редактирования, использовать всевозможные иконки, чтоб юзер видел, что творит
при перетаскивании и вообще правильный метод.
Еще раз напоминаю очень важную вещь, если ты не понял из предыдущего: результат
перетаскивания над перемещаемым объектом (копирование, удаление, вставка и т.д.)
определяется в объекте-приемнике в процедуре обработки события DragDrop.
Итак, для того, чтобы начать чего-нибудь перетаскивать, надо перейти в режим
перетаскивания. Для этого обычно используется процедура события MouseDown
для объекта-источника. В ней мы включаем метод Drag. Для включения-выключения
метода и отмены перетаскивания используются следующие константы, их объявлять
не надо:
vbCancel =0 'отменяет операцию перетаскивания
vbBeginDrag =1 'включает метод Drop
vbEndDrag =2 'выключает метод Drop
Давай-ка лучше сделаем новый
exe-проект и попробуем все на практике. Наш новый проект мало чем отличается
от старого по внешнему виду, но не по коду. На форме у нас будут Text1, Text2,
Text3 и еще кнопка Command1. Смысл проекта в том, чтобы перетаскивать содержимое
Text1 в Text3, а Text2 запрещен для перетаскивания. И для прикола, потаскаем
по форме командную кнопку Command1. Итак, начнем.
Объявим переменную Flag как булеву. На фига я ее ввожу? Ну не знаю, чтобы позволить
юзеру беспрепятственно редактировать текст в объекте-источнике, т.е в Text1.
Т.е. изначально Flag=False и при первом щелчке метод Drag в процедуре Text1_MouseDown
не включается. Юзер спокойно может редактировать текст. Но в конце процедуры
Flag меняет свое значение на противоположный (Flag = Not Flag) и при повторном
нажатии кнопки мыши уже включается метод Drag.
Option Explicit
Dim Flag As Boolean
В процедуре загрузки формы
зададим какое-нибудь содержимое TextBox'ам (можем и не задавать и вообще наплевать
на нее):
Private Sub
Form_Load()
Text1.Text = "Это какой-то текст, записанный в Text1"
Text2.Text = "А я вообще не знаю, что здесь делаю"
Text3.Text = "А это другой текст, записанный в Text3"
End Sub
Далее в событии MouseDown
для объекта-источника Text1 включим метод Drag для левой кнопки
мыши. И меняем состояние переменной Flag:
Private Sub
Text1_MouseDown(Button
As Integer, Shift As Integer,
X As Single, Y As Single)
'проверяем, если нажата левая кнопка мыши и это повторное
нажатие то
If Button = vbLeftButton And
Flag = True Then
'включаем метод Drag
Text1.Drag vbBeginDrag
'загружаем общую иконку для курсора в виде молнии. Она
будет обозначать,
'что объект готов к перетаскиванию
Text1.DragIcon = LoadPicture(App.Path & "\Move.ico")
End If
'меняем значение флага на противоположное
Flag = Not Flag
End Sub
В объекте-приемнике по событию
DragDrop производим результат перетаскивания, т.е. присваиваем значение Text3=Text1.
При этом проверяем тип объекта-источника:
Private Sub
Text3_DragDrop(Source
As Control, X As Single,
Y As Single)
'проверяем, соответствует ли тип объекта-источника TextBox'у
If TypeOf Source Is
TextBox Then
'если да, то
Text3.Text = Source.Text
'и для солидности передадим фокус в объект-приемник (Text3)
Text3.SetFocus
End If
End Sub
Поскольку наглядность перетаскивания для юзера чрезвычайно важна, загрузим иконки
в соответствии с положением мыши для объекта-источника (Text1):
Private Sub
Text1_DragOver(Source
As Control, X As Single, Y As
Single, State As Integer)
'если мышь над объектом-источником грузим обычную иконку
(молния)
If State = vbEnter Then
Text1.DragIcon = LoadPicture(App.Path & "\Move.ico")
'если покидает объект, то критический треугольник
ElseIf State = vbLeave Then
Text1.DragIcon = LoadPicture(App.Path & "\No.ico")
End If
End Sub
и для объекта-приемника.
Причем, обратите внимание, что в процедуре Text3 объекта-приемника мы определяем
иконки для объекта-источника (Text1). В противном случае возникнет путаница.
Private Sub
Text3_DragOver(Source
As Control, X As Single,
Y As Single, State As Integer)
'если мышь над объектом-приемником, то листик с кнопкой
- готовность принять объект
If State = vbEnter Then
Text1.DragIcon = LoadPicture(App.Path & "\Yes.ico")
'если вне объекта-приемника - то критический треугольник
ElseIf State = vbLeave Then
Text1.DragIcon = LoadPicture(App.Path & "\No.ico")
End If
End Sub
Вот вобщем-то и все. В заключении
я хочу показать, что использование проверки типа объекта-источника важна. На
этой же форме включим метод Drag для командной кнопки Command1.
Private Sub
Command1_MouseDown(Button
As Integer, Shift As Integer,
X As Single, Y As Single)
If Button = vbLeftButton Then
Command1.Drag vbBeginDrag
End If
End Sub
и напишем процедуру ее таскания
по форме
Private
Sub
Form_DragDrop(Source As Control,
X As Single, Y As Single)
If TypeOf Source Is CommandButton
Then
Source.Move X, Y
End If
End Sub
Если бы мы не проверяли тип
объекта с помощью ключевого слова TypeOf, то при попытке перетащить кнопку
в Text3 получили бы ошибку и фатальное завершение программы. Можешь попробовать.
А при наличии проверки наши методы не мешают друг другу и все проходит успешно.
В этой главе мы разобрали
технологию Drag&Drop для перетаскивания в пределах одного нашего приложения.
Скачать исходник примера можно вверху страницы.
В следующей главе мы попробуем исследовать эту технологию для обмена данных
между разными приложениями.
|
Copyright
|