Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1864to1868
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Scrollrad in List- bzw. Combobox

Scrollrad in List- bzw. Combobox
29.01.2022 01:11:16
Matthias
Hallo in die Runde und Danke fürs Forum :)
Ich suchte eine Möglichkeit, mit dem Scrollrad in einer Listbox bzw. Combobox zu navigieren.
Leider habe ich trotz SuFu nur einen alten Beitrag aus 2005 gefunden --> https://www.herber.de/forum/archiv/608to612/609792_Listbox_Scroll.html :)
Leider funktioniert der Code nicht, dafür fehlt zu viel.
Ich habe aber einen anderen Code hier gefunden, der auch ohne das Fehleranfällige "Hook" auskommt-
--> https://www.mrexcel.com/board/threads/combobox-scroll-with-mouse-wheel.1024789/page-6#post-5540441
Ich stelle ihn hier aber trotzdem kurz vor, denn er ist einfach zu implementieren und funktioniert :)
Zuerst kommt dieser Code in ein Modul...



Private Type POINTAPI
x As Long
y As Long
End Type
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
#If VBA7 Then
Private Type MSG
hwnd As LongPtr
message As Long
wParam As LongPtr
lParam As LongPtr
time As Long
pt As POINTAPI
End Type
#If Win64 Then
Private Declare PtrSafe Function WindowFromPoint Lib "user32" (ByVal Point As LongPtr) As LongPtr
Private Declare PtrSafe Function AccessibleObjectFromPoint Lib "oleacc" (ByVal arg1 As LongPtr, ppacc As Any, pvarChild As Variant) As Long
#Else
Private Declare PtrSafe Function AccessibleObjectFromPoint Lib "oleacc" (ByVal lX As Long, ByVal lY As Long, ppacc As IAccessible, pvarChild As Variant) As Long
Private Declare PtrSafe Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As LongPtr
#End If
Private Declare PtrSafe Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As LongPtr) As Long
Private Declare PtrSafe Function IsWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare PtrSafe Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Declare PtrSafe Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As Long
Private Declare PtrSafe Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As MSG, ByVal hwnd As LongPtr, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
Private Declare PtrSafe Function WaitMessage Lib "user32" () As Long
Private Declare PtrSafe Function GetClientRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
Private Declare PtrSafe Function GetCursorPos Lib "user32.dll" (lpPoint As POINTAPI) As Long
Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hDc As LongPtr, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDc As LongPtr) As Long
#Else
Private Type MSG
hwnd As Long
message As Long
wParam As Long
lParam As Long
time As Long
pt As POINTAPI
End Type
Private Declare Function AccessibleObjectFromPoint Lib "oleacc" (ByVal lX As Long, ByVal lY As Long, ppacc As IAccessible, pvarChild As Variant) As Long
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function WindowFromAccessibleObject Lib "oleacc" (ByVal pacc As IAccessible, phwnd As Long) As Long
Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal Wparam As Long, ByVal lParam As Long) As Long
Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
Private Declare Function WaitMessage Lib "user32" () As Long
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetCursorPos Lib "user32.dll" (lpPoint As POINTAPI) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDc As Long, ByVal nIndex As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDc As Long) As Long
#End If
' API consts
Private Const WM_MOUSEWHEEL = &H20A
Private Const WHEEL_DELTA = 120
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Const MK_LBUTTON = &H1
Private Const SM_CXVSCROLL = 2
Private Const PM_NOREMOVE = &H0
Private Const LOGPIXELSX As Long = 88
Private Const LOGPIXELSY As Long = 90
Private Const POINTSPERINCH As Long = 72
Private Const LINES_PER_SCROLL = 1 ' 46 Then
ComboBox.Value = ComboBox.List(vChild - 1)
End If
IsMouseOverListBox = oIA.accRole(0&) = 33 Or oIA.accRole(0&) = 46
End Function
Private Sub UserFeedBack(ByVal Feedback As String)
Debug.Print Feedback
sFeedback = Feedback
End Sub
Private Function MakeDWord(ByVal loword As Integer, ByVal hiword As Integer) As Long
MakeDWord = (hiword * &H10000) Or (loword And &HFFFF&)
End Function
Private Function HighWord32(ByVal wParam As Long) As Integer
CopyMemory HighWord32, ByVal VarPtr(wParam) + 2, 2
End Function
#If Win64 Then
Private Function HighWord64(ByVal wParam As LongPtr) As Long
CopyMemory HighWord64, ByVal VarPtr(wParam) + 2, 4
End Function
#End If
Private Function ScreenDPI(ByVal bVert As Boolean) As Long
Static lDPI(1), hDc
If lDPI(0) = 0 Then
hDc = GetDC(0)
lDPI(0) = GetDeviceCaps(hDc, LOGPIXELSX)
lDPI(1) = GetDeviceCaps(hDc, LOGPIXELSY)
hDc = ReleaseDC(0, hDc)
End If
ScreenDPI = lDPI(Abs(bVert))
End Function
Private Function PTtoPX(ByVal Points As Single, ByVal bVert As Boolean) As Long
PTtoPX = Points * ScreenDPI(bVert) / POINTSPERINCH
End Function


Aufruf:
Die Prozedur kann wie folgt einfach aufgerufen werden im Codeteil einer UserForm...



Private Sub ComboBox1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal y As Single)
'Change the combobox value when scrolling by setting the second Optional arg to TRUE.
EnableMouseScroll(ComboBox:=ComboBox1, ChangeComboValueWithScroll:=True) = True
lblFeedBack.Caption = sFeedback
End Sub
Private Sub ComboBox2_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal y As Single)
EnableMouseScroll(ComboBox:=ComboBox2) = True
lblFeedBack.Caption = sFeedback
End Sub


Ich habe es mit einer Listbox probiert und es klappte :)
Also einfach die ComboBox2 mit z.B. der Listbox ersetzen und los gehts :)
Im Beispiel "ComboBox1" wird in der Listbox/Combobox der Eintrag gleich mitgewählt beim Scrollen, im Beispiel "ComboBox2" wird nur der Inhalt gescrollt, der Eintrag muss dann wie gewohnt per Mausklick erfolgen.
Gruß und viel Spass,
Matthias
P.s.: Und Danke an den Original Ersteller, vermutlich Jaafar Tribak

8
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Scrollrad in List- bzw. Combobox
29.01.2022 11:05:13
Matthias
OK, ich sag nix 🤣
Scrollrad, Mausrad...
Sind alles bürgerliche Kategorien :)
Dann geschlossen 😀
AW: Scrollrad in List- bzw. Combobox
29.01.2022 12:00:09
volti
Hallo zusammen!
@Matthias:
Vielen Dank für das von Dir gepostete Beispiel. Leider sind keinerlei Erklärungen zum Code dabei und ich bin nicht der Typ, der das unbearbeitet übernimmt.
Da es aber genau in meinem Programmierstil geschrieben ist, ist es sehr interessant und ich konnte schon zwei, drei neue Erkenntnisse gewinnen.
Offensichtlich wird hier das Scrolling in einer eigenen (VBA) DO-Schleife mit der Ermittlung der gewünschten Messages erledigt, die dann wiederum die Mausradaktivitäten (PostMessage DropDownHwnd, WM_LBUTTONDOWN, MK_LBUTTON, lParm) an das Control senden.
Ganz ohne Hooking....
@Boris:
Zur Zeit verwende ich auch, ähnlich wie Nepumuk, die Hooking-Methode, die deutlich codesparender ist als diese Methode.
Ich muss aber auch sagen, dass bei mir (64 Bit) das auch mal ohne erkennbaren Grund abschmiert. Deswegen ließ mich die Aussage von Matthias "fehleranfällig" aufhorchen.
Ich selbst bastele derzeit noch an einer dritten Varianten, bei der über SetWindowlong die Controlprozedur auf eine eigene umgelenkt wird. Ist codesparender und sollte eigentlich auch funktionieren. Will aber im Moment noch nicht ganz funktionieren.
In diesem Sinne, danke noch mal für den tollen Input.
viele Grüße
Karl-Heinz
Anzeige
Sehr gut :-) und...
29.01.2022 14:48:05
{Boris}
Hi Karl-Heinz,
...dritten Varianten, bei der über SetWindowlong die Controlprozedur auf eine eigene umgelenkt wird. Ist codesparender und sollte eigentlich auch funktionieren.
Logisch ;-))
Du musst endlich aufhören. dieses Zeugs zu rauchen ;-)))
VG, Boris
AW: Sehr gut :-) und...
29.01.2022 19:55:56
Matthias
@Karl-Heinz
Ja, und vor allem hat er gleich funktioniert.
Hatte über die Hook-Methode nur Schen von 2005 gefunden mit Anpassung an Excel97 und entsprechenden Warnungen.
Daher war ich froh über den Ansatz aus 2020 (siehe anderes Forum).
@Boris
Karl-Heinz raucht?
Brauche das auch 😀😃😄
@all
Gibt es das auch für ListView?
Gruss
Anzeige
Eine dritte Version
29.01.2022 21:25:53
volti
Hallo zusammen,
wenn ihr nur eine Listbox in Eurer Userform einsetzen wollt, gibt es hier eine codesparende weitere Hookingversion für das Mousewheeling.
Hierbei wird die Listbox bereits bei der Aktivierung der Userform gehookt und erst bei Verlassen derselben ungehookt, so dass die Funktionen zur Ermittlung des Controlbetretens und -verlassens entfallen.
Code:

