Проектирование интерфейса. Объекты диалоговых окон
Объект DataObject
Этот объект не элемент управления, но участвует в операциях перетаскивания выделенных текстов из одного элемента управления в другой. В нем одновременно могут храниться несколько текстовых данных в разных форматах. Когда в DataObject помещается новый текст с имеющимся там форматом, то прежний текст с этим форматом заменяется на новый.
Поведение DataObject похоже на поведение буфера обмена. Однако DataObject существует только в момент работы приложения и исчезает после ее завершения, а данные в буфере обмена при этом не теряются, DataObject может хранить только текстовые данные, а буфер обмена - и графические. С другой стороны, DataObject - настоящий OLE-объект и поддерживает в отличие от буфера обмена операции перетаскивания текста.
Текст заносится в DataObject методом SetText, а извлекается оттуда методом GetText:
объект. SetText (StoreData [, format])
и
Строка = объект. GetText ([format]),
где объект - объект-владелец метода, StoreData - текст, который надо запомнить в объекте, format - это необязательный параметр, задающий "формат" данных ( 1 соответствует стандартному текстовому формату, а другие числа и строки соответствуют пользовательским форматам). Если параметр format в вызове SetText явно не указан, то запоминаемому тексту присваивается формат стандартного текста 1. Так как для каждого формата DataObject содержит лишь один текст с этим форматом, то фактически формат играет роль ключа, по которому текст заносится и извлекается из DataObject. Метод GetFormat позволяет узнать, имеется ли в объекте DataObject текст определенного формата:
BooleanVar = объект. GetFormat (format)
Переменная BooleanVar получит значение True, если данные с указанным форматом входят в объект. Объект DataObject может обмениваться данными с буфером обмена посредством методов GetFromClipboard и PutInClipboard. Оператор:
String = объект. GetFromClipboard ()
помещает содержимое буфера обмена в DataObject, а вызов:
объект. PutInClipboard
переносит данные из DataObject, имеющие текстовый формат 1, в буфер обмена.
Допустим, в диалоговом окне имеются два поля ввода TextIn и TextOut, командная кнопка CmbCopy и метка Lable1. Занесем при инициализации окна в поле TextIn текстовую информацию и инициализируем глобальные переменные:
Public NewData As DataObject Public NumClick As Integer Private Sub UserForm_Initialize () Set NewData = New DataObject 'инициализация объекта NumClick = 0 'число щелчков TextIn. Text = "Пример переноса данных с помощью DataObject " End Sub
При последовательных щелчках командной кнопки занесем содержимое поля TextIn в объект DataObject методом SetText, из него перенесем в буфер обмена с помощью PutInClipboard, а уже из него поместим в поле TextOut методом Paste. О выполнении очередной операции будет сообщать метка Label1.
Private Sub CmdCopy_Click () Select Case NumClick Case 0 NewData. SetText TextIn. Text Label1. Caption = "Из TextIn в DataObject" Case 1 NewData. PutInClipboard Label1. Caption = "Из DataObject в буфер обмена" Case 2 TextOut. Paste Label1. Caption = "Из буфера обмена в TextOut" End Select NumClick = NumClick + 1 If NumClick = 3 Then NumClick = 0 End Sub
Разумеется, перенос информации из одного поля в другое можно было осуществить и через буфер обмена, минуя DataObject. Для копирования данных из поля ввода в буфер обмена можно вызвать метод Copy. Более важный метод этого объекта, инициирующий операцию перетаскивания, - StartDrag рассмотрим подробнее.
Перемещение объектов. Как реализовать технику DragAndDrop
При организации интерфейса в диалоговых формах зачастую полезно предоставить пользователю возможность использовать технику DragAndDrop (Переместить и Опустить), когда некоторый объект захватывается мышью, перетаскивается к другому целевому объекту и при опускании изменяет свойства целевого объекта. Типичным примером является возможность перетаскивания элементов из одного списка в другой. Другим примером является перетаскивание писем и опускание их в почтовый ящик. Важным элементом этой техники является изменение внешнего вида курсора. Захват объекта происходит при подведении курсора к объекту и нажатии левой кнопки мыши, В этот момент курсор меняет свою внешнюю форму. Затем, когда происходит перемещение мыши, то в тех областях, где расположен целевой объект, курсор снова меняет форму, показывая, что цель достигнута. Если в этот момент, отпустить левую кнопку, то операция перемещения заканчивается успешно, отпускание кнопки мыши в других областях приводит к неуспеху. Объект DataObject и его метод StartDrag является частью этой технологии работы. Достаточно сложно понять суть этого метода, не разобравшись и в остальных частях этой технологии, в частности, в целом ряде событий, возникающих в процессе перетаскивания.
О событиях пойдет речь чуть далее, а начнем рассмотрение все-таки с метода StartDrag, который инициирует операцию перетаскивания объекта DataObject, хранящего перетаскиваемую информацию. Но прежде стоит рассмотреть пример, на котором весь этот процесс будет объясняться. Будем рассматривать диалоговое окно, имеющее два элемента ѕ список и окно ввода. Список будет содержать цвета, а текстовое окно ввода ѕ цвет, любимый пользователем. Пользователь имеет возможность выбрать любой из элементов списка и перетащить его в окно ввода. Когда пользователь захватывает выбранный им элемент списка, то возникает некоторое событие. В нашем примере это событие MouseMove, обработчик которого и будет вызывать метод StartDrag объекта DataObject, хранящего значение перетаскиваемого элемента. Теперь, когда, хотя бы частично, прояснена ситуация, предшествующая вызову метода, рассмотрим его синтаксис:
Function StartDrag ([Effect As fmDropEffect]) As fmDropEffect
Эта функция обычно вызывается в операторе присваивания вида:
ResultEffect=объект. StartDrag ([Effect as fmDropEffect])
Необязательный параметр Effect и результат выполнения функции принадлежат перечислению fmDropEffect. Константы, входящие в это перечисление имеют следующие значения:
- fmDropEffectNone = 0 - не копировать и не передвигать опущенный исходный элемент на место назначения,
- fmDropEffectCopy = 1 - копировать опущенный исходный элемент на место назначения,
- fmDropEffectMove = 2 - передвинуть опущенный исходный элемент на место назначения,
- fmDropEffectCopyOrMove = 3 - скопировать или передвинуть опущенный исходный элемент на место назначения.
Параметр Effect задает цель операции и имеет по умолчанию значение 1 ( fmDropEffectCopy ). Обычно он опускается, поскольку значение по умолчанию задает наиболее вероятную цель операции. Возвращаемое методом StartDrag значение определяет результат выполнения операции. Его можно использовать для анализа того, что же произошло в результате перетаскивания на самом деле. Важно только понимать, что между запуском метода StartDrag в правой части оператора присваивания и присваиванием результата левой части переменной ResultEffect происходит много событий в процессе перемещения объекта, работают обработчики этих событий и результат говорит о том, как закончился этот процесс.
Вот как выглядит спроектированное нами диалоговое окно "Поле и Список" в процессе работы с ним:
В этом диалоговом окне пользователь имеет возможность выбрать произвольный элемент списка "Цвета" и перетащить его мышью в поле "Любимый цвет"
Рассмотрим обработчики событий, поддерживающие процесс перетаскивания. Начнем с обработчика события Initialize для диалогового окна, обеспечивающего инициализацию начального состояния:
Private Sub UserForm_Initialize () With Me. DraggedList . AddItem "Красный" . AddItem "Оранжевый" . AddItem "Желтый" . AddItem "Зеленый" . AddItem "Голубой" . AddItem "Синий" . AddItem "Фиолетовый" . AddItem "Черный" . AddItem "Белый" End With End Sub
Здесь инициализируется список "Цвета", имеющий имя DraggedList. Когда пользователь, выбирая элемент этого списка, нажимает левую клавишу мыши, готовясь перетащить этот элемент в другое место, у списка возникает событие MouseMove, обработчик которого имеет много параметров. Описание этого события, всех его параметров, описание других используемых нами событий, будут даны в последующих параграфах, а сейчас приведем текст этого обработчика:
Private Sub DraggedList_MouseMove (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single) Dim MyDataObject As DataObject Dim Msg As String Msg = "Видимо, Вы уронили цвет при перетаскивании. Повторите операцию!" If Button = 1 Then Debug. Print "MouseMove" Set MyDataObject = New DataObject Dim Effect As Integer MyDataObject. SetText DraggedList. Value Effect = MyDataObject. StartDrag (fmDropEffectCopy) If Effect = 0 Then MsgBox (Msg) Debug. Print "Effect = ", Effect End If End Sub
О параметрах, как уже говорилось речь пойдет впереди, а сейчас прокомментируем его работу. Если в момент возникновения события нажата левая кнопка мыши, то создается новый объект DataObject, его метод SetText копирует значение выбранного элемента списка, а метод StartDrug запускает процесс перетаскивания. Заметьте, что метод StartDrug можно было бы вызывать без параметра, ѕ на результат это не повлияло бы. Результат перетаскивания анализируется и, если он закончился неуспехом ( Effect = 0 ), то выдается уведомляющее сообщение. Исполняемые операторы окаймлены отладочной печатью, что позволит нам продемонстрировать, что между первой печатью, уведомляющей о начале работы обработчика MouseMove, и последней печатью, уведомляющей о результате работы, будут напечатаны сообщения других обработчиков, к рассмотрению которых мы и переходим.
Событие BeforeDragOver возникает для объекта TextIn (поле ввода "Любимый цвет"), когда курсор в процессе перетаскивания попадает в область, занятую объектом. Заметьте, событие возникает многократно, поскольку курсор находится в этой области некоторое время. Вот текст обработчика этого события:
Private Sub TextIn_BeforeDragOver (ByVal Cancel As MSForms. ReturnBoolean, _ ByVal Data As MSForms. DataObject, ByVal X As Single, _ ByVal Y As Single, ByVal DragState As MSForms. fmDragState, _ ByVal Effect As MSForms. ReturnEffect, ByVal Shift As Integer) Cancel = True Effect = fmDropEffectCopy Debug. Print "DragOver" End Sub
Заметьте, основное, что делает этот обработчик, он устанавливает значение параметра Effect. Поскольку эффект совпадает с целевым эффектом, то курсор в области, занятой полем TextIn, будет менять свою форму, принимая вид прямоугольника со знаком "+", указывающим, что цель достигнута и можно отпустить левую клавишу мыши. Завершающий оператор отладочной печати позволит проследить за числом вызовов этого обработчика.
Следующее событие для объекта TextIn возникает, когда отпущена левая клавиша мыши в области этого объекта. Вот его обработчик:
Private Sub TextIn_BeforeDropOrPaste (ByVal Cancel As MSForms. ReturnBoolean, _ ByVal Action As MSForms. fmAction, ByVal Data As MSForms. DataObject, _ ByVal X As Single, ByVal Y As Single, ByVal Effect As MSForms. ReturnEffect, _ ByVal Shift As Integer) Cancel = True Effect = fmDropEffectCopy TextIn. Text = Data. GetText Debug. Print "DragPaste" End Sub
Здесь также возвращается значение эффекта. Главное, завершается операция перетаскивания копированием текста в поле ввода из переданного в качестве параметра объекта Data класса DataObject, хранящего значение цвета, выбранного пользователем.
Совместная работа этих трех обработчиков событий и вызываемые в них методы объекта DataObject - SetText, GetText, StartDrag - обеспечивают в совокупности технику DragAndDrop. В заключение о двух экспериментах при работе с диалоговым окном. Вначале, мы не донесли выбранный нами цвет до окна ввода, отпустив левую клавишу мыши на дороге к нему. Вот как выглядело сообщение, полученное нами:
Затем повторно выбранный нами зеленый цвет был успешно перетащен в окно "Любимый цвет". Приведем отладочную печать этих двух экспериментов:
MouseMove Effect = 0 MouseMove DragOver DragOver DragOver DragPaste Effect = 1
Первые две строчки связаны с неудачной попыткой переноса, когда эффект был нулевым. Следующие строки описывают успешный эксперимент. Заметьте, что между печатью, информирующей о начале работы обработчика MouseMove и его заключительной печатью об успешном эффекте, вклинились сообщения, поступающие от обработчиков событий DragOver и DropOrPaste. Заметьте, я оставил только три сообщения от обработчика DragOver, реально их было 25. На этом описание примера заканчивается, но разговор о событиях еще предстоит.