ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 26.07.2002

Diese Seite wurde zuletzt aktualisiert am 26.07.2002
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Fokus zu Fuß

Zurück...


Anzeige

(-hg) mailto:hg_stepfocus@aboutvb.de

Visual Basic macht es Ihnen als Entwickler recht einfach festzulegen, in welcher Reihenfolge die Steuerelemente auf einem Form angesprungen werden sollen, wenn der Anwender den Eingabe-Fokus mit der Tabulator-Taste weiterbewegt. Doch wenn Sie diese Fokus-Verschiebung selbst per Code erledigen oder exakt kontrollieren möchten, oder wenn Sie die Tabulator-Taste zweckentfremden wollen, lässt Visual Basic Sie im Stich.

Welche Steuerelemente per Tabulator-Taste den Fokus erhalten können und deren Reihenfolge legen Sie gewöhnlich über die Eigenschaften TabStop und TabIndex fest. Es ist jedoch gar nicht so einfach, den Nachfolger eines Steuerelements innerhalb dieser Reihenfolge zu ermitteln. Zunächst einmal müssen Sie ermitteln, welche Steuerelemente überhaupt den Fokus erhalten können. Visual Basic stellt Ihnen zwar die Controls-Collection eines Forms zur Verfügung, die aber einfach alle Steuerelemente enthält - von Fokus-fähigen Steuerelementen (Schaltflächen, TextBoxen usw.) über Menüs und grafische Elemente (wie Line und Shape) bis hin zu unsichtbaren Hilfssteuerelementen (wie Timer und Common Dialog).

Das erste Filterkriterium für eine reduzierte Sammlung ist die Eigenschaft TabIndex. Leider können Sie ein Steuerelement nicht direkt fragen, ob es die TabIndex-Eigenschaft anzubieten hat. Statt dessen müssen Sie einen Zugriff versuchen und über eine Kontext-Fehlerbehandlung (per On Error Resume Next) Fehlversuche registrieren:

Dim nControl As Control
Dim nTabIndex As Integer

On Error Resume Next
For Each nControl in Controls
  nTabIndex = nControl.TabIndex
  If Err.Number Then
    Err.Clear
  Else
    ' Control hat TabIndex-Eigenschaft:
    Debug.Print nControl.Name, nControls.TabIndex
  End If
Next

Ihnen wird sicher schnell auffallen, dass die Reihenfolge der Steuerelemente in der Controls-Collection absolut nichts mit der TabIndex-Reihenfolge zu tun hat: Die Ausgaben in oben stehender Schleife erfolgen bezüglich der TabIndex-Reihenfolge wild durcheinander (Tatsächlich hängt die Reihenfolge in der Controls-Collection letztlich von der ZOrder-Reihung ab). Um die Aufgabe erfüllen zu können, einen Nachfolger in der TabIndex-Reihenfolge ausfindig zu machen, werden Sie noch eine Sortierung vornehmen müssen.

Die Ausgaben der Schleife zeigen aber auch, dass es Steuerelement-Klassen gibt, die zwar über die TabIndex-Eigenschaft verfügen, aber wohl nicht den Fokus erhalten können. Dazu gehören das Label-Steuerelement, aber auch UserControls, bei denen die Eigenschaft ForwardFocus gesetzt worden ist. Derartige Steuerelemente dienen in der Regel dazu, Tastatur-Kürzel (Alt+[Taste]) anzunehmen und das in der TabIndex-Reihenfolge nachfolgende Steuerelement zu aktivieren (Sie sehen: intern hat Visual Basic die Aufgabe längst gelöst - die Lösung wird leider nur nicht offen gelegt). Das Merkmal zur Unterscheidung dieser Steuerelemente von denjenigen, die tatsächlich den Fokus erhalten können, liegt in der TabStop-Eigenschaft. Ist diese bei einem Steuerelement verfügbar, kann es den Fokus erhalten - grundsätzlich jedenfalls.

Erweitern wir also nun unsere Schleife um dieses weitere Filterkriterium:

