GuiRegisterMsg + Combobox = Stress -.-

  • Moin!
    Neuer Tag, neues Problem ;(:

    Ich hab mir einen String erstellt (in diesem Beispiel sowas wie ne Einkaufsliste) und ich habe ne Combobox. Nun will ich aber das, wenn es eine überstimmung zwischen dem geschriebenem text in der combobox und meinem string besteht, diese Übereinstimmung + der rest vom wort im string in die liste der combobox gestellt wird..quasi sowas wie ein autocomplete bei suchseiten wie google..
    So ungefähr klappt mein script auch:

    Spoiler anzeigen
    [autoit]

    #include <array.au3>
    #include <Inet.au3>
    #include <GuiComboBox.au3>
    #include <String.au3>
    #include <GUIConstants.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $gui = GuiCreate("Main Gui", 300,300)
    $Combo = GuiCtrlCreateCombo("Einkaufsliste...", 35, 150)
    $BUtton = GuiCtrlCreateButton("OK", 240,148)
    GuiSetState()
    Global $Einkaufsliste = "| Apfel| Birne| Cola| Datteln| Eis| Fleisch| Gemüse| Hefe| Ingwer| Joghurt| Kaffee| Lachs| Mais| Nutella| Obst| Pizza| Quark| Reis| Salz| Tee| U| Vanillezucker| Wasser| X| Y| Zucker"
    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
    While 1
    Wend

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $hWndEdit
    If Not IsHWnd($Combo) Then $hWndEdit1 = GUICtrlGetHandle($Combo)

    [/autoit] [autoit][/autoit] [autoit]

    $hWndFrom = $ilParam
    $iIDFrom = _WinAPI_LoWord ($iwParam)
    $iCode = _WinAPI_HiWord ($iwParam)
    Switch $hWndFrom
    Case $Combo, $hWndEdit1
    Switch $iCode
    Case $CBN_EDITCHANGE
    If StringInStr($Einkaufsliste, "| " & GUICtrlRead($Combo)) Then
    $string1 = StringInStr($Einkaufsliste, "| " & GUICtrlRead($Combo),Default, 1)
    $string2 = StringMid($Einkaufsliste, $string1+2)
    $string3 = StringInStr($string2, "|", Default, 1)
    $string4 = StringMid($string2, 1, $string3-1)
    $string5 = _GuiCtrlComboBox_GetListArray($Combo)
    If $string5[1] = "Einkaufsliste..." Then
    _GuiCtrlComboBox_DeleteString($Combo, $string5[1])
    EndIf
    If $string5[0] > 1 Then
    For $i = 1 To $string5[0]
    If $string5[$i] <> $string4 Then
    _GuiCtrlComboBox_DeleteString($Combo, $string5[$i])
    EndIf
    Next
    EndIf
    _GuiCtrlCombobox_InsertString($Combo, $string4)
    _GuiCtrlComboBox_ShowDropDown($Combo, true)
    EndIf
    EndSwitch
    EndSwitch
    EndFunc

    [/autoit]

    Aber es gibt ein paar Probleme die ich gerne beseitigen will:

    1.Beim ersten mal wenn ich nur 1 Buchstabe eingebe, wird der text in der combobox schon sofort auf die Übereinstimmung gesetzt ohne das
    man irgendeinen anderen buchstaben schreiben darf... Im prinzip will ich das nichts mit dem geschriebenen text in der combobox gemacht wird sondern nur das sich die liste der combobox verändert!

    2.Wenn dann nun die Liste der Combobox aufgeht, verschwindet der mauscursor hinter der gui was extremst nervig ist..das könnte an _GuiCtrlComboBox_ShowDropDown liegen!

    3.Nachdem es nur noch 1 Übereinstimmung gibt, wird nach jedem buchstaben diese übereinstimmung noch 1 zusätzliches mal in die liste gesetzt, sodass bei dem Wort "Apfel", 5xApfel in der Liste steht. Ich will das immer nur 1 item in der liste ist, das die näheste übereinstimmung anzeigt..

    Soo das wärs erstmal! =)

    MFG, Apfel

    2 Mal editiert, zuletzt von Apfeltasche (7. März 2009 um 21:34)

  • Hey BugFix! Deine IntelliSenseBox ist schonmal super, danke! Kann ich auf jeden fall später gebrauchen..

    Aber gäbe es auch in diesem fall eine lösung nicht mit listview sondern mit ner combobox? Weil in meinem richtigem script (nicht im beispiel-einkaufsscript) ist 1tens die listview ein wenig unhandlich und ich müsste nicht nur 10 einträge wie in deinem beispiel machen sondern knapp 30000; habs zwar schon versucht aber das script streikt dann aus irgend nem grund... joa und mir wäre lieber wenn immer nur 1 eintrag gezeigt werden würde ;P Also wäre ne combobox 1A, hoffe das geht...

    Mfg, Apfel

    • Offizieller Beitrag

    Also ich hoffe mal, ich habs jetzt richtig verstanden.
    - Du hast eine Liste mit Einträgen
    - Die Liste der ComboBox ist leer
    - Wenn du einen Buchstaben (Folgebuchstaben) in das Editfeld der ComboBox schreibst, sollen Begriffe aus deiner vorgefertigten Liste, wo Übereinstimmung besteht, zur Auswahl gezeigt werden
    - Ausgewählte Einträge werden mit OK-Button übernommen und in die ListBox eingetragen

    Auf dieser Basis habe ich das mal erstellt:

    Spoiler anzeigen
    [autoit]

    #include <WindowsConstants.au3>
    #Include <GuiListBox.au3>
    #include <GUIComboBox.au3>
    #include <Misc.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $show = False
    Global $index = -1
    Global $POSForm1[2]

    [/autoit] [autoit][/autoit] [autoit]

    $gui = GuiCreate("Main Gui", 300,300)
    $Combo = GuiCtrlCreateCombo("Einkaufsliste...", 35, 150, -1, -1, BitOR($CBS_DROPDOWN,$WS_VSCROLL,$WS_TABSTOP))
    $BUtton = GuiCtrlCreateButton("OK", 240,148)
    GuiSetState()

    [/autoit] [autoit][/autoit] [autoit]

    Global $aData = StringSplit("Ananas|Apfel|Apfelmus|Birne|Cola|Datteln|Eis|Fleisch|Gemüse|Hefe|Ingwer|Joghurt|Kaffee|Lachs|Mais|Nuss|Nutella|Obst|Pizza|Quark|Reis|Salz|Tee|U|Vanillezucker|Wasser|X|Y|Zucker", '|')
    $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))
    For $i = 1 To UBound($aData) -1
    _GUICtrlListBox_AddString($box, $aData[$i])
    Next

    [/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
    GUIRegisterMsg($WM_MOVE,"_WM_MOVE")
    GUIRegisterMsg(0x231,"_WM_ENTERSIZEMOVE")

    [/autoit] [autoit][/autoit] [autoit]

    While True
    If $show Then
    If _IsPressed('0D') Then
    ControlSetText($gui, '', $Combo, _GUICtrlListBox_GetText($box, $index))
    GUISetState(@SW_HIDE, $guiBox)
    $show = False
    ElseIf _IsPressed('1B') Then
    GUISetState(@SW_HIDE, $guiBox)
    $show = False
    ElseIf _IsPressed('26') Then
    If $index > 0 Then
    $index -= 1
    _GUICtrlListBox_SetCurSel($box, $index)
    Sleep(90)
    EndIf
    ElseIf _IsPressed('28') Then
    If $index < _GUICtrlListBox_GetCount($box)-1 Then
    $index += 1
    _GUICtrlListBox_SetCurSel($box, $index)
    Sleep(90)
    EndIf
    EndIf
    EndIf
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    Exit
    Case $BUtton
    _GUICtrlComboBox_AddString(GUICtrlGetHandle($Combo), ControlGetText($gui, '', GUICtrlGetHandle($Combo)))
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func MY_WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
    $nNotifyCode = BitShift($wParam, 16)
    $hCtrl = $lParam
    Local $hCombo = $Combo
    If Not IsHWnd($hCombo) Then $hCombo = GUICtrlGetHandle($Combo)
    If $hCtrl = $hCombo And $nNotifyCode = 6 Then
    Local $str = ControlGetText($hWnd, '', $hCombo)
    $index = _GUICtrlListBox_FindString($box, $str)
    _GUICtrlListBox_SetCurSel($box, $index)
    $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
    $index = _GUICtrlListBox_GetCurSel($box)
    ControlSetText($gui, '', $Combo, _GUICtrlListBox_GetText($box, $index))
    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

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_ENTERSIZEMOVE($hWnd, $Msg, $wParam, $lParam)
    If $hWnd = $gui Then $POSForm1 = WinGetPos($gui)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_MOVE($hWnd, $Msg, $wParam, $lParam)
    If $hWnd = $gui Then
    Local $pos = WinGetPos($guiBox)
    Local $postemp = WinGetPos($gui)
    WinMove($guiBox,"",$pos[0]-($POSForm1[0]-$postemp[0]),$pos[1]-($POSForm1[1]-$postemp[1]))
    $POSForm1 = WinGetPos($gui)
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    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
    $t[0] = $w[0] + $e[0]
    $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

    [/autoit]
  • Eeeeendlich hab ichs geschafft!!! :rock:
    Hab nochma laange dran gesessen, versucht deinen code zu begreifen, hab ihn ein wenig vereinfacht und verändert und jetzt hab ichs genauso wie ichs haben wollte:

    Spoiler anzeigen
    [autoit]

    #include <WindowsConstants.au3>
    #Include <GuiListBox.au3>
    #include <GUIComboBox.au3>
    #include <Misc.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $show = False
    Global $index = -1
    Global $POSForm1[2]

    [/autoit] [autoit][/autoit] [autoit]

    $gui = GuiCreate("Main Gui", 300,300)
    $Combo = GuiCtrlCreateCombo("Artistlist...", 35, 150, -1, 16, $CBS_AUTOHSCROLL)
    GuiSetState()

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Global $aData = StringSplit("Ananas|Apfel|Apfelmus|Birne|Cola|Datteln|Eis|Fleisch|Gemüse|Hefe|Ingwer|Joghurt|Kaffee|Lachs|Mais|Nuss|Nutella|Obst|Pizza|Quark|Reis|Salz|Tee|U|Vanillezucker|Wasser|X|Y|Zucker", '|')
    FileOpen("artistlist.txt", 0)
    Global $aData = FileRead("artistlist.txt")
    $aData = StringSplit($aData, "|")

    [/autoit] [autoit][/autoit] [autoit]

    $guiBox = GUICreate('', 200, 17, 0, 0, BitOR(0,$WS_POPUP), $WS_EX_TOPMOST+$WS_EX_TOOLWINDOW)
    $box = _GUICtrlListBox_Create($guiBox, '', 0, 0, 200, 17,$LBS_NOINTEGRALHEIGHT)

    [/autoit] [autoit][/autoit] [autoit]

    For $l = 1 To Ubound($aData) -1
    $aData[$l] = StringTrimLeft($aData[$l],1)
    _GUICtrlListBox_AddString($box, $aData[$l])
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ;~ For $i = 1 To UBound($aData) -1
    ;~ _GUICtrlListBox_AddString($box, $aData[$i])
    ;~ Next

    [/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
    GUIRegisterMsg($WM_MOVE,"_WM_MOVE")
    GUIRegisterMsg(0x231,"_WM_ENTERSIZEMOVE")

    [/autoit] [autoit][/autoit] [autoit]

    While True
    If $show Then
    If _IsPressed('0D') Then
    ControlSetText($gui, '', $Combo, _GUICtrlListBox_GetText($box, $index))
    GUISetState(@SW_HIDE, $guiBox)
    $show = False
    ElseIf _IsPressed('1B') Then
    GUISetState(@SW_HIDE, $guiBox)
    $show = False
    ElseIf _IsPressed('26') Then
    If $index > 0 Then
    $index -= 1
    ControlSetText($gui, '', $Combo, _GUICtrlListBox_GetText($box, $index))
    _GUICtrlListBox_SetCurSel($box, $index)
    Sleep(200)
    EndIf
    ElseIf _IsPressed('28') Then
    If $index < _GUICtrlListBox_GetCount($box)-1 Then
    $index += 1
    ControlSetText($gui, '', $Combo, _GUICtrlListBox_GetText($box, $index))
    _GUICtrlListBox_SetCurSel($box, $index)
    Sleep(200)
    EndIf
    EndIf
    EndIf
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func MY_WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
    $nNotifyCode = BitShift($wParam, 16)
    $hCtrl = $lParam
    Local $hCombo = $Combo
    If Not IsHWnd($hCombo) Then $hCombo = GUICtrlGetHandle($Combo)
    If $hCtrl = $hCombo And $nNotifyCode = 6 Then
    Local $str = ControlGetText($hWnd, '', $Combo)
    $index = _GUICtrlListBox_FindString($box, $str)
    _GUICtrlListBox_SetCurSel($box, $index)
    If $str = "" Or $index = -1 Then
    GUISetState(@SW_HIDE,$guiBox)
    $show = false
    Else
    GUISetState(@SW_SHOWNOACTIVATE,$guiBox)
    $show = true
    ENdiF
    $caret = _CaretPos()
    WinMove($guiBox, '', $caret[0], $caret[1] +18)
    $index = _GUICtrlListBox_GetCurSel($box)
    $index2 = _GUICtrlListBox_GetText($box, $index)
    If $str = $index2 Then
    GUISetState(@SW_HIDE,$guiBox)
    $show = false
    EndIf
    Elseif $hCtrl = $box And $nNotifyCode = 1 Then
    $index = _GUICtrlListBox_GetCurSel($box)
    ControlSetText($gui, '', $Combo, _GUICtrlListBox_GetText($box, $index))
    GUISetState(@SW_HIDE, $guiBox)
    $show = False
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_ENTERSIZEMOVE($hWnd, $Msg, $wParam, $lParam)
    If $hWnd = $gui Then $POSForm1 = WinGetPos($gui)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_MOVE($hWnd, $Msg, $wParam, $lParam)
    If $hWnd = $gui Then
    Local $pos = WinGetPos($guiBox)
    Local $postemp = WinGetPos($gui)
    WinMove($guiBox,"",$pos[0]-($POSForm1[0]-$postemp[0]),$pos[1]-($POSForm1[1]-$postemp[1]))
    $POSForm1 = WinGetPos($gui)
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    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
    $t[0] = $w[0] + $e[0]
    $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

    [/autoit]

    Vielen Dank Bugfix, du bistn echter Tag- bzw Nachtretter!

    Mfg, Apfel

    Einmal editiert, zuletzt von Apfeltasche (7. März 2009 um 21:34)