Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Как создать событие для листа Excel?

3.4K
05 августа 2003 года
max_r
5 / / 06.06.2003
Подскажите можно ли создать для листа Excell свое событие например worksheet_MouseMove(ну чтоб перхватывалось событие перемещения курсора на листом). Догадываюсь только, что этот как-то релизуется через API функции, но какие функции использовать? Подскажите, плиз.
258
18 августа 2003 года
SergeySV
1.5K / / 19.03.2003
Насколько мне видится это можно сделать следующим образом.

Ставим в макросе hook (ловушку) типа - WH_JOURNALRECORD. Для этого надо создать модуль со следующим кодом:
Код:
Option Explicit

Public Type POINTAPI
x As Long
y As Long
End Type

Public Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Public Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long

Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare Function GetForegroundWindow Lib "user32" () As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long


Private Const WM_MOUSEMOVE = &H200
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Const WM_LBUTTONDBLCLK = &H203
Private Const WM_RBUTTONDOWN = &H204
Private Const WM_RBUTTONUP = &H205
Private Const WM_RBUTTONDBLCLK = &H206
Private Const WM_MBUTTONDOWN = &H207
Private Const WM_MBUTTONUP = &H208
Private Const WM_MBUTTONDBLCLK = &H209
Private Const WM_MOUSEWHEEL = &H20A
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101

Public Const WH_JOURNALRECORD = 0

Type CBTACTIVATESTRUCT
fMouse As Long
hWndActive As Long
End Type

Dim CBT As CBTACTIVATESTRUCT
Public hHook As Long



'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
' Значение этих констант может зависеть от версии Office!
' Необходимо через Spy++ или WinIspector определить классы окон в Вашей версии Office.
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Const cClassNameXLMAIN As String = "XLMAIN" ' имя класса главного окна Excel'а
Const cClassNameWrbook As String = "EXCEL7" ' имя класса окна workbook Excel'а



' свои служеб. переменные
Public sNameBook As String ' имя книги для которой необходимо отслеживать событие MoveMouse,
                           ' меняем из любого места программы.
                           

Public Function HookProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim WinWnd As Long
Dim lpClassName As String
Dim sNameWin As String
Dim i As Long

' получаем дескриптор активного окна
WinWnd = GetForegroundWindow()
' буфер для имени класса окна
lpClassName = Space(256)
' получаем имя класса активного окна
i = GetClassName(WinWnd, lpClassName, 256)
' от пробелов освобождаемся
lpClassName = Left(lpClassName, i)

If lpClassName = cClassNameXLMAIN Then ' если активное окно не Excel, то не мучаем систему
                                       ' и больше ничего не делаем.
     
    CopyMemory CBT, ByVal lParam, Len(CBT)
   
    Select Case CBT.fMouse
   
    ' событие - движение мыши
    Case WM_MOUSEMOVE
      Dim CurPos As POINTAPI
      ' получаем новые коорд.
      GetCursorPos CurPos
      ' получение hWnd окна под курсором
      WinWnd = WindowFromPoint(CurPos.x, CurPos.y)
      ' опр. имя класса по найденному hWnd
      lpClassName = Space(256)
      i = GetClassName(WinWnd, lpClassName, 256)
      lpClassName = Left(lpClassName, i)
      If lpClassName = cClassNameWrbook Then ' курсор над workbook (какой-то, пока еще не известно какой)
        ' создание стр. перем. необходимой длинны
        sNameWin = String(GetWindowTextLength(WinWnd) + 1, Chr$(0))
        ' получение заголовка окна (в нем название акт. Excel'ского файла)
        GetWindowText WinWnd, sNameWin, Len(sNameWin)
        'Debug.Print sNameWin 'отладка
        If sNameWin = sNameBook Then
          ' курсор движется над нужной (sNameBook) workbook
           
          ' вызываем свою функцию для обработки события MouseMove над книгой
          Call MouseMoveOnWorkbook(CurPos.x, CurPos.y)
        End If
      End If
       
    Case WM_KEYDOWN
      Debug.Print "KEYDOWN"
    Case WM_KEYUP
      Debug.Print "KeyUp"
   
    Case WM_MOUSEWHEEL
      Debug.Print "MOUSEWHEEL"
   
    Case WM_LBUTTONDOWN
      Unload UserForm2
      Debug.Print "LBUTTONDOWN"
       
    Case WM_LBUTTONUP
      Debug.Print "LeftUp"
   
    Case WM_RBUTTONDOWN
      Debug.Print "RBUTTONDOWN"
   
    Case WM_RBUTTONUP
      Debug.Print "RightUp"
   
    Case WM_MBUTTONDOWN
      Debug.Print "MBUTTONDOWN"
   
    Case WM_MBUTTONUP
      Debug.Print "MiddleUp"
     
    End Select