Dim nControl As Control
Dim nTabIndex As Integer
Dim nTabStop As Boolean

On Error Resume Next
For Each nControl In Controls
  With nControl
    nTabIndex = .TabIndex
    If Err.Number = 0 Then
      nTabStop = .TabStop
      If Err.Number = 0 Then
        ' TabIndex und TabStop vorhanden:
        Debug.Print .Name, .TabIndex, .TabStop
      End If
    End If
  End With
  Err.Clear
Next 'i

Hier verkürzen wir die Fehlerauswertung. Wir beschränken uns auf die fehlerfreien Fälle und setzen das Err-Objekt nur einmal zum Ende eines Schleifendurchlaufs zurück, um das Err-Objekt für den nächsten Schleifendurchlauf zu neutralisieren.

Wie Ihnen bekannt sein sollte, können Sie Steuerlemente aus der TabIndex-Reihenfolge herausnehmen, indem Sie die TabStop-Eigenschaft auf False setzen. Diese Steuerelemente können dann den Fokus nur noch auf direktem Wege erhalten (etwa durch Anklicken), aber nicht mehr über die Tabulator-Taste. Der Wert der TabStop-Eigenschaft bildet also ein weiteres Filterkriterium.

Das nächste Filterkriterium stellt die Sichtbarkeit eines Steuerelements dar. Ein unsichtbares Steuerelement kann nun einmal nicht den Fokus erhalten. Die Abfrage der Visible-Eigenschaft hat aber auch wieder mit der Tücke zu kämpfen, dass nicht jedes Steuerelement damit aufwartet - etwa ein Timer oder ein UserControl, bei dem die Eigenschaft InvisibleAtRuntime gesetzt ist. Auch hier müssen Sie wieder den Weg über Versuch und Irrtum gehen.

Als letztes Filterkriterium bleibt noch die Enabled-Eigenschaft übrig. Nur ungesperrte Steuerelemente können den Fokus erhalten. Wenn Sie nun meinen, dass alle Steuerelemente, die den Fokus erhalten können, über die Enabled-Eigenschaft verfügen, unterliegen Sie einer Täuschung. Dies gilt zwar für alle Visual Basic-eigenen Steuerelemente und auch für die meisten externen Steuerelemente (OCXe). Doch gibt es hin und wieder Hersteller von Steuerelementen, die in diesem Punkt schlampen. Und, Hand auf's Herz: Denken Sie selbst auch immer daran, Ihren eigenen auf UserControl-Basis erstellten Steuerelementen eine Enabled-Eigenschaft zu verpassen? Immerhin: Auch wenn die Enabled-Eigenschaft fehlt, wird vielleicht trotzdem das Fenster-Handle des Steuerelements offen gelegt (hWnd-Eigenschaft o.ä.). Dann können Sie ersatzweise die API-Funktion IsWindowEnabled mit dem Handle füttern und so in Erfahrung bringen, ob das Steuerelement eventuell gesperrt ist. Fehlen allerdings beide Eigenschaften, bleibt Ihnen zunächst kaum etwas anderes übrig, als vorläufig anzunehmen, dass das Steuerelement den Fokus erhalten kann, und erst beim späteren, tatsächlichen Setzen des Fokus einen Fehlschlag diesbezüglich per Kontext-Fehlerbehandlung abzufangen.

Private Declare Function IsWindowEnabled Lib "user32" _
 (ByVal hwnd As Long) As Long

Dim nControl As Control
Dim nTabIndex As Integer
Dim nTabStop As Boolean
Dim nVisible As Boolean
Dim nEnabled As Boolean
Dim nHWnd As Long
Dim nFocusControls As Collection

Set nFocusControls = New Collection
On Error Resume Next
For Each nControl in Controls
  With nControl
    nTabIndex = .TabIndex
    If Err.Number = 0 Then
      nTabStop = .TabStop
      If Err.Number = 0 Then
        If nTabStop Then
          nVisible = .Visible
          If Err.Number = 0 Then
            If nVisible Then
              nEnabled = .Enabled
              If Err.Number Then
                nHWnd = .hWnd
                If Err.Number Then
                  ' Control kann prinzipiell den Fokus erhalten
                  ' Enabled-Zustand nicht ermittelbar
                  nFocusControls.Add nControl
                Else
                  If IsWindowEnabled(nHWnd) Then
                    ' Control kann den Fokus erhalten
                    nFocusControls.Add nControl
                  End If
                End If
              Else
                If nEnabled Then
                  ' Control kann den Fokus erhalten
                  nFocusControls.Add nControl
                End If
              End If
            End If
          End If
        End If
      End If
    End If
  End With
  Err.Clear
Next 'i

Somit hätten wir nun eine Liste (Collection), die alle Steuerelemente enthält, die aktuell den Fokus erhalten können (wie gesagt: einschließlich der eventuellen Fälle, in denen der Enabled-Zustand noch nicht eindeutig ermittelbar gewesen ist).

Diese Liste hilft Ihnen allerdings noch nicht viel weiter. Die Ermittlung der aktuell Fokus-fähigen Steuerelemente war nämlich erst die halbe Miete. Die Frage lautete ja, wie Sie den Nachfolger eines gegebenen Steuerelements in der TabIndex-Reihenfolge ausfindig machen können. Nun könnten Sie die Collection nachträglich sortieren, oder Sie könnten die ermittelten Steuerelemente gleich richtig sortiert in die Collection einfügen. Allerdings ist an dieser Stelle beides wenig hilfreich. Denn Sie können den Aufwand dafür auch in die folgende Ermittlung des Nachfolgers stecken. Damit Sie die in die Collection eingefügten Steuerelemente später anhand ihres TabIndex-Wertes identifizieren können, brauchen Sie sie lediglich mit dem TabIndex-Wert als Schlüssel in die Collection einzufügen. Doch Vorsicht: Der Wert ist ein Integer-Wert und würde von der Collection als Index und nicht als Schlüssel interpretiert werden. Sie müssen den TabIndex-Wert mittels CStr ausdrücklich in einen String konvertieren. Ändern Sie also in der Schleife alle Einfügungen eines Steuerelements in die Collection wie folgt:

nFocusControls.Add nControl, CStr(nTabIndex)

Apropos "Nachfolger": Bisher war immer nur die Rede vom Nachfolger in der TabIndex-Reihenfolge. Genau so ist natürlich die Ermittlung des Vorgängers sinnvoll - etwa zum Rückwärtsmarschieren in der TabIndex-Reihenfolge. Denken Sie also von nun an den Nachfolger im Sinne des Nachfolgers in der jeweiligen Marschrichtung.

Bevor wir uns nun mit der eigentlichen Ermittlung des Nachfolgers befassen, möchte ich ein paar Überlegungen zu verschiedenen Anwendungsfällen einschieben und zu sich eventuell daraus ergebenden weiteren zu berücksichtigenden "Kleinigkeiten".

Im einfachsten Fall soll unsere Lösung tatsächlich nur dazu dienen, den direkten Nachfolger oder Vorgänger zu einem gegebenen Steuerelement ermitteln. Dabei sollte es unerheblich sein, ob das gegebene Steuerelement selbst aktuell den Fokus erhalten könnte. Denn es könnte sich um ein Label handeln, oder es könnte unsichtbar oder gesperrt sein, oder TabStop könnte auf False gesetzt sein. Einzige Bedingung wäre, dass es über die TabIndex-Eigenschaft verfügt - anderenfalls wäre es ja unmöglich, einen Nachfolger oder Vorgänger in der TabIndex-Reihenfolge zu finden.

Vor der Rechenzeit raubenden Zusammenstellung der Liste der aktuell Fokus-fähigen Steuerelemente prüfen Sie also zuerst letzteres (StartControl = gegebenes Steuerelement):

Dim nTabIndex As Integer

On Error Resume Next
nTabIndex = StartControl.TabIndex
If Err.Number = 0 Then
  ' ... Liste zusammenstellen
End If

Wie Eingangs erwähnt könnte eine der Anwendungsmöglichkeiten der Ersatz der Visual Basic-eigenen Tabulator-Reihenfolge sein. Wenn Ihre Anwendung beispielsweise darauf angewiesen ist, dass das KeyDown-Ereignis (etwa in Form_KeyDown, wenn die KeyPreview-Eigenschaft des Forms gesetzt haben) auch beim Betätigen der Tabulator-Taste ausgelöst wird, müssen Sie den VB-Mechanismus außer Kraft setzen. Dazu setzen Sie die TabStop-Eigenschaft bei allen Controls auf False. Die TabIndex-Eigenschaften bleiben davon unberührt, so dass das Weiterreichen des Fokus per Code zum einem von unserer Lösung ermittelten Nachfolger ohne weiteres möglich bleibt. Lediglich die eigentliche Funktion des Ausklammerns einzelner Steuerelemente aus der Kette entfällt. der Einfachheit halber können Sie statt dessen die auszuklammernden Steuerelemente ans Ende der TabIndex-Reihenfolge schieben. In unsere Schleife fügen Sie eine Bedingung ein, die Steuerelemente mit einem TabIndex oberhalb eines bestimmten Grenzwertes ("MaxTabIndex") nicht mehr einfügt. Zusätzlich kann die Prüfung des TabStop-Wertes entfallen oder in der Prüfung kommt eine zusätzlich zu setzende Variable "IgnoreTabStopValues" hinzu:

  ' ...
  With nControl
    nTabIndex = .TabIndex
    If Err.Number = 0 Then
      If nTabIndex <= MaxTabIndex Then
        nTabStop = .TabStop
        If Err.Number = 0 Then
          If nTabStop Or IgnoreTabStopValues Then
            nVisible = .Visible
            ' ...

Nebenbei sollten Sie noch den Wert des höchsten tatsächlich aufgenommenen TabIndex ermitteln, um die spätere Suche nach dem Nachfolger zu vereinfachen. Damit der Code dazu nicht an allen drei Einfügestellen wiederholt zu werden braucht, wird das mitsamt dem Einfügen an einer zentralen Stelle erledigt. Dazu wird in der Variablen nSet festgehalten, ob eingefügt werden soll. Eine vollständige Funktion zur Ermittlung der Liste der aktuell Fokus-fähigen Steuerelemente könnte nun so aussehen:

Function FocusControls(ParentControls As Object, _
 TopTabIndex As Integer, _
 Optional ByVal MaxTabIndex As Integer = -1, _
 Optional IgnoreTabStopValues As Boolean) As Collection

  Dim nControl As Control
  Dim nTabIndex As Integer
  Dim nTabStop As Boolean
  Dim nVisible As Boolean
  Dim nEnabled As Boolean
  Dim nHWnd As Long
  Dim nSet As Boolean
  
  If MaxTabIndex = -1 Then
    MaxTabIndex = ParentControls.Count - 1
  End If
  Set FocusControls = New Collection
  On Error Resume Next
  For Each nControl In ParentControls
    With nControl
      nTabIndex = .TabIndex
      If Err.Number = 0 Then
        If nTabIndex <= MaxTabIndex Then
          nTabStop = .TabStop
          If Err.Number = 0 Then
            If nTabStop Or IgnoreTabStopValues Then
              nVisible = .Visible
              If Err.Number = 0 Then
                If nVisible Then
                  nEnabled = .Enabled
                  If Err.Number Then
                    nHWnd = .hwnd
                    If Err.Number Then
                      nSet = True
                    Else
                      If IsWindowEnabled(nHWnd) Then
                        nSet = True
                      End If
                    End If
                  Else
                    If nEnabled Then
                      nSet = True
                    End If
                  End If
                End If
              End If
            End If
          End If
          If nSet Then
            If nTabIndex > TopTabIndex Then
              TopTabIndex = nTabIndex
            End If
            FocusControls.Add nControl, CStr(nTabIndex)
          End If
        End If
      End If
    End With
    Err.Clear
    nSet = False
  Next 'i
End Sub

Bei fehlenden TabStops kommt hinzu, dass Visual Basic beim Deaktivieren eines Forms (d.h. ein anderes Form wird aktiviert) vergisst, welches Steuerelement zuletzt den Fokus inne hatte. Beim Reaktivieren des Forms wird der Fokus stur auf das erste Fokus-fähige Steuerelement gesetzt. Sicher ist es ein Leichtes, in einer Variablen das Steuerelement abzulegen, das beim Deaktivieren zuletzt den Fokus inne hatte, und beim Reaktivieren (im Form_Activate-Ereignis) über diese Variable den Fokus wieder zu setzen. Das Nachhalten, welches Steuerelement zuletzt den Fokus inne hatte, ist ja kein Problem, da unsere Lösung das Steuerelement zurückgeben kann, dem sie den Fokus zugewiesen hat. Beim Zuweisen des Fokus im Form_Activate-Ereignis könnte es jedoch sein, dass das in jener Variablen nachgehaltene Steuerelement gar nicht mehr den Fokus erhalten kann, etwa weil es mittlerweile unsichtbar geworden oder gesperrt worden sein könnte. Eine kleine Verfeinerung unserer Lösung wäre also, dass sie auf Wunsch zunächst versuchen könnte, den Fokus auf ein gegebenes Steuerelement zu setzen. Und dass nur dann, wenn dies fehlschlagen sollte, dessen Nachfolger ermittelt und diesem der Fokus zugewiesen wird:

On Error Resume Next
StartControl.SetFocus
If Err.Number Then
  ' ... Nachfolger ermitteln
End If

Kommen wir nun zur eigentlichen Ermittlung des Nachfolgers. Da die Fokus-fähigen Steuerelemente in der Collection der unsortiert eingefügt worden sind, wird die Collection anhand der Schlüssel durchgegangen. Die Suche des Nachfolgers beginnt aufsteigend beim Wert des TabIndex des gegebenen Steuerelement plus 1 bis zum mit der Ermittlung der Liste zugleich ermittelten höchsten vorkommenden TabIndex, die Suche des Vorgängers absteigend beim Wert des TabIndex des gegebenen Steuerelement minus 1 bis zum TabIndex 0. Weil in der Liste diejenigen Steuerelemente nicht alle TabIndex-Werte enthalten sind, wird nicht zu jedem TabIndex-Wert der Schleife ein Steuerelement gefunden. Per Kontext-Fehlerbehandlung werden diese Lücken einfach übersprungen.

Da wir es bei der TabIndex-Reihenfolge eigentlich mit einer umlaufenden Liste zu tun haben (auf das letzte Steuerelement folgt wieder das erste nach, bzw. dem ersten Steuerelement geht das letzte voraus), kann es vorkommen, dass beim ersten Durchgang noch kein Nachfolger (je nach Richtung) gefunden wird. Darum ist gegebenenfalls ein zweiter Durchgang erforderlich, bei dem der zuvor ausgeklammerte Rest durchsucht wird - aufsteigend also beginnend bei TabIndex = 0 bis zum TabIndex des gegebenen Steuerelements minus 1, bzw. absteigend vom höchsten vorkommenden TabIndex bis zum TabIndex des Steuerelements plus 1. War danach die Suche immer noch erfolglos, wird der Fokus nicht verändert und es wird das Ausgangssteuerelement zurückgegeben.

Wie bei der Ermittlung der Fokus-fähigen Steuerelemente erwähnt, kann die Liste immer noch Steuerelemente erhalten, für die nicht eindeutig festgestellt werden konnte, ob sie tatsächlich den Fokus erhalten können. Beim Setzen des Fokus wird also auch hier mit einer Kontext-Fehlerbehandlung ein mögliches Scheitern abgefangen. Im Falle des Scheiterns wird die Suche einfach weiter fortgesetzt. Als Option fügen wir hier noch die Möglichkeit ein, den Fokus nicht sofort zu setzen, sondern nur das gefundene Steuerelement zurückzugeben. Die letztendliche Erfolgsprüfung, ob das Steuerelement den Fokus wirklich erhalten kann, müsste dann irgendwo außerhalb erfolgen, wenn der Fokus gesetzt werden soll. Bei einem Fehlschlagen dort kann dieses Steuerelement als Ausgangspunkt zu einer erneuten Suche des nächstmöglichen Steuerelements verwendet werden.

Da Sie beim erstmaligen Anzeigen eines Forms wahrscheinlich noch gar kein gegebenes Ausgangssteuerelement zur Verfügung haben werden, können Sie statt dessen auch Nothing übergeben. Dann wird automatisch das erste Steuerelement in der Liste als Ausgangssteuerelement verwendet.

Function SetFocusControl(Controls As Collection, _
 Control As Control, ByVal TopTabIndex As Integer, _
 ByVal DoSetFocus As Boolean, _
 Optional ByVal Forward As Boolean = True) As Control

  Dim nStartControl As Control
  Dim nStartControlTabIndex As Integer
  Dim i As Integer
  Dim nControl As Control
  Dim ii As Integer
  Dim nStart As Integer
  Dim nEnd As Integer
  Dim nStep As Integer
  
  On Error Resume Next
  If Control Is Nothing Then
    For i = 0 To TopTabIndex
      Set nStartControl = Controls(CStr(i))
      If Err.Number = 0 Then
        Exit For
      End If
      Err.Clear
    Next
  Else
    Set nStartControl = Control
  End If
  nStartControlTabIndex = nStartControl.TabIndex
  Select Case Forward
    Case True
      nStart = nStartControlTabIndex + 1
      nEnd = TopTabIndex
      nStep = 1
    Case False
      nStart = nStartControlTabIndex - 1
      nEnd = 0
      nStep = -1
  End Select
  For ii = 1 To 2
    For i = nStart To nEnd Step nStep
      Set nControl = Controls(CStr(i))
      If Err.Number = 0 Then
        If DoSetFocus Then
          nControl.SetFocus
          If Err.Number Then
            Set nControl = Nothing
          End If
        End If
        If Not (nControl Is Nothing) Then
          Set SetFocusControl = nControl
          Exit Function
        End If
      End If
      Err.Clear
    Next 'i
    Select Case Forward
      Case True
        nStart = 0
        nEnd = nStartControlTabIndex - 1
        nStep = 1
      Case False
        nStart = TopTabIndex
        nEnd = nStartControlTabIndex + 1
        nStep = -1
    End Select
  Next 'ii
  Set SetFocusControl = nStartControl
End Function

Damit hätten Sie nun das notwendige Rüstzeug zur Nachfolger-Ermittlung zusammen. Die einzelnen Schritte zur Suche nach einem Nachfolger und einem Vorgänger haben wir in zwei separaten Funktionen zusammengefasst. Sie übergeben beim Aufruf jeweils das Ausgangssteuerelement (oder Nothing) und die Controls-Collection des jeweiligen Forms. Mit dem Parameter MaxTopIndex legen Sie optional den höchsten TabIndex fest, wenn Steuerelemente oberhalb dieses Wertes den Fokus nicht erhalten sollen. Sollen die TabStop-Werte ignoriert werden, weil sie etwa sowieso alle False sind, setzen Sie (optional) den Parameter IgnoreTabStopValues auf True. Mit DoSetFocus legen Sie fest, ob der Fokus gleich gesetzt werden soll, oder ob das ermittelte Steuerelement lediglich zurückgegeben werden soll. Mit TryFocus können Sie schließlich noch angeben, ob zuerst versucht werden soll, den Fokus auf das Ausgangssteuerelement zu setzen.

Public Function NextFocus(Control As Control, _
 Controls As Object, _
 Optional ByVal MaxTabIndex As Integer = -1, _
 Optional IgnoreTabStopValues As Boolean, _
 Optional ByVal DoSetFocus As Boolean = True, _
 Optional ByVal TryFocus As Boolean) As Control

  Dim nControls As Collection
  Dim nTabIndex As Integer
  Dim nTopTabIndex As Integer

  On Error Resume Next
  If Control Is Nothing Then
    If TryFocus Then
      Exit Function
    End If
  Else
    nTabIndex = Control.TabIndex
    If Err.Number Then
      Exit Function
    End If
    If TryFocus Then
      Control.SetFocus
      If Err.Number = 0 Then
        Set NextFocus = Control
        Exit Function
      End If
    End If
  End If
  Set nControls = FocusControls(Controls, nTopTabIndex, _
   MaxTabIndex, IgnoreTabStopValues)
  If nControls.Count Then
    Set NextFocus = SetFocusControl(nControls, Control, _
     nTopTabIndex, DoSetFocus)
  End If
End Function

Public Function PrevFocus(Control As Control, _
 Controls As Object, _
 Optional ByVal MaxTabIndex As Integer = -1, _
 Optional IgnoreTabStopValues As Boolean, _
 Optional ByVal DoSetFocus As Boolean = True) As Control

  Dim nControls As Collection
  Dim nTabIndex As Integer
  Dim nTopTabIndex As Integer

  On Error Resume Next
  If Not (Control Is Nothing) Then
    nTabIndex = Control.TabIndex
    If Err.Number Then
      Exit Function
    End If
  End If
  Set nControls = FocusControls(Controls, nTopTabIndex, _
   MaxTabIndex, True)
  If nControls.Count Then
    Set PrevFocus = SetFocusControl(nControls, Control, _
     nTopTabIndex, DoSetFocus, False)
  End If
End Function

Falls Sie nur die Liste der aktuell Fokus-fähigen Steuerelemente interessiert, können Sie die folgende Funktion verwenden, die praktischerweise die Liste entsprechend der TabIndex-Reihenfolge umsortiert zurückgibt:

Public Function TabIndexControls(Controls As Object, _
 Optional ByVal MaxTabIndex As Integer = -1, _
 Optional ByVal IgnoreTabStopValues As Boolean) As Collection
  Dim nControlsRaw As Collection
  Dim nTopTabIndex As Integer
  Dim i As Integer
  Dim nControl As Control
  
  Set nControlsRaw = FocusControls(Controls, nTopTabIndex, _
   MaxTabIndex, IgnoreTabStopValues)
  If nControlsRaw.Count = 0 Then
    Set TabIndexControls = nControlsRaw
  Else
    Set TabIndexControls = New Collection
    With TabIndexControls
      On Error Resume Next
      For i = 0 To nTopTabIndex
        Set nControl = nControlsRaw(CStr(i))
        If Err.Number Then
          Err.Clear
        Else
          .Add nControl, CStr(i)
        End If
      Next 'i
    End With
  End If
End Function

Abschließend noch zwei Anmerkungen zu UserControls und komplexen Steuerelementen, die selbst mehrere Fokus-fähige Steuerelemente enthalten. Solche Steuerelemente sind aus der Sicht eines VB-Forms (oder anderen VB-Containers) lediglich ein einzelnes Steuerelement. Der Fokus wird an sie weitergegeben, und sie selbst verwalten ihre eigene interne TabIndex-Reihenfolge und -Steuerung. Da sie bei fremden Steuerelementen keine Eingriffsmöglichkeit haben, können Sie deren interne Fokus-Steuerung auch nicht beeinflussen. Bei selbst geschriebenen UserControls ist unsere Lösung leider nur eingeschränkt einsetzbar. Sie können für einzelne Steuerelemente ohne weiteres den Vorgänger oder Nachfolger ermitteln (hier übergeben Sie statt der Form.Controls-Collection die UserControl.Controls-Collection). Doch die Kontrolle der Tabulator-Taste per KeyPreview und durch Ausschalten der TabStops lässt sich offensichtlich nicht erlangen.


Beispiel-Projekt und Modul modStepFocus (stepfocus.zip - ca. 7,3 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer