#excel #vba #winapi
#excel #vba #winapi
Вопрос:
Я хотел бы изменить изображение курсора во время выполнения моего макроса Excel. Мне удалось изменить курсор с помощью этих функций winapi: setCursor и LoadCursorFromFileA.
Вот пример :
Option Explicit
Declare Function LoadCursorFromFileA Lib "user32" (ByVal lpFileName As String) As Long
Declare Function SetCursor Lib "user32" (ByVal hCursor As Long) As Long
Sub TestCursor()
Call SetCursor(LoadCursorFromFileA("C:Tempcursor2.cur"))
' Waits 5 seconds, any movement of the mouse will revert the cursor back to default
Application.Wait Now TimeValue("00:00:05")
' Cursor is back to default at the end of the sub
End Sub
Однако курсор вернется к значению по умолчанию, если произойдет событие (например, диалоговое окно) или если курсор будет перемещен.
Из этой ссылки кажется, что Excel обновляет курсор при наведении курсора на элементы.
Я нашел решение, но это мешает запуску моего макроса, потому что он использует бесконечный цикл.
Есть ли способ переопределить, как Excel взаимодействует с курсором?
Комментарии:
1. Что вы конкретно пытаетесь сделать? Мне кажется, перехватывать сообщения WM для получения полного контроля над указателем мыши — это вааааай перебор. МНОЖЕСТВО вещей, находящихся вне вашего контроля, отправят сообщения WM в цикл сообщений, чтобы изменить внешний вид курсора. Бесконечный цикл несколько разумен, поскольку альтернатива включает в себя создание подклассов (т. Е. Самостоятельный ввод цикла обмена сообщениями Windows)… это не то, что вы обычно делаете в повседневном коде VBA. «Во время выполнения моего макроса» не очень понятно .. вы пытаетесь изменить курсор на песочные часы? Смотрите
Application.Cursor
тогда. В противном случае… удачи!2. Самым простым способом, который я могу выразить: я хотел бы использовать пользовательское изображение для замены курсора во время работы моего макроса (в основном вычисления и форматирование). Мне удалось изменить курсор на пользовательское изображение, но в Excel есть некоторые обновления, возвращающие его к курсору по умолчанию. Я знаю о
Application.Cursor
, но он не обеспечивает поддержку пользовательских изображений. Я знаю, что это, вероятно, будет излишеством, но на данный момент это просто из любопытства и изучения более сложного способа использования VBA.3. Хм. Это одна из битв, в которой я бы предпочел не участвовать (в VBA с подклассами довольно сложно), и просто продолжайте
Application.Cursor = xlWait
во время выполнения макроса. Если курсор нужен вам только дляUserForm
, рассмотрите возможность настройкиMousePointer
свойства, как предложено в разделе «использование пользовательского указателя мыши» в этой статье .
Ответ №1:
Это некоторый пример кода подкласса. В Excel Application.hWnd
есть hWnd, который вы хотите.
Public Const WM_SETCURSOR = amp;H20
Когда вы получите вышеуказанное сообщение, верните True (-1), чтобы остановить дальнейшие изменения в курсоре.
gWindowProc = true
Public Sub Hook()
lpPrevWndProc = SetWindowLong(EditNote.gRtfHwnd, GWL_WNDPROC, _
AddressOf gWindowProc)
End Sub
Public Sub Unhook()
Dim temp As Long
temp = SetWindowLong(EditNote.gRtfHwnd, GWL_WNDPROC, lpPrevWndProc)
End Sub
Public Function gWindowProc(ByVal hwnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
If Msg = WM_CONTEXTMENU Then
If EditNote.mnuViewEditContextMenu.Checked Then EditNote.PopupMenu EditNote.mnuEdit
' gWindowProc = CallWindowProc(lpPrevWndProc, hWnd, Msg, wParam, _
lParam)
Else ' Send all other messages to the default message handler
gWindowProc = CallWindowProc(lpPrevWndProc, hwnd, Msg, wParam, _
lParam)
End If
End Function
Примечания
Слово старшего порядка в lParam равно нулю, когда окно переходит в режим меню. Функция DefWindowProc передает сообщение WM_SETCURSOR в родительское окно перед обработкой. Если родительское окно возвращает значение TRUE, дальнейшая обработка приостанавливается. Передача сообщения в родительское окно window дает родительскому окну контроль над настройками курсора в дочернем окне. Функция DefWindowProc также использует это сообщение для установки курсора в положение стрелки, если его нет в клиентской области, или в положение курсора зарегистрированного класса, если он находится в клиентской области. Если младшим словом параметра lParam является HTERROR, а старшим словом параметра lParam указывается, что нажата одна из кнопок мыши, DefWindowProc вызывает функцию MessageBeep.
MSDN 2001
Комментарии:
1. Спасибо, это очень полезно и почти работает. Это отлично работает, если мой курсор находится над лентой, но если курсор находится над окном (внутренними окнами Excel), курсор вернется к значению по умолчанию. Похоже, что Windows отправляет свое собственное сообщение, и я не могу перехватить его с помощью дескриптора приложения. Я пытался использовать дескриптор окна, но получаю
error 438 : object doesn't support this property or method
.2. Смотрите learn.microsoft.com/en-au/windows/desktop/winmsg / … о
PeekMessage()
работе. Или создайте таймер на 100 мс, который устанавливает курсор.