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.
|