[Cc][+][-]

' In ein Modul Option Explicit Private Declare PtrSafe Function WindowFromAccessibleObject Lib "oleacc" ( _ ByVal pacc As IAccessible, phwnd As LongPtr) As Long #If Win64 Then Private Declare PtrSafe Function SetWindowLongA Lib "user32" _ Alias "SetWindowLongPtrA" ( _ ByVal hWnd As LongPtr, ByVal nIndex As Long, _ ByVal dwNewLong As LongPtr) As LongPtr #Else Private Declare PtrSafe Function SetWindowLongA Lib "user32" ( _ ByVal hWnd As LongPtr, ByVal nIndex As Long, _ ByVal dwNewLong As LongPtr) As LongPtr #End If Private Declare PtrSafe Function CallWindowProcA Lib "user32" ( _ ByVal lpPrevWndFunc As LongPtr, _ ByVal hWnd As LongPtr, ByVal Msg As Long, _ ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr Private Const GWL_WNDPROC As Long = -4 Dim ghWnd As LongPtr, glpOldProc As LongPtr, goCtrl As Object Private Function WindowProc(ByVal hWnd As LongPtr, ByVal uMsg As Long, _ ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr ' Mausradbewegung verarbeiten, andere Messages an alte Prozedur weiterleiten If uMsg = &H20A Then ' WM_MOUSEWHEEL-Message ' Mausrad verarbeiten On Error Resume Next goCtrl.TopIndex = goCtrl.TopIndex + IIf(wParam > 8000000, 1, -1) End If WindowProc = CallWindowProcA(glpOldProc, hWnd, uMsg, wParam, lParam) End Function Sub MouseWheelHookList(Obj As Object) ' Zeiger auf neue Prozedur legen, alte Prozedur sichern Set goCtrl = Obj WindowFromAccessibleObject goCtrl, ghWnd ' Ermittlung Controlhandle glpOldProc = SetWindowLongA(ghWnd, GWL_WNDPROC, AddressOf WindowProc) End Sub Sub MouseWheelUnHookList() ' Zeiger auf alte Prozedur wiederherstellen Call SetWindowLongA(ghWnd, GWL_WNDPROC, glpOldProc) End Sub ' In die Userform Private Sub UserForm_Activate() Dim i As Integer Call MouseWheelHookList(ListBox1) For i = 1 To 20 ListBox1.AddItem "Item" & i Next i End Sub Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) Call MouseWheelUnHookList End Sub Private Sub UserForm_Deactivate() Call MouseWheelUnHookList End Sub

_________________________
viele Grüße aus Freigericht 😊
Karl-Heinz

Gibt es das auch für ListView?
Falls Du die von Nepumuk gezeigte Hooking-Version meinst, da kannst Du natürlich auch Listviews entsprechend übergeben.
Anzeige
AW: Eine dritte Version
29.01.2022 23:39:08
Matthias
Vielen Dank für Alles.
Werde mich dann mal durchwurschteln 🙂
Gruß und danke noch einmal...
Matthias
Und zu guter letzt....
30.01.2022 10:16:23
volti
Hallo Mattias,
dann viel Erfolg bei "Wurschteln" und Aussuchen der am besten passenden Lösung....
Und sollten es dann doch mehr Listboxen werden in einer Userform, so steht dem auch nichts mehr im Wege.
MouseWheelingListbox.xlsm
Gruß und einen schönen Sonntag noch
Karl-Heinz

Links zu Excel-Dialogen

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige