|
Einen gewissen Komfort bieten ComboBoxen und ListBoxen ja. Sie
können mit der Eingabe eines Zeichens in das Eingabefeld der
ComboBox den ersten Listeneintrag vorauswählen, der mit diesem
Zeichen beginnt. Bei einer ListBox wählt die Eingabe eines Zeichens
den ersten mit diesem Zeichen beginnenden Listeintrag direkt aus.
Aber wirklich komfortabel ist das nicht. In vielen Anwendungen
können Sie statt dessen auch mehrere Zeichen hintereinander
eingeben, woraufhin der erste Listeneintrag ausgewählt wird, der
mit dieser Zeichenfolge beginnt. Und dazu wird Ihre Eingabe zur
vollen Länge des gefundenen Listeneintrags ergänzt. Sie können
jedoch ihre Eingabe um weitere Zeichen ergänzen, wobei weiter nach
dem ersten dazu passenden Listeneintrag gesucht wird.
Das Standardverhalten der Tastatureingabe einer ComboBox oder
einer TextBox (die in Verbindung mit einer ListBox verwendet wird),
läuft dieser Auswahltechnik jedoch völlig zuwider. Die
Tastatureingaben müssen ziemlich stark uminterpretiert werden,
damit das erwünschte Verhalten erzielt wird. Dies haben wir für
Sie erledigt - Sie können die drei Prozeduren ComboSIKeyDown,
ComboSIKeyPress und ComboSIKeyUp einfach aus den entsprechenden
Ereignissen einer ComboBox aufrufen. Als ersten Parameter übergeben
Sie die betreffende ComboBox und reichen die weiteren Parameter der
Ereignisse (KeyCode und Shift bzw. KeyPress) an diese Prozeduren
weiter. Im jeweils letzten Parameter können Sie optional eine
String-Variable angeben, die als Zwischenspeicher für die
eingegebene Zeichenfolge dient. Lassen Sie diese Variable weg, wird
die Tag-Eigenschaft der ComboBox zur Zwischenspeicherung verwendet.
Im vorletzten, optionalen Parameter AllowAny bei ComboSIKeyPress
und ComboSIKeyUp können Sie angeben, ob nicht mit überhaupt
irgendeinem Listeneintrag übereinstimmende Zeichenfolgen nach der
Eingabe erscheinen sollen. Standardmäßig erscheinen nicht zu einem
Fund führende Zeichen nicht - wird keine einzige Übereinstimmung
gefunden, wird der Inhalt des Eingabefeldes gelöscht.
Die Tastaturbedienung weicht naturgemäß ein wenig von dem
Standard für Eingabefelder ab. Die Funktionen zur Erweiterung der
Markierung machen hier wenig Sinn. Lediglich Die Pos1- und Endtasten
haben zusammen mit der Strg-Taste eine Bedeutung - sie setzen den
ListIndex auf den Anfang bzw. an das Ende der Liste. Die
Rückschritttaste löscht nicht, sondern fungiert wie eine
Pfeil-Links-Taste. Die Entfernen-Taste löscht zwar zunächst nur
den markierten Bereich - da dies jedoch wohl meistens dazu führen
dürfte (falls Sie nicht ausdrücklich AllowAny gesetzt haben
sollten), dass der Inhalt des Eingabefeldes mit keinem Listeneintrag
mehr übereinstimmt, wird dann auch dessen ganzer Inhalt gelöscht.
Mit der Prozedur ComboSIClear können Sie den ganzen Mechanismus
zurücksetzen. Das Eingabefeld wird gelöscht, der Inhalt der
Tag-Eigenschaft bzw. der Zwischenspeicher-Variablen ebenfalls.
Setzen Sie den optionalen Parameter ResetListIndex auf True, wird
der ListIndex auf -1 gesetzt - es ist also kein Element
mehr ausgewählt.
Übrigens wird sicher gestellt, dass durch jede Eingabe, die zu
einem Treffer in der Liste führt, das Click-Ereignis der ComboBox
ausgelöst wird. Sie können es ja gegebenenfalls einfach
ignorieren.
Die Prozeduren TextSIKeyDown, TextSIKeyPress, TextSIKeyUp und
TextSIClear sind vom Code her nahezu identisch. Sie unterscheiden
sich lediglich darin, dass Sie statt einer ComboBox eine TextBox und
die mit dieser verbundenen ListBox als Parameter übergeben müssen
und daher die entsprechenden Zuordnungen im Code zwangsläufig
abweichend sind. Den Code dieser Prozeduren finden Sie im Modul
modComboListSelInput.bas, das Sie zu diesem Artikel herunterladen
können.
Option Compare Text
Private Declare Function SendMessageStr Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As String) As Long
Private Const CB_ERR = (-1)
Private Const CB_FINDSTRING = &H14C
Private Const CB_FINDSTRINGEXACT = &H158
Private Const LB_ERR = (-1)
Private Const LB_FINDSTRING = &H18F
Private Const LB_FINDSTRINGEXACT = &H1A2
Public Sub ComboSIKeyDown(Combo As ComboBox, _
KeyCode As Integer, Shift As Integer, _
Optional Store As Variant)
Dim nLen As Integer
With Combo
Select Case KeyCode
Case vbKeyLeft
If Shift Then
KeyCode = 0
Else
If IsMissing(Store) Then
nLen = Len(.Tag) - 1
If nLen > -1 Then
.Tag = Left$(.Text, nLen)
End If
Else
nLen = Len(Store) - 1
If nLen > -1 Then
Store = Left$(.Text, nLen)
End If
End If
End If
Case vbKeyRight
If Shift Then
KeyCode = 0
Else
If IsMissing(Store) Then
.Tag = Left$(.Text, Len(.Tag) + 1)
Else
Store = Left$(.Text, Len(Store) + 1)
End If
End If
Case vbKeyHome
Select Case Shift
Case vbCtrlMask
If .ListCount Then
.ListIndex = 0
End If
KeyCode = 0
Case vbShiftMask
KeyCode = 0
End Select
Case vbKeyEnd
Select Case Shift
Case vbCtrlMask
If .ListCount Then
.ListIndex = .ListCount - 1
End If
KeyCode = 0
Case vbShiftMask
KeyCode = 0
End Select
End Select
End With
End Sub
Public Sub ComboSIKeyPress(Combo As ComboBox, _
KeyAscii As Integer, Optional ByVal AllowAny As Boolean, _
Optional Store As Variant)
Dim nSel As Integer
With Combo
Select Case KeyAscii
Case Is >= 32
If IsMissing(Store) Then
.Tag = Left$(.Text, .SelStart + .SelLength) _
& Chr$(KeyAscii)
Else
Store = Left$(.Text, .SelStart + .SelLength) _
& Chr$(KeyAscii)
End If
zShowSel Combo, AllowAny, Store
KeyAscii = 0
Case vbKeyBack
nSel = .SelStart + .SelLength - 1
If IsMissing(Store) Then
If nSel > 0 Then
.Tag = Left$(.Text, nSel)
Else
.Tag = ""
.SelStart = 0
.SelLength = 0
End If
Else
If nSel > 0 Then
Store = Left$(.Text, nSel)
Else
Store = ""
End If
End If
zShowSel Combo, AllowAny, Store
KeyAscii = 0
End Select
End With
End Sub
Public Sub ComboSIKeyUp(Combo As ComboBox, _
KeyCode As Integer, Shift As Integer, _
Optional ByVal AllowAny As Boolean, _
Optional Store As Variant)
With Combo
Select Case KeyCode
Case vbKeyDown, vbKeyUp
.SelStart = 0
.SelLength = Len(.Text)
If IsMissing(Store) Then
.Tag = .Text
Else
Store = .Text
End If
Case vbKeyRight, vbKeyLeft
zShowSel Combo, AllowAny, Store
Case vbKeyEnd
If IsMissing(Store) Then
.Tag = .Text
Else
Store = .Text
End If
zShowSel Combo, AllowAny, Store
Case vbKeyHome
If IsMissing(Store) Then
.Tag = ""
Else
Store = ""
End If
If Shift = vbShiftMask Then
.SelStart = 0
End If
Exit Sub
Case vbKeyDelete
If AllowAny Then
If IsMissing(Store) Then
.Tag = Left$(.Text, .SelStart)
Else
Store = Left$(.Text, .SelStart)
End If
Else
If IsMissing(Store) Then
.Tag = .Text
Else
Store = .Text
End If
If zShowSel(Combo, AllowAny, Store) Then
.Text = ""
If IsMissing(Store) Then
.Tag = ""
Else
Store = ""
End If
End If
End If
End Select
If .SelLength = 0 Then
.ListIndex = -1
End If
End With
End Sub
Private Function zShowSel(Combo As ComboBox, _
Optional ByVal AllowAny As Boolean, _
Optional Store As Variant) As Boolean
Dim nIndex As Long
Dim nIndex2 As Long
Dim nIndex3 As Long
Dim l As Long
With Combo
If IsMissing(Store) Then
nIndex = SendMessageStr(.hwnd, CB_FINDSTRING, -1, .Tag)
If nIndex = CB_ERR Then
If AllowAny Then
.Text = .Tag
.SelStart = Len(.Text)
.SelLength = 0
Else
zShowSel = True
End If
Else
nIndex2 = SendMessageStr(.hwnd, _
CB_FINDSTRINGEXACT, -1, .Tag & Mid$(.Text, _
Len(.Tag) + 1))
If nIndex2 = CB_ERR Then
.ListIndex = nIndex
.Text = .List(nIndex)
Else
If nIndex < nIndex2 Then
For l = nIndex To nIndex2 - 1
If Left$(.List(l), Len(.Tag)) Like .Tag Then
nIndex = l
Exit For
End If
Next
.ListIndex = nIndex
.Text = .List(nIndex)
Else
.ListIndex = nIndex2
.Text = .List(nIndex2)
End If
End If
.SelStart = 0
.SelLength = Len(.Tag)
End If
Else
nIndex = SendMessageStr(.hwnd, CB_FINDSTRING, -1, Store)
If nIndex = CB_ERR Then
If AllowAny Then
.Text = Store
.SelStart = Len(.Text)
.SelLength = 0
Else
zShowSel = True
End If
Else
nIndex2 = SendMessageStr(.hwnd, CB_FINDSTRINGEXACT, _
-1, .Tag & Mid$(.Text, Len(.Tag) + 1))
If nIndex2 = CB_ERR Then
.ListIndex = nIndex
.Text = .List(nIndex)
Else
If nIndex < nIndex2 Then
For l = nIndex To nIndex2 - 1
If Left$(.List(l), Len(Store)) Like Store Then
nIndex = l
Exit For
End If
Next
.ListIndex = nIndex
.Text = .List(nIndex)
Else
.ListIndex = nIndex2
.Text = .List(nIndex2)
End If
End If
.SelStart = 0
.SelLength = Len(Store)
End If
End If
End With
End Function
Public Sub ComboSIClear(Combo As ComboBox, _
Optional ByVal ResetListIndex As Boolean, _
Optional Store As Variant)
With Combo
.Text = ""
If IsMissing(Store) Then
.Tag = ""
Else
Store = ""
End If
If ResetListIndex Then
.ListIndex = -1
End If
End With
End Sub
|