End If

HookProc = CallNextHookEx(hHook, nCode, wParam, lParam)

End Function


В этом модуле описывается функция HookProc, которая вызывается, когда твоя прога устанавливает hook (ловушку). В ней же идет анализ перехваченных событий в системе.
В Win98 установленная таким образом ловушка будет глобальной, на всю систему, а вот под другие оси возможно ограничения только процессом установшим эту ловушку (нам и такой и вариант для Excel'а в принципе подходит). Дело в том, что по хорошем, для глобальных hook их функцию HookProc надо бы засовывать не в модуль, а в Dll'ку (но, вообщем, для такого типа ловушек - WH_JOURNALRECORD и для наших задач и так пока сойдет, а написание своих dll это уже совсем другая история).

Когда модуль будет создан и включен в проект, необходимо будет в своем коде установить ловушку, а потом еще не забыть ее удалить. Это делается так:

hHook = SetWindowsHookEx(WH_JOURNALRECORD, AddressOf HookProc, 0, 0)

а удалить:
Call UnhookWindowsHookEx(hHook)

(переменная hHook уже объявлена в модуле, так что объявлять ее еще раз в коде макроса не надо)

Несколько слов по коду модуля:
1. Как я там написал, константы cClassNameXLMAIN и cClassNameWrbook могут зависеть от версии Office и их хорошо бы перепроверить в твоем случае через программы: Spy++ или WinIspector.
2. Публичная переменая sNameBook - для указания названия книги, для которой необходимо отслеживать движение мыши (если все равно над какими книгами, то код легко упростить, убрав лишнюю проверку)
3. В итоге событие возникает при движении мыши над книгой, без проверки названия листа - до него не смог добраться. Но это просто сделать и обычными средствами Ecxel'а через ThisWorksheet в самом коде макроса, получив известие о движении мыщи в пределах выбранной книги (так же можно уточнить и название книги ThisWorkbook, соответ. убрав из кода модуля тогда уже не нужную проверку на название активной книги).
Вообщем, код твой, смотри, меняй, кромсай :)
4.3K
26 августа 2003 года
max_cr
6 / / 15.08.2003
Спасибо SergeySV за пример, это как раз то, что было моей мечтой идиота уже несколько
месяцев.:)

Хочу только добавить пару моментов, с которыми столкнулся.
1. Перед всеми функциями типа(Chr,Left,Space$) нужно проставить имена модулей,
к которым они принадлежат(напр. strings.Space$), пока я это не сделал,excel при запуске
макроса постоянно зависал.

2. Согласно документации по HookProc (Borland win32) - если был поставлен хук типа
WH_JOURNALRECORD, то параметр lParam функции HookProc указывает на структуру EVENTMSG, в
которой 5 параметров. В примере копируется этот блок памяти в структуру CBTACTIVATESTRUCT,
у которой всего 2 параметра. И хотя все работает нормально, в виду того что работа с
памятью для меня темный лес я не совсем понял как так может быть. Кстати, я попытался
записывать lParam в структуру EVENTMSG, тоже сработало.

Еще раз спасибо, здорово выручил.
258
27 августа 2003 года
SergeySV
1.5K / / 19.03.2003
Цитата:
Originally posted by max_cr
2. Согласно документации по HookProc (Borland win32) - если был поставлен хук типа
WH_JOURNALRECORD, то параметр lParam функции HookProc указывает на структуру EVENTMSG, в
которой 5 параметров. В примере копируется этот блок памяти в структуру CBTACTIVATESTRUCT,
у которой всего 2 параметра. И хотя все работает нормально, в виду того что работа с
памятью для меня темный лес я не совсем понял как так может быть. Кстати, я попытался
записывать lParam в структуру EVENTMSG, тоже сработало.



Так там в структуре поля (fMouse, hWndActive) и копирование происходит по полям (в получаемом lParam тоже поля), соотв. если в структуре указанных полей нет, то они пропускаются, а заполняются только какие есть.


Насчет хука типа - WH_JOURNALRECORD, есть у меня милок подозрение. Нет у меня у меня доверия к хуку, который запущенный из модуля должен перехватывать (по MSDN) сообщения только своей программы, а в Win98 перехватывает все, как глобальный. Не проверял, но говорят, что на других платформах он так не пашет, токо в Win98. И еще программа с таким хуком у меня периодически вешает систему - грешу на него.
Так что если есть время и желание, то сделай все по уму и засунь его в отдельную dll или используй уже готовые (их много в инете разных)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог