Управление Excel через Midi-контроллер
У меня есть один из них ![nanoKontrol's]()
(источник: netdna-cdn.com)
и хотел использовать ползунки для управления Excel, как одна из полос прокрутки в форме Excel.
Мне удалось изменить этот код для VBA, но он крайне нестабилен.
Кто-нибудь может помочь мне стабилизировать это? Я думаю, что функция MidiIn_Event может дать сбой, если она не возвращается достаточно быстро, но я могу ошибаться.
Заранее спасибо.
Public Const CALLBACK_FUNCTION = &H30000
Public Declare Function midiInOpen Lib "winmm.dll"
(lphMidiIn As Long,
ByVal uDeviceID As Long, ByVal dwCallback As Any,
ByVal dwInstance As Long, ByVal dwFlags As Long) As Long
Public Declare Function midiInClose Lib "winmm.dll"
(ByVal hMidiIn As Long) As Long
Public Declare Function midiInStart Lib "winmm.dll"
(ByVal hMidiIn As Long) As Long
Public Declare Function midiInStop Lib "winmm.dll"
(ByVal hMidiIn As Long) As Long
Public Declare Function midiInReset Lib "winmm.dll"
(ByVal hMidiIn As Long) As Long
Private ri As Long
Public Sub StartMidiFunction()
Dim lngInputIndex As Long
lngInputIndex=0
Call midiInOpen(ri, lngInputIndex, AddressOf MidiIn_Event,
0, CALLBACK_FUNCTION)
Call midiInStart(ri)
End Function
Public Sub EndMidiRecieve()
Call midiInReset(ri)
Call midiInStop(ri)
Call midiInClose(ri)
End Sub
Public Function MidiIn_Event(ByVal MidiInHandle As Long,
ByVal Message As Long, ByVal Instance As Long,
ByVal dw1 As Long, ByVal dw2 As Long) As Long
'dw1 contains the midi code
If dw1 > 255 Then 'Ignore time codes
Call MsgBox(dw1) 'This part is unstable
End If
End Function
Ответы
Ответ 1
Проблема, вероятно, MsgBox
:
- Поскольку события MIDI используют обратные вызовы, они скорее всего запускаются из другого потока. VBA по сути является однопоточным (см., Например, многопоточность в VBA), поэтому попытка показать модальное диалоговое окно из другого потока может вызвать проблемы (поведение undefined крушение, все остальное...)
- MIDI обычно запускает огромное количество событий (самое маленькое движение ползунка или ручки вызывает событие), поэтому перемещение чего-то заметного количества может привести к сотням событий. Отображение диалога (требующего нажатия OK) на каждом событии может быть проблемой.
Для тестирования попробуйте заменить Call MsgBox(dw1)
на Debug.Print dw1
, чтобы значения только что были напечатаны в окне Immediate, которое должно быть намного более стабильным. Если вы пытаетесь выполнить какое-то простое действие (например, обновите значение в ячейке, прокрутите окно), вы сможете уйти с ним, если каждый вызов MidiIn_Event
завершается до следующего события.
Более сложным, но стабильным решением может быть толкание точек данных в очередь в обработчике событий и использование повторяющегося таймера в VBA, который выталкивает элементы из очереди и выполняет некоторые действия в потоке VBA.
Ответ 2
Это так замечательно круто: D
но окно сообщения, как упоминалось выше, убьет его, но удаление почтового ящика, вероятно, не поможет. Вы хотите свести к минимуму количество трафика, чтобы преуспеть, потому что vba- > excel не будет мгновенным.
Soooo решение будет
в макросе запуска рабочей книги
Public lngMessage As String
Private Sub Workbook_Open()
alertTime = Now + TimeValue("00:00:01")
Application.OnTime alertTime, "EventMacro"
End Sub
Sub EventMacro()
ActiveSheet.Cells(1, 1).Value = lngMessage
alertTime = Now + TimeValue("00:00:01")
End Sub
Public Function MidiIn_Event(ByVal MidiInHandle As Long, ByVal Message As Long, ByVal Instance As Long, ByVal dw1 As Long, ByVal dw2 As Long) As Long
'dw1 contains the midi code
If dw1 > 255 Then 'Ignore time codes
lngMessage = dw1 'This part is now happy
End If
End Function