Использование метода
HitTest
Для работы с различными элементами управления можно использовать метод HitTest, который позволяет обнаруживать объект, заданный координатами точки. Этот метод использовался в проекте LVWDemo (см. гл. 8). Сейчас же рассмотрим метод HitTest подробнее, чтобы увидеть, как он использован совместно с функцией GetCursorPos().
Метод HitTest применяется только по отношению к некоторым элементам управления, являющимся контейнерами. Например, объект
ListView может содержать несколько объектов Listltem. Когда пользователь выполняет двойной щелчок в окне объекта ListView, вызывается событие DblClick,
но с его помощью нельзя определить место, где был выполнен щелчок. Чтобы выяснять, на каком именно объекте был выполнен двойной щелчок, следует использовать функцию GetCursorPos(). Она позволяет определить координаты указателя и передать их методу HitTest, который возвратит ссылку на объект, расположенный в указанном месте.
Вернемся к проекту LVWDemo и рассмотрим обработчик события DblClick в объекте ListView. Окно объекта ListView заполнено названиями компаний и связанными с ними данными. Поскольку эти объекты отображаются в виде значков (рис. 13.6), то нужно определить, на каком именно значке был выполнен щелчок (или двойной щелчок). Об отслеживании одиночного щелчка "беспокоится" обработчик события ItemClick,
генерирующий соответствующее сообщение. Обработчик события ItemClick объявляется следующим образом.
Private Sub ListViewl_ItemClick(ByVal Item As ComctLib.Listltem)
Однако обработчик события ItemDblClick отсутствует, вместо него объявлен обработчик события DblClick.
Private Sub ListViewl_DblClick()
Хотя обработчик события DblClick не позволяет получить сообщение об объекте, на котором он выполнен, обычной практикой является использование элемента управления ListView для реакции на двойной щелчок. При этом программа может косвенно обнаруживать объект, на котором выполнен двойной щелчок с помощью функции GetCursorPos() и метода HitTest. Чтобы определить координаты точки, в которой был выполнен двойной щелчок, выполните следующее.
Рис. 13.6. Приложение LVWDemo использование функции GetCursorPos() для получения информации об объекте, на котором выполнен щелчок.
Сначала объявите в модуле функцию GetCursorPos() и структуру данных POINTAPI.
Type POINTAPI
х As Long
у As Long
End Type
Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" _
(IpPoint As POINTAPI) As Long
В обработчике события DblClick необходимо организовать вызов функции GetCursorPosQ, чтобы выяснить координаты указателя в момент выполнения двойного щелчка.
GetCursorPos dPoint
Членами структуры dPoint являются координаты Х и Y указателя мыши, выраженные в пикселях в системе координат экрана. Другими словами, если функция GetCursorPosQ вызывается из обработчика события DblClick элемента управления ListView, то в результате она возвращает пару координат. Если после этого пользователь переместит форму (приложение) в другое место экрана, а затем выполнит двойной щелчок на том же значке, то координаты точки, в которой выполняется щелчок, изменятся. Следовательно, необходимо предусмотреть процедуру преобразования координат экрана в координаты окна приложения. Для этого нужно вычесть значения свойств Left и Тор окна приложения и элемента управления ListView в этом окне из значений соответствующих координат, возвращаемых функцией GetCursorPos().
X = dPoint.X - Me.Left – ListViewl.Left
Y = dPoint Y - Me.Top – ListViewl.Top
Однако данные действия не вполне корректны, поскольку координаты dPoint. Х и dPoint.Y заданы в пикселях, а все остальные координаты - в твипах (twips). Перед нахождением разности все координаты необходимо преобразовать в пиксели с помощью методов ScaleX и ScaleY. Ниже приведены выражения, позволяющие преобразовать экранные координаты во внутренние координаты элемента управления ListView
Х = dPoint.X - ScaleX(Me.Left + ListViewl.Left,
vbTwips, vbPixels) Y = dPoint.
Y = ScaleY(Me.Top + ListViewl.Top, _
vbTwips, vbPixels)
где Х и Y - координаты указателя в пикселях в момент выполнения двойного щелчка. Координаты (0, 0) соответствуют левому верхнему углу окна приложения. Значения переменных Х и Y должны быть переданы методу HitTest, возвращающему ссылку на объект, на котором выполнен двойной щелчок. Однако для обращения к методу HitTest требуется, чтобы координаты были определены в твипах. Вызов метода HitTest показан ниже.
Set LItem = ListViewl.HitTest(ScaleX(X, vbPixels, vbTwips),
ScaleY(Y, vbPixels, vbTwips))
Значения переменных Х и Y сначала преобразуются в твипы, а затем передаются методу HitTest. В результате возвращается хранящаяся в переменной LItem ссылка на объект, на котором выполнен двойной щелчок. Эта переменная объявляется как Listitem.
Dim LItem As Listltem
Используя переменную LItem, можно получить доступ к свойствам объекта, на котором был выполнен двойной щелчок. Например, можно организовать подсветку этого элемента непосредственно из программы
LItem.Selected = True
или организовать чтение элементов нижнего уровня как членов семейства.
LItem.ListSubItems
Если двойной щелчок выполнен в пределах элемента управления ListView в месте, не содержащем объектов, то переменная LItem получит значение Nothing. В этом случае попытка обратиться к свойствам элемента управления приведет к ошибке выполнения. Чтобы избежать этого, используйте оператор
On Error Resume Next
и организуйте проверку значения переменной LItem.
On Error Resume Next
Set LItem = ListViewl.HitTest(ScaleX(X, vbPixels, vbTwips), _
ScaleY(Y, vbPixels, vbTwips))
If LItem Is Nothing Then Exit Sub
(набор операторов, обеспечивающих доступ к значениям свойств LItem)
Ниже приведен текст программы обработчика события
DblClick элемента управления ListView. Этот фрагмент программы (без операторов, с помощью которых выполняется обработка членов переменной LItem} можно использовать непосредственно в пользовательской программе, если требуется организовать реагирование программы на двойной щелчок на ListView.
Программа 13.8. Обработчик события DblClick элемента управления ListView
Private Sub ListViewl_DblClick()
Dim dPoint As POINTAPI
Dim LItem As Listltem
GetCursorPos dPoint
X = dPoint.X - ScaleX(Me.Left + ListViewl.Left, vbTwips,
vbPixels)
Y = dPoint.Y - ScaleY(Me.Top + ListViewl.Top, vbTwips, vbPixels)
On Error Resume Next
Set LItem = ListViewl.HitTest(ScaleX(X, vbPixels, vbTwips), _
ScaleY(Y, vbPixels, vbTwips))
If LItem Is Nothing Then Exit Sub
If ListViewl.View = Ivwicon Or ListViewl.View = IvwSmalllcon Then
LItem.Selected = True
msg = LItem.Text & vbCrLf
For i = 1 To LItem.ListSubItems.Count
msg = msg & " " & LItem.ListSubItems(i).Text & vbCrLf
Next
MsgBox msg
End If
End Sub
Приведенный пример — не единственный способ использования метода HitTest (и даже не самый типичный). Впрочем, этот пример нетривиален, именно поэтому он столь подробно рассматривался. Этот метод был разработан в основном для обработки события DragDrop. Обработчик события DragDrop сообщает координаты точки, в которую помещен объект. Если объект операции перенести-и-оставить (drag-and-drop) находится в окнах элементов управления типа ListView или TreeView, то требуется знать элемент управления, на который был перемещен объект Ниже приведено объявление обработчика события DragDrop.
Private Sub TreeViewl _ DragDrop(Source As Control, x As Single,_
у As Single)
Поскольку координаты точки, в которую перенесен объект, известны, их можно передать в метод HitTest. чтобы выяснить, на какой из элементов управления был перенесен объект. Заметьте: при этом не требуется преобразовывать или пересчитывать значения координат, поскольку обработчик события DragDrop возвращает их значения, выраженные во внутренней системе координат (в твипах).