Пособие-самоучитель on-line "Visual Basic с нуля"
Глава 19. Технология Drag&Drop (перетаскивание) между приложенями. Автоматическое перетаскивание. Метод OLEDrag. События перетаскивания. Объект DataObject.
Скачать исходник примера OLEDrag
Дата создания 25.04.2005 {Автор 4us}

Итак, в прошлой главе мы проанализировали технологию 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 мы имеем еще целый ряд событий и их нам, как говорится, надо:


Private Sub объект_OLEDragDrop(data As DataObject, effect As Long, button As Integer, shift As Integer, x As Single, y As Single)

Возникает при перетаскивании объекта-источника в объект-приемник.
data - объект DataObject содержит форматы (и возможно данные для этих форматов), которые обеспечивает источник. Если в объекте никаких данных не содержится, то они предоставляются при вызове метода GetData. Методы SetData и Clear использованы быть не могут.
effect - число long, устанавливаемое приемником, для опознавания действия, которое выполнено (например удалять или копировать содержимое источника). Может принимать значения следующих констант:
0 (vbDropEffectNone) - приемник не может принять данные
1 (vbDropEffectCopy) - передача копии (исходник источника сохраняется)
2 (vbDropEffectMove) - перемещение данных (исходник источника удаляется)
button - соответствует состоянию кнопки мыши. 1 - левая кнопка, 2 - правая и 4 - средняя.
shift - указывает состояние кнопок shift, alt и ctrl (1- shift, 2- alt и 4 - ctrl). При удержании больше одной кнопки их значения складываются (ctrl-alt = 4+2=6).
Значения переменных x и y возвращают текущие координаты курсора мыши (x - по-горизонтали, y - по-вертикали) в единицах измерения, заданных свойствами ScaleHeight, ScaleWidth.


Private Sub объект_OLEDragOver(data As DataObject, effect As Long, button As Integer, shift As Integer, x As Single, y As Single, state As Integer)

 

Возникает при перетаскивании одного компонента над другим.
data - объект DataObject содержит форматы (и возможно данные для этих форматов), которые обеспечивает источник. Если в объекте никаких данных не содержится, то они предоставляются при вызове метода GetData. Методы SetData и Clear использованы быть не могут.
effect - число long, устанавливаемое приемником, для опознавания действия, которое выполнено (например удалять или копировать содержимое источника). Может принимать значения следующих констант:
0 (vbDropEffectNone) - приемник не может принять данные
1 (vbDropEffectCopy) - передача копии (исходник источника сохраняется)
2 (vbDropEffectMove) - перемещение данных (исходник источника удаляется)
-2147483648 (&H80000000) (VbDropEffectScroll) - происходит или подготавливается прокрутка в приемнике (только при выполнении пользовательской прокрутки в приемнике).
button - соответствует состоянию кнопки мыши. 1 - левая кнопка, 2 - правая и 4 - средняя.
shift - указывает состояние кнопок shift, alt и ctrl (1- shift, 2- alt и 4 - ctrl). При удержании больше одной кнопки их значения складываются (ctrl-alt = 4+2=6).
Значения переменных x и y возвращают текущие координаты курсора мыши (x - по-горизонтали, y - по-вертикали) в единицах измерения, заданных свойствами ScaleHeight, ScaleWidth.
state - показывает состояние перетаскиваемого объекта по отношению к форме. Может принимать следующие значения:
0 (vbEnter) - источник в пределах приемника
1 (vbLeave) - источник вне окрестности приемника
2 (vbOver) - источник перемещается в приемнике из одного положения в другое

Private Sub объект_OLEGiveFeedback (effect As Long, defaultcursors As Boolean)
Происходит после каждого события _OLEDragOver. Позволяет показывать пользователю (например с помощью изменения курсора мыши) ход перетаскивания.
effect - число long, устанавливаемое в событии _OLEDragOver, и определяет действие, которое может быть педпринято, если пользователь опускает объект на компонент. Используется для визуализации перетаскивания.
Может принимать значения следующих констант:
0 (vbDropEffectNone) - приемник не может принять данные
1 (vbDropEffectCopy) - передача копии (исходник источника сохраняется)
2 (vbDropEffectMove) - перемещение данных (исходник источника удаляется)
-2147483648 (&H80000000) (VbDropEffectScroll) - происходит или подготавливается прокрутка в приемнике (только при выполнении пользовательской прокрутки в приемнике).
defaultcursors - значение True, если использовать курсор мыши по умолчанию и False, если не использовать. (Курсор может быть установлен свойством .MousePointer объекта Screen)

Private Sub объект_OLEStartDrag (data As DataObject, allowedeffects As Long)

Происходит, когда выполняется метод OLEDrag или когда объект инициирует операцию перемещения, если свойство OLEDragMode установлено в значение 1 - авто.
data - объект DataObject содержит форматы (и возможно данные для этих форматов), которые обеспечивает источник. Если в объекте никаких данных не содержится, то они предоставляются при вызове метода GetData. Методы SetData и Clear использованы быть не могут.
allowedeffect - число long, содержит результаты, поддерживаемые приемником. Значения данного параметра устанавливаются программистом. Может принимать значения следующих констант:
0 (vbDropEffectNone) - приемник не может принять данные
1 (vbDropEffectCopy) - передача копии (источник сохраняется)
2 (vbDropEffectMove) - перемещение данных (источник удаляется)


Private Sub объект_OLESetData(data As DataObject, dataformat As Integer)
Происходит на источнике, когда приемник выполняет метод GetData на объекте DataObject, но данные указанного формата еще не загружены.
data - объект DataObject, в который необходимо поместить запрашиваемые данные. Компонент вызывает метод SetData, чтобы загрузить запрашиваемый формат.
dataformat - целое число, уточняющее формат данных. Используется для указания источнику, что загружать в объект DataObject.

Private Sub объект_OLECompleteDrag ([effect As Long]) Возникает, когда источник опускается на получатель, информируя источник, что операция перетаскивания выполнена или отменена.
effect - число long, устанавливаемое источником, позволяющее определить действие, которое выполнено. Может принимать значения следующих констант:
0 (vbDropEffectNone) - приемник не может принять данные
1 (vbDropEffectCopy) - передача копии (источник сохраняется)
2 (vbDropEffectMove) - перемещение данных (источник удаляется)

Прочитав этот полубезумный бред, мы не будем впадать в истерику. Известна аксиома - "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.

Теперь, собственно, загрузка нашей картинки будет выглядеть так:
Picture1.Picture = Data.GetData(vbCFDIB)
Кроме того, мы можем использовать параметр effect процедуры _OLEDragDrop для определения характеристики перетаскивания: копирования, переноса или ничего.
Effect = vbDropEffectCopy 'например для копирования
Но надо сказать, что поскольку пакет данных для перетаскивания готовился в объекте-источнике в неизвестном нам приложении, то толку от использования этого параметра будет мало. Т.е. вообще не будет. Этот параметр сообщает в объект-источник, какое действие было выполнено. Но объект источник-то - в чужом приложении и ему в большей степени наплевать на наш параметр. Этот параметр сработает, если только второе приложение - тоже создавалось нами и для его объекта-источника определены соответствующие процедуры. Но мы все-таки оставим этот оператор для, так сказать, чистоты эксперимента. В результате наша процедура будет такая:

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 © 2005 4us




Сайт создан в системе uCoz