RSS
StartseiteKnowledge LibraryTop 10Impressum

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.