Часть
1. Основы Visual Basiс
|
||||||
25.04.2005 | ||||||
Глава
19.
|
||||||
Технология
Drag&Drop (перетаскивание между приложениями).
События перетаскивания. Автоматическое и ручное перетаскивание. Метод OLEDrag. Объект DataObject. |
||||||
Итак, в прошлой главе мы
проанализировали технологию Drag&Drop при перетаскивании под управлением
событий. Это хорошо при работе внутри нашего проекта. Если же нам необходимо
осуществить перетаскивание из окна совсем другого приложения, то навряд-ли мы
дождемся наступления какого-нибудь события для нашей формы (или ее объектов),
если будем щелкать по чужому окну. Поэтому сейчас мы проанализируем перетаскивание
с помощью OLE технологий. Принцип перетаскивания здесь тот же, что и при перетаскивании
с использованием событий - есть объект-приемник и объект-источник. Один и тот
же объект может быть и приемником и источником (в случае если он используется
и для приема и для передачи).
Как и в прошлой главе, начнем с чего попроще - с автоматического перетаскивания.
Автоматическое перетаскивание. |
Очень простая и удобная
технология. С его помощью мы просто перемещаем содержимое одного объекта в другой
объект. Для включения автоматического перетаскивания мы имеем два свойства:
.OLEDropMode - активизирует объект в качестве приемника | |
может принимать значения: | |
0 (vbOLEDropNone) - Нет | |
1 (vbOLEDropManual) - Вручную | |
2(vbOLEDropAutomatic) - Авто | |
.OLEDragMode - активизирует объект в качестве передатчика | |
может принимать значения: | |
0 (vbOLEDragManual) - Вручную | |
1 (vbOLEDragAutomatic) - Авто |
Эти свойства можно задавать
как в окне свойств, так и программно, в ходе выполнения программы.
Но, к сожалению, не все элементы управления (объекты) поддерживают автоматическое
перетаскивание. Некоторые элементы поддерживают оба свойства - и .OLEDropMode
и .OLEDragMode, а некоторые - только OLEDragMode. А ряд элементов
вообще нельзя использовать для автоматического перетаскивания. Вот элементы
и поддерживаемые ими свойства.
Элемент управления с режимом авто (OLE перетаскивание) |
.OLEDropMode
|
OLEDragMode
|
ComboBox |
НЕТ
|
ДА
|
DBComboBox |
НЕТ
|
ДА
|
DBGrid |
ДА
|
ДА
|
DBListBox |
НЕТ
|
ДА
|
DirecoryListBox |
НЕТ
|
ДА
|
FileListBox |
НЕТ
|
ДА
|
Image |
ДА
|
ДА
|
ListBox |
НЕТ
|
ДА
|
ListView |
НЕТ
|
ДА
|
MaskedEdit |
ДА
|
ДА
|
PictureBox |
ДА
|
ДА
|
RichTextBox |
ДА
|
ДА
|
TextBox |
ДА
|
ДА
|
TreeView |
НЕТ
|
ДА
|
Создадим новый exe-проект. Положим на форму PictureBox1 и Image1. Установим программно свойства перетаскивания в автоматический режим:
Private Sub
Form_Load()
Picture1.OLEDropMode = vbOLEDropAutomatic 'автоматический
прием
Picture1.OLEDragMode = vbOLEDragAutomatic 'автоматическая
передача
Image1.OLEDropMode = vbOLEDropAutomatic
Image1.OLEDragMode = vbOLEDragAutomatic
End Sub
Это, собственно,
все. Запустим проект. Если теперь мы откроем какую-нибудь картинку в приложении,
поддерживающем технологию OLE-перетаскивания (например Photoshop, но при этом
должен быть включен инструмент "Двигать" ("Move")), то запросто
можем перетащить картинку из него в наш проект и обратно.
Также можно перетаскивать и внутри нашего проекта из Picture1 в Image1 и наоборот.
При этом обратите внимание на то, что при перетаскивании нажатой кнопкой мыши
картинка в объекте-передатчике уничтожается, т.е. происходит перемещение. Чтобы
происходило копирование (картинка сохранялась) перетаскивание надо осуществлять
с нажатой кнопкой Ctrl.
При автоматической реализации OLE-технологии Drag&Drop мы не обрабатываем
результаты перетаскивания. Картинка (или другие данные) должны быть загружены
в объект-передатчик. Т.е. мы не можем, например, перетащить в Image1 иконку
графического файла .jpg из проводника Windows в надежде, что этот файл там неожиданно
откроется. Поскольку мы программно этого не описали, никаких сюрпризов ждать
не приходится.
Для более гибкого (и соответственно более сложного) управления перетаскиванием
можно попробовать ручное перетаскивание.
Метод OLEDrag - ручное перетаскивание. |
Ручное управление перетаскиванием позволяет программировать различные дополнительные действия. Кроме того с его помощью можно работать с такими элементами управления, не поддерживающими автоматическое перетаскивание, как CommandButton, Label, CheckBox, OptionButton, Frame и DriveListBox.
Итак, приступим. Помимо рассмотренных нами уже свойств .OLEDropMode и .OLEDragMode мы имеем еще целый ряд событий и их нам, как говорится, надо:
Прочитав этот
полубезумный бред, мы не будем впадать в истерику. Нам известна аксиома - "Visual
Basic - это не просто просто, а очень просто". Исходя из этой аксиомы,
морща лоб от напряжения и пуская слюни от усердия, мы попытаемся сейчас реализовать
технологию перетаскивания на раз-два-готово.
Изначально будем считать, что у нас есть наше приложение и некое чужое. Вот
между ними мы и будем таскать объекты, как китайские кули.
Итак, указаные выше события возникают каждое на своем объекте:
на стороне объекта-источника | на стороне объекта-приемника |
OLEStartDrop | OLEDragDrop |
OLESetData | OLEDragOver |
OLEGetFeedback | |
OLECompleteDrag |
Вроде как на
стороне приемника их меньше, вот и начнем с конца. Создадим новый exe-проект
и положим на него Picture1 и Text1. В них мы должны перетащить картинку и текст
соответственно из неких сторонних приложений. Таким образом, на нашем проекте
имеется только объекты-приемники, а формирование на стороне объекта-источника
мы оставим на совести чужого приложения. Сперва мы должны инициализировать наши
Picture1 и Text1 как объекты-приемники. Для этого мы используем то же свойство
.OLEDropMode, что и при автоматическом перетаскивании, только значение
его должно быть в этот раз vbOLEDropManual, т.е. ручное. Сделаем это
в процедуре загрузки формы (хотя можно и в окне свойств проекта):
Private
Sub
Form_Load()
Picture1.OLEDropMode = vbOLEDropManual
Text1.OLEDropMode = vbOLEDropManual
End Sub
Зная,
что при окончании перетаскивания на стороне приемника возникает событие _OLEDragDrop,
используем его для загрузки картинки в Picture1. Но как же нам передать в нашу
процедуру, что за картинка у нас, собственно, перетаскивается? А данные об этом
хранятся в объекте DataObject. Прежде всего, этот объект позволяет нам
проверить, того ли формата данные мы пытаемся загрузить в приемник (Picture1),
так как, например, текст в PictureBox загружать не очень хорошо. Для этого объект
DataObject имеет метод GetFormat. Его синтаксис следующий:
объект.GetFormat (format)
где
объект - это
наш объект DataObject
format - это
константа, указывающая на формат объекта и может принимать следующие значения:
Константа
|
Значение
константы
|
Описание
формата
|
vbCFText |
1
|
Текст (.txt-фйлы) |
vbCFBitmap |
2
|
Растр (.bmp, .jpg-файлы) |
vbCFMetafile |
3
|
Метафайл (.wmf-файлы) |
vbCFEMetafile |
14
|
Улучшеный метафайл (.emf) |
vbCFDIB |
8
|
Независимые от устройств растровые рисунки (DIB) |
vbCFPalette |
9
|
Цветовая палитра |
vbCFFiles |
15
|
Список файлов |
vbCFRTF |
-16639
|
Формат RTF (.rtf файлы) |
Коль уж мы
работаем с растровыми файлами, то можно использовать константу vbCFBitmap, однако
некоторые чужие приложения могут имет другой формат, поэтому для картинок предпочтительнее
использовать формат vbCFDIB, хотя это тоже не гарантия, что формат перетаскиваемого
объекта будет соответствовать поддерживаемому VB.
Таким образом проверка формата объекта будет выглядеть так:
If Data.GetFormat(vbCFDIB) Then ....
Теперь далее. Если наш формат правильный, то мы можем
загрузить картинку, используя метод GetData для все того же объекта DataObject.
Метод GetData возвращает данные объекта DataObject в установленном
формате. Обратный ему метод SetData устанавливает данные в нужном формате
объекта DataObject.
Синтаксис этих методов аналогичен синтаксису метода GetFormat:
объект.GetData (format)
объект.SetData данные,format
где
объект - это
наш объект DataObject
данные - это
то, что мы будем перетаскивать.
format - это
константа, указывающая на формат объекта и может принимать те же значения, что
и для метода GetFormat.
Private Sub
Picture1_OLEDragDrop(Data As DataObject, Effect
As Long, Button As Integer,
Shift As Integer, X As Single,
Y As Single)
If Data.GetFormat(vbCFDIB) Then
Picture1.Picture = Data.GetData(vbCFDIB)
Effect = vbDropEffectCopy
End If
End Sub
Как видишь
все на самом деле просто. У нас еще осталось неиспользованое событие _OLEDragOver.
С его помощью и с помощью параметра Effect мы можем управлять курсором
мыши. В зависимости от параметра Effect курсор мыши может иметь следующий
вид:
Effect = vbDropEffectNone | |
Effect = vbDropEffectCopy | |
Effect = vbDropEffectMove |
Для курсора копирования
мы можем записать такую процедурку:
Private Sub
Picture1_OLEDragOver(Data
As DataObject, Effect As
Long, Button As Integer, Shift As
Integer, X As Single, Y As
Single, State As Integer)
Effect = vbDropEffectCopy
End Sub
Надо сказать, что все прочие
параметры события _OLEDragOver имеют контрольный характер и нас не интересуют.
Хотя, отслеживая значение параметра State мы можем подгружать изображение
нужных нам курсоров (если есть желание), как мы делали в прошлой, 18-й главе.
Теперь можно перетаскивать картинку из того же Photoshopa в наш проект. Но,
например, перетащить из ACDSee (из окна превьюшек) не удастся из-за несовместимости
форматов.
А сейчас давай напишем две аналогичные процедурки для перетаскивания текста
в Text1. Суть их совершенно та же. В качестве формата объекта возьмем константу
vbCFText.
Private Sub
Text1_OLEDragDrop(Data
As DataObject, Effect As
Long, Button As Integer, Shift As
Integer, X As Single, Y As
Single)
If Data.GetFormat(vbCFText) Then
Text1.SelText = Data.GetData(vbCFText)
Effect = vbDropEffectCopy
End If
End Sub
Private Sub Text1_OLEDragOver(Data As
DataObject, Effect As Long, Button As
Integer, Shift As Integer, X As
Single, Y As Single, State As
Integer)
Effect = vbDropEffectCopy
End Sub
Теперь, если мы выделим в чужом окне, например, хоть окне кода того же Basic'а кусочек строки, то его можно будет перетянуть в Text1. Единственное, что я хочу заметить, мы в качестве свойства Text1 использовали незнакомое нам свойство .SelText. Мы могли бы использовать и свойство .Text, но тогда вставляемый текст просто заменял бы уже существующий. А с использованием свойства .SelText мы можем вставлять фрагмент текста в уже существующий текст в любое место. Подробней это и сопутствующие ему свойства рассмотрены в следующей 20-й главе.
Итак, как видите, ничего
сложного, больше пугающих таблиц со свойствами и константами, чем строк кода.
А теперь также радостно попробуем создать на нашей форме объекты-источники и
перетащить наши данные в чужое приложение. Сперва мы изменим процедуру Form_Load.
В ней мы добавим две строчки для инициализации Picture1 и Text1 как объекты-источники
и заполним их данными и будет это выглядеть так:
Private
Sub
Form_Load()
Picture1.OLEDropMode = vbOLEDropManual
Picture1.OLEDragMode = vbOLEDragManual
Text1.OLEDropMode = vbOLEDropManual
Text1.OLEDragMode = vbOLEDropManual
Picture1 = LoadPicture(App.Path & "\images_07.jpg")
Text1 = "Visual Basic - это не просто просто, а очень просто"
End Sub
Обрати внимание, что я не писал свойство .Text у Text1 и свойство .Picture у объекта Picture1. Дело в том, что это главные свойства этих объектов и понимаются VB по умолчанию (как, например, .Capture у Label и т.д.) и писать их нет никакой необходимости. Так же я буду поступать и далее.
Напишем
необходимые процедуры для источника перетаскивания - Text1. Для того,
чтобы начать перетаскивание, используется метод OLEDrag. Он не имеет
аргументов и просто начинает перетаскивание. Его удобно поставить в процедуру
_MouseMove или _MouseDown, которые позволят отследить нажатие
левой кнопки мыши (ведь при нажатой левой кнопке мыши мы и осуществляем перетаскивание):
Private Sub Text1_MouseDown(Button As
Integer, Shift As Integer, X As
Single, Y As Single)
If Button = vbLeftButton Then
'если нажата левая кнопка мыши
Text1.OLEDrag 'включаем перетаскивание
End If
End Sub
При запуске метода
OLEDrag возникает событие _OLEStartDrag, которое позволяет нам
сформировать данные для объекта-приемника. Данные эти надо поместить в объект
DataObject с помощью метода SetData. Так же, с помощью параметра
AllowedEffects мы можем определить порядок перетаскивания (копирование
или перемещение):
Private
Sub
Text1_OLEStartDrag(Data As DataObject,
AllowedEffects As Long)
AllowedEffects = vbDropEffectCopy Or vbDropEffectMove
Data.Clear 'очистка DataObject
Data.SetData Text1, vbCFText 'заполнение DataObject данными
End Sub
Обрати
внимание,
что если нам надо включить в DataObject несколько форматов, это достигается
повторным вызовом метода .SetData каждый раз с новым форматом. Поэтому,
чтобы гарантировать, что у нас нет ранее вызванных форматов, перед первым вызовом
объект DataObject очищается с помощью метода Clear.
Мы можем использовать тот
вид курсора, который нам захочется. Сделать это можно в процедуре события _OLEGiveFeedback,
в зависимости от значения его параметра Effect. Для этого используется
объект Screen и его свойства .MousePointer и .MouseIcon:
Private
Sub
Text1_OLEGiveFeedback(Effect As
Long, DefaultCursors As Boolean)
'убираем курсор по-умолчанию
DefaultCursors = False
'включаем пользовательский курсор
Screen.MousePointer = vbCustom
'в зависимости от параметра Effect подгружаем нужные нам
иконки
If Effect = vbDropEffectNone Then
Screen.MouseIcon = LoadPicture(App.Path & "\No.ico")
ElseIf vbDropEffectMove And
Effect Then
Screen.MouseIcon = LoadPicture(App.Path & "\Move.ico")
ElseIf vbDropEffectCopy And
Effect Then
Screen.MouseIcon = LoadPicture(App.Path & "\Yes.ico")
End If
End Sub
После окончания перетаскивания для объекта-источника возникает событие _OLECompleteDrag. В этой процедуре мы можем очиститьText1, если перетаскивание было перемещением, а не копированием и кроме того, надо обязательно вернуть курсор к виду, который у него был до начала перетаскивания.
Private Sub
Text1_OLECompleteDrag(Effect
As Long)
'проверка состояния Effect
If vbDropEffectMove And
Effect Then Text1 = ""
'восстановление курсора по-умолчанию
Screen.MousePointer = vbDefault
End Sub
Обратите внимание, что проверка
константы vbDropEffectMove осуществляется не так, как можно было бы предположить,
исходя из здравого смысла, а именно: If Effect = vbDropEffectMove...,
а маскируется с помощью логической операции And. В полном виде это выглядело
бы так:
If Effect and vbDropEffectMove = vbDropEffectMove, мы в программе использовали
сокращенный аналог. Делается это для совместимости с будущими версиями VB, хотя
с появлением VB Net это, наверное, неактуально.
Вот в основном и все. Теперь ты можешь перетащить текст из Text1 в другое приложение,
например Word. Процедуры для перетаскивания из Picture1 абсолютно аналогичны
и приведены в коде примера "OLEDrag.zip", который можно скачать вверху
страницы.
|
Copyright
|