Visual Basic - Technik, FAQ, Tricks, Beispiele

Home / Objekte / Controls / Fokus

Nächstes Control in Tab-Reihenfolge finden

Problem

In manchen Situationen ist es notwendig, das nächste Control in der Tab-Reihenfolge zu finden, z.B. wenn bei Druck auf Return auf das nächste Eingabefeld gesprungen werden soll. Oft wird in so einem Fall SendKeys benutzt, um ein Druck auf die Tabulator-Taste zu generieren, etwa so:

Private Sub txtEingabe_KeyPress(KeyAscii As Integer)
  If KeyAscii = vbKeyReturn Then SendKeys "{Tab}"
End Sub

Dies hat jedoch einige Nachteile, z.B. wird u.U. der Status der Num-Taste geändert.

Lösung

Mit den unten gezeigten Routinen ist es möglich, das Control zu bestimmen, welches als nächstes den Fokus erhalten soll. Dann reicht es im obigen Beispiel folgendes zu schreiben:

Private Sub txtEingabe_KeyPress(KeyAscii As Integer)
  If KeyAscii = vbKeyReturn Then JumpNextControl
End Sub

Stört ein nervender Piepton oder soll der Tastendruck für das gesamte Formular gelten? Dann empfehle ich unbedingt folgenden Artikel: Bei Enter: Aktion statt Beep!

Code

Die erste Funktion gibt für ein Control an, ob es überhaupt den Fokus via Tabulator erhalten kann. Dazu muss er u.a. sichtbar (Visible) und aktivierbar (Enabled) sein. Ausserdem darf er kein Container sein (wird via Error-Handler und ClipControls-Eigenschaft festgestellt):

Public Function IsFocusable( _
    ByRef ctl As Control _
  ) As Boolean
  On Error Resume Next
  
  'Auf Fokussierbarkeit prüfen:
  If Not ctl.TabStop Then Exit Function
  If Not ctl.Visible Then Exit Function
  If Not ctl.Enabled Then Exit Function
  
  'Nur nicht-Container berücksichtigen:
  If ctl.ClipControls <> ctl.ClipControls _
  Then IsFocusable = True
  
  On Error GoTo 0
End Function

Die folgende Funktion benutzt IsFocusable, um das nächste Control in der Tab-Reihenfolge zu finden. Es wird dabei genau das Control auf dem Formular frm gesucht, dessen TabIndex größer als TabMin ist, aber kleiner als alle anderen:

Public Function FindNextControl( _
    ByRef frm As Form, _
    ByVal TabMin As Long _
  ) As Control
  Dim ctl As Control
  Dim TabMax As Long
  
  TabMax = 32767 'Maximaler TabIndex
  For Each ctl In frm.Controls

    With ctl

      'Control auf Eignung als Kandidat prüfen:
      If IsFocusable(ctl) Then
      
        'TabIndex des Kandidaten checken:
        Select Case .TabIndex
        Case TabMin To TabMax
          'Kandidat merken:
          Set FindNextControl = ctl
          TabMax = .TabIndex
        End Select
      
      End If 'IsFocusable(ctl)

    End With 'ctl

  Next ctl
End Function

Die eigentliche Haupt-Routine kann mit einem optionalen Parameter aufgerufen werden, der entweder das Formular oder Steuerelement angibt, wo die Suche gestartet werden soll. Wird ActiveObject nicht angegeben, so wird automatisch das aktuelle Control des aktuellen Formulars verwendet.

Public Sub JumpNextControl( _
    Optional ByRef ActiveObject As Object _
  )
  Dim frm As Form
  Dim ctl As Control
  Dim ctlFokus As Control
  
  'Aktuelles Control bestimmen:
  If ActiveObject Is Nothing Then
    Set frm = Screen.ActiveForm
    Set ctl = frm.ActiveControl
  ElseIf TypeOf ActiveObject Is Form Then
    Set frm = ActiveObject
    Set ctl = frm.ActiveControl
  ElseIf TypeOf ActiveObject Is Control Then
    Set ctl = ActiveObject
    Set frm = ctl.Parent
  Else
    Err.Raise 5 'Invalid procedure call or argument
  End If
  
  'Nächst größeren TabIndex suchen:
  Set ctlFokus = FindNextControl(frm, ctl.TabIndex + 1)
  
  'Ggf. kleinsten TabIndex suchen:
  If ctlFokus Is Nothing _
  Then Set ctlFokus = FindNextControl(frm, 0)
  
  'Bei Erfolg Fokus setzen:
  If Not ctlFokus Is Nothing _
  Then ctlFokus.SetFocus
End Sub

Man beachte, dass erst nach dem Control mit dem nächst größeren TabIndex gesucht wird. Falls kein solches Control existiert, wird der kleinste gültige TabIndex berücksichtigt. Das entsprechende Control erhält dann ggf. den Fokus.

© Jost Schwider, 19.03.2001-19.03.2001 - http://vb-tec.de/ctltab.htm