|
Es mag viele Gründe für eine separate, von einer ListBox unabhängige vertikale ScrollBar geben. Vielleicht möchten Sie wie in unserer Abbildung zusätzliche Schaltflächen unterbringen, die ScrollBar aus anderen Gründen anders oder anderswo anordnen, oder vielleicht sogar eine eigene ScrollBar implementieren.
Das Verbergen der vorhandenen ScrollBar einer ListBox ist noch das Einfachste. Ein Aufruf der API-Funktion ShowScrollBar verbirgt sie:
Private Declare Function ShowScrollBarAPI Lib "user32" _
Alias "ShowScrollBar" (ByVal hwnd As Long, _
ByVal wBar As Long, ByVal bShow As Long) As Long
ShowScrollBarAPI ListBox1.hWnd, SB_VERT, False
Natürlich können Sie sie auch jederzeit wieder mit
ShowScrollBarAPI ListBox1.hWnd, SB_VERT, True
sichtbar werden lassen.
Die eigentliche Aufgabe besteht darin, die notwendigen Angaben für eine eigene ScrollBar von der ListBox zu erhalten. Diese liefert Ihnen die API-Funktion GetScrollInfo.
Private Type SCROLLINFO
cbSize As Long
fMask As Long
nMin As Long
nMax As Long
nPage As Long
nPos As Long
nTrackPos As Long
End Type
Private Declare Function GetScrollInfo Lib "user32" _
(ByVal hwnd As Long, ByVal n As Long, _
lpScrollInfo As SCROLLINFO) As Long
Sie füllt die benutzerdefinierte Variable SCROLLINFO mit den bekannten Angaben: aktuelle Position, Minimum und Seitengröße und Maximum. Während die ersteren drei zu eins an die Eigenschaften Min, LargeChange und Value einer ScrollBar weitergegeben werden können, entspricht das Maximum der tatsächlichen Anzahl der vorhandenen ListBox-Elemente. Da jedoch nur bis zum ersten Element der letzten Seite gerollt werden kann, müssen wir die Seitengröße, vermindert um 1, vom Maximum abziehen.
Die Feststellung, ob die ScrollBar gesperrt oder verborgen werden soll, wenn die Anzahl der Elemente in der ListBox unter die Seitengröße fällt, treffen wir anhand der Angabe der Seitengröße. Ist die Anzahl kleiner als die Seitengröße, wird die ScrollBar nicht benötigt.
Diese Anpassung der ScrollBar implementieren wir als Hilfsprozedur, da sie von verschiedenen Stellen aus aufgerufen werden muss. Zum einen vom Scroll-Ereignis der ListBox aus, um de aktuelle Position nachzuführen. Aber auch nach dem Hinzufügen oder Entfernen von Elementen muss sie aufgerufen werden, da sich ja dadurch das Maximum ändert. Genauso bei einer Größenänderung der ListBox selbst wird der Aufruf notwendig, da sich hierbei die Seitengröße ändert.
Die Synchronisation in umgekehrter Richtung ist wieder "sau"einfach: Sie brauchen bloß in den Ereignissen Change und Scroll der ScrollBar den TopIndex der ListBox auf den Wert (Value) der ScrollBar zu setzen. Das unschöne Fokus-Blinken der eigenständigen ScrollBar verhindern Sie schließlich noch, indem Sie im GetFocus-Ereignis der ScrollBar den Fokus an die ListBox mit einem Aufruf ihrer SetFocus-Methode weiterreichen.
Private Const SIF_RANGE = &H1
Private Const SIF_PAGE = &H2
Private Const SIF_POS = &H4
Private Const SIF_DISABLENOSCROLL = &H8
Private Const SIF_ALL = SIF_RANGE Or SIF_PAGE Or SIF_POS
Private Const SB_VERT = 1
Public Sub AdjustScrollBar(ListBox As ListBox, _
ScrollBar As Object, _
Optional ByVal ShowHideListBoxScrollBar As Boolean)
Dim nScrollInfo As SCROLLINFO
On Error Resume Next
With nScrollInfo
.cbSize = LenB(nScrollInfo)
.fMask = SIF_ALL
End With
With ListBox
GetScrollInfo .hwnd, SB_VERT, nScrollInfo
ShowScrollBarAPI .hwnd, SB_VERT, ShowHideListBoxScrollBar
End With
With ScrollBar
.Max = nScrollInfo.nMax - nScrollInfo.nPage + 1
.LargeChange = nScrollInfo.nPage
.Value = nScrollInfo.nPos
.Enabled = Not (ListBox.ListCount = nScrollInfo.nPage)
End With
End Sub
Public Sub OnScrollBarScroll(ListBox As ListBox, _
ScrollBar As Object, _
Optional ByVal ShowHideListBoxScrollBar As Boolean)
With ListBox
.TopIndex = ScrollBar.Value
ShowScrollBarAPI .hwnd, SB_VERT, ShowHideListBoxScrollBar
End With
End Sub
|