- Offizieller Beitrag
Als StandardControl haben wir ja mit der ComboBox die Möglichkeit eine eingabesensitive Auswahl zu ermöglichen.
Ich habe hier mal ein Beispiel erstellt, wie man diese Funktionalität auch für z.B. Input-Ctrl erreichen kann.
Gründe dafür:
- ich finde es optisch nicht sehr ansprechend, wenn die Schaltfläche der ComboBox die GUI 'verschandelt'
- ich habe hiermit die Möglichkeit eigene Auswahllisten auch für Fremdanwendungen (so sie denn Standard Windows Controls verwenden) zu nutzen
Funktionsweise:
Wird in das Inputfeld ein Buchstabe eingegeben, der auch als Anfangsbuchstabe in der Liste hinterlegt ist, popt das Auswahlfenster auf.
Der Focus bleibt aber beim Inputfeld.
Ist in der Liste kein Eintrag mit diesem Buchstaben, wird sie auch nicht eingeblendet.
Es wird mit jedem weiteren Buchstaben auf Übereinstimmung geprüft und entsprechend der erste Eintrag markiert, auf den die bisherige Eingabe zutrifft.
Mit PFEIL AUF / PFEIL AB kann in der Liste die Auswahl verschoben werden.
Mit ENTER wird der momentan markierte Eintrag aus der Liste in das Input übernommen.
Mit ESC kann die Liste ohne Übernahme gechlossen werden.
Edit 08.03.09:
Habe das Skript nochmal etwas bearbeitet. Alle bisher im Thread besprochenen Änderungen/Ergänzungen sind enthalten.
Es ist jetzt allgemein gehalten, sodass es für Input- und ComboBox-Ctrl gleichermaßen verwendet werden kann. Es brauchen auch keine Anpassungen in den Funktionen für die Control-ID's erfolgen.
Es muß zur Anwendung nur noch folgendes getan werden:
- Einmalig bei der Erstellung eine Zuweisung auf den allgemeinen Namen ($SenseGui u. $SenseCtrl)
- Befüllen des DatenArray mit den Auswahldaten
Edit zum Edit: $nNotifyCode für ComboBox fehlte noch - jetzt komplett
Spoiler anzeigen
#include<GUIConstantsEx.au3>
#include<ListBoxConstants.au3>
#include <WindowsConstants.au3>
#include <GUIListBox.au3>
#Include <WinAPI.au3>
#include <Misc.au3>
Opt("GUICloseOnESC", 0)
#region - Deklarationen für Sense
Global $show = False
Global $indexB = -1
Global $SenseGui, $SenseCtrl, $guiBox, $box
Global $POSSenseGui[2]
#Region Box
; Hier die Auswahldaten (braucht nicht sortiert sein):
Global $aData[10] = ['Birne','Alligator','Auto','Dank','Automat','Bett','Garten','Bettler','Danke','Danksagung']
$guiBox = GUICreate('', 150, 85, 0, 0, BitOR($WS_SIZEBOX,$WS_POPUP), $WS_EX_TOPMOST)
$box = _GUICtrlListBox_Create($guiBox, '', 0, 0, 150, 86, BitOR($LBS_SORT, 0x00B00002))
; ListBox muß 1 Pixel höher als GUI sein - sonst fehlerhafte Darstellung
For $i = 0 To UBound($aData) -1 ; falls Daten mit _FileReadToArray gelesen werden: StartIndex=1
_GUICtrlListBox_AddString($box, $aData[$i])
Next
#EndRegion Box
GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
GUIRegisterMsg($WM_MOVE, "_WM_MOVE")
GUIRegisterMsg(0x231, "_WM_ENTERSIZEMOVE")
#EndRegion - Deklarationen Sense
#Region Main
$Form1 = GUICreate('Intelli Sense Box', 400, 300, 200, 50)
$SenseGui = $Form1 ; <== Für Allgemeingültigkeit Zuweisung an $SenseGui
$Input = GUICtrlCreateInput('', 10, 10, 380, 21)
$SenseCtrl = $Input ; <== Für Allgemeingültigkeit Zuweisung an $SenseCtrl
$hInput = GUICtrlGetHandle($Input)
GUISetState()
#EndRegion Main
While True
_ChooseBox()
If GUIGetMsg() = $GUI_EVENT_CLOSE Then Exit
WEnd
#region - SenseFuncs
Func _ChooseBox()
If Not $show Then Return
If _IsPressed('0D') Then ; ENTER
ControlSetText($SenseGui, '', $SenseCtrl, _GUICtrlListBox_GetText($box, $indexB))
GUISetState(@SW_HIDE, $guiBox)
$show = False
ElseIf _IsPressed('1B') Then ; ESC
GUISetState(@SW_HIDE, $guiBox)
$show = False
ElseIf _IsPressed('26') Then ; UP
If $indexB > 0 Then
$indexB -= 1
_GUICtrlListBox_SetCurSel($box, $indexB)
Sleep(90)
EndIf
ElseIf _IsPressed('28') Then ; DOWN
If $indexB < _GUICtrlListBox_GetCount($box)-1 Then
$indexB += 1
_GUICtrlListBox_SetCurSel($box, $indexB)
Sleep(90)
EndIf
EndIf
EndFunc
Func MY_WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
Local $nNotifyCode = BitShift($wParam, 16)
Local $hCtrl = $lParam
Local $hSenseCtrl = $SenseCtrl
If Not IsHWnd($hSenseCtrl) Then $hSenseCtrl = GUICtrlGetHandle($hSenseCtrl)
If ($nNotifyCode = 1024 Or $nNotifyCode = 6) And $hCtrl = $hSenseCtrl Then
Local $str = ControlGetText($SenseGui, '', $SenseCtrl)
$indexB = _GUICtrlListBox_FindString($box, $str)
_GUICtrlListBox_SetCurSel($box, $indexB)
$caret = _CaretPos()
If Not @error And Not $show Then
If $caret[3] + $caret[4] - 95 < 0 Then ; Platz für Liste über dem Ctrl ausreichend?
WinMove($guiBox, '', $caret[0], $caret[1] +25) ; Versatz 25 (Ctrlhöhe+5) unter y vom Ctrl
Else
WinMove($guiBox, '', $caret[0], $caret[1] -95) ; Versatz 95 (Boxhöhe+10) über y vom Ctrl
EndIf
GUISetState(@SW_SHOWNOACTIVATE, $guiBox)
$show = True
EndIf
ElseIf $hCtrl = $box And $nNotifyCode = 1 Then
$indexB = _GUICtrlListBox_GetCurSel($box)
ControlSetText($SenseGui, '', $SenseCtrl, _GUICtrlListBox_GetText($box, $indexB))
GUISetState(@SW_HIDE, $guiBox)
$show = False
ElseIf $show And $nNotifyCode = 512 And $hCtrl = $lParam And Not $hCtrl = $box Then
GUISetState(@SW_HIDE,$guiBox)
$show = False
EndIf
Return $GUI_RUNDEFMSG
EndFunc
Func _WM_ENTERSIZEMOVE($hWnd)
If $hWnd = $SenseGui Then $POSSenseGui = WinGetPos($SenseGui)
EndFunc
Func _WM_MOVE($hWnd)
If $hWnd = $SenseGui Then
Local $pos = WinGetPos($guiBox)
Local $postemp = WinGetPos($SenseGui)
WinMove($guiBox,"",$pos[0]-($POSSenseGui[0]-$postemp[0]),$pos[1]-($POSSenseGui[1]-$postemp[1]))
$POSSenseGui = WinGetPos($SenseGui)
EndIf
EndFunc
Func _CaretPos()
Local $old = Opt("CaretCoordMode", 0) ;relative mode
Local $c = WinGetCaretPos() ;relative caret coords
Local $w = WinGetPos("") ;window's coords
Local $f = ControlGetFocus("","") ;text region "handle"
Local $e = ControlGetPos("", "", $f) ;text region coords
Local $h = ControlGetHandle("", "", $f) ;Ctrl-Handle
Local $t[5]
If IsArray($c) and IsArray($w) and IsArray($e) Then
If _WinAPI_IsClassName($SenseCtrl, 'Edit') Then ; Input wird als Edit-Class erkannt
$t[0] = $c[0] + $w[0] + $e[0]
ElseIf _WinAPI_IsClassName($SenseCtrl, 'ComboBox') Then
$t[0] = $w[0] + $e[0]
EndIf
$t[1] = $c[1] + $w[1] + $e[1]
$t[2] = $h
$t[3] = $w[1]
$t[4] = $e[1]
Opt("CaretCoordMode", $old)
Return $t ;absolute screen coords of caret cursor
Else
Opt("CaretCoordMode", $old)
SetError(1)
EndIf
EndFunc
#endregion - SenseFuncs
DL bisher: 70