Bedarfsgerechte Scrollleisten
Die Scrollleisten einer Multiline Textbox dynamisch ein- und ausblenden
Scrollleisten bei einer TextBox anzuzeigen ist kein Problem. Diese aber dynamisch aus- und einzublenden schon eher. Abgesehen davon, dass man die Scrollbars - Eigenschaft nur zur Designtime setzen kann, muss man auch in Erfahrung bringen, wann die Leisten benötigt werden.
Die Scrollbars-Eigenschaft einer TextBox ist zur Laufzeit schreibgeschützt. Wenn
Sie also eine Multiline TextBox in Ihrer Anwendung einsetzen, müssen Sie schon vorher
entscheiden, ob der Anwender Scrollleisten gebrauchen könnte und in Kauf nehmen, dass
diese Scrollleisten immer eingeblendet werden auch wenn sie gar nicht benötigt werden.
Mit einem einfachen Aufruf der API Funktion ShowScrollBar, können Sie jedoch diese Leisten ausblenden:
Private Declare Function ShowScrollBar Lib "user32" _ (ByVal hWnd As Long, ByVal wBar As Long, ByVal bShow As Long) As Long
"hWnd" gibt dabei den Handle des ScrollBar- Control, bzw. des Fensters an, das eine Standard- SrollBar verwendet. Der Parameter "wBar" kann eine der folgenden Konstanten sein, die angeben welche ScrollBar manipuliert werden soll:
Private Const SB_VERT = 1 ' vertikale Scrollleiste Private Const SB_HORZ = 0 ' horizontale Scrollleiste Private Const SB_BOTH = 3 ' beide Scrolleisten
"bShow" gibt dabei an, ob die Scrollleiste angezeigt (True) oder ausgeblendet (False) werden soll.
Soweit alles noch ganz einfach und schnell erledigt. Aber wann werden die Scrollleisten wirklich benötigt und wann nicht? Zur Beantwortung dieser Frage muss man zunächst in Erfahrung bringen, wie viel Platz für den Text in der TextBox zur Verfügung steht. Diesen Wert liefern die Width- bzw. Height- Eigenschaften der TextBox abzüglich des 3D Rahmens, dessen Breite bzw. Höhe Mithilfe der API Funktion GetSystemMetrics ermittelt wird:
lngInnerWidth = TextBox.Width - (GetSystemMetrics(SM_CXEDGE) * 2 + 2) * _ Screen.TwipsPerPixelX lngInnerHeight = TextBox.Height - (GetSystemMetrics(SM_CYEDGE) * 2 + 2) * _ Screen.TwipsPerPixelY
Der Platz für den Text wird aber noch weiter eingeschränkt, wenn gegebenenfalls zusätzlich eine horizontale bzw. vertikale ScrollBar angezeigt werden muss. Hier wird vorweg geprüft, ob der Text in seiner Breite in den vorgegebenen Rahmen passt und wenn erforderlich die Höhe der horizontalen ScrollBar abgezogen:
If (TextBox.ScrollBars = vbHorizontal Or TextBox.ScrollBars = vbBoth) And _ (TextBox.Parent.TextWidth(TextBox.Text)) > lngInnerWidth Then lngInnerHeight = lngInnerHeight - (GetSystemMetrics(SM_CYHSCROLL) * _ Screen.TwipsPerPixelY) End If
Umgekehrt wird überprüft, ob der Text in die vorgegebene Höhe passt und gegebenenfalls die Breite der vertikalen ScrollBar vom vorgegebenen Rahmen abgezogen.
Nach diesen "Vorarbeiten", kann nun ermittelt werden, ob der Text über die vorgegebenen Ränder hinausläuft und die Anzeige von Scrollleisten erforderlich bzw. sinnvoll ist. Für die Anzeige der vertikalen ScrollBar wird die Höhe einer Textzeile Mithilfe der TextHeight - Methode des TextBox- Parent ermitteln, was voraussetzt das beide die gleichen Font- Einstellungen haben. Der so ermittelte Wert wird mit der Anzahl der in der TextBox enthaltenen Zeilen ermittelt, was über SendMessage und EM_GETLINECOUNT geschieht. Ist diese Summe größer, als der zur Verfügung stehende Rahmen, ist die Anzeige einer vertikalen ScrollBar erforderlich:
lngLines = SendMessage(TextBox.hWnd, EM_GETLINECOUNT, 0, ByVal 0&) If (TextBox.Parent.TextHeight("Xy") * (lngLines)) > lngInnerHeight Then ShowScrollBar TextBox.hWnd, SB_VERT, True Else ShowScrollBar TextBox.hWnd, SB_VERT, False End If
Für die horizontale ScrollBar muss nur die Textbreite, die mit der TextWidth-Methode ermittelt wird, mit der zur Verfügung stehenden Breite verglichen werden:
If (TextBox.Parent.TextWidth(TextBox.Text)) > lngInnerWidth Then ShowScrollBar TextBox.hWnd, SB_HORZ, True Else ShowScrollBar TextBox.hWnd, SB_HORZ, False End If
Übersichtlich und handlich in einer Prozedur verpackt:
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _ lParam As Any) As Long Private Const EM_GETLINECOUNT = &HBA Private Declare Function ShowScrollBar Lib "user32" (ByVal hWnd As Long, _ ByVal wBar As Long, ByVal bShow As Long) As Long Private Const SB_VERT = 1 Private Const SB_HORZ = 0 Private Declare Function GetSystemMetrics Lib "user32" _ (ByVal nIndex As Long) As Long Private Const SM_CXVSCROLL = 2 Private Const SM_CYHSCROLL = 3 Private Const SM_CXEDGE = 45 Private Const SM_CYEDGE = 46 Public Sub ScrollsAutoHide(ByRef TextBox As TextBox) Dim lngLines As Long Dim lngInnerWidth As Long Dim lngInnerHeight As Long With TextBox lngInnerWidth = .Width - (GetSystemMetrics(SM_CXEDGE) * 2 + 2) * _ Screen.TwipsPerPixelX lngInnerHeight = .Height - (GetSystemMetrics(SM_CYEDGE) * 2 + 2) * _ Screen.TwipsPerPixelY If (.ScrollBars = vbHorizontal Or .ScrollBars = vbBoth) Then If (.Parent.TextWidth(.Text)) > lngInnerWidth Then lngInnerHeight = lngInnerHeight - (GetSystemMetrics(SM_CYHSCROLL) * _ Screen.TwipsPerPixelY) End If End If If (.ScrollBars = vbVertical Or .ScrollBars = vbBoth) Then lngLines = SendMessage(TextBox.hWnd, EM_GETLINECOUNT, 0, ByVal 0&) If (.Parent.TextHeight("Xy") * (lngLines)) > lngInnerHeight Then ShowScrollBar .hWnd, SB_VERT, True lngInnerWidth = lngInnerWidth - (GetSystemMetrics(SM_CXVSCROLL) * _ Screen.TwipsPerPixelY) Else ShowScrollBar .hWnd, SB_VERT, False End If End If If (.ScrollBars = vbHorizontal Or .ScrollBars = vbBoth) Then If (.Parent.TextWidth(.Text)) > lngInnerWidth Then ShowScrollBar .hWnd, SB_HORZ, True Else ShowScrollBar .hWnd, SB_HORZ, False End If End If End With End Sub
Anwendung findet diese Prozedur in zwei Ereignissen, dem Form_Load-Ereignis und dem Change-Ereignis der entsprechenden TextBox:
Private Sub Form_Load() ScrollsAutoHide Text1 End Sub Private Sub Text1_Change() ScrollsAutoHide Text1 End Sub
Die ScrollBars-Eigenschaft muss weiterhin zur Designzeit festgelegt werden.
- modScrollAutoHide Modul und Beispielprojekt (scrollhide.zip - 3 KB)