Jump to content

_GUICtrlComboBox_AutoComplete example issue with accelerator keys and close window


 Share

Recommended Posts

I was playing around with _GUICtrlComboBox_AutoComplete example code and wanted to test using the enter key in the combobox. I added an accelerator key to catch the enter key but it wasn't being picked up so I tried putting a sleep in GUIGetMsg loop and that worked but then when you click on the X close window button it isn't picked up.  If I reduce the pause in the loop it get more responsive for closing the window but misses some of the enter key presses.
 
I have an alternative using _IsPressed which works but I like the idea of the accelerator key just working in the one window.
I'd like to understand why there isn't a balance between the accelerator key, the GUIRegisterMsg, and the close window.
 
In my example you can see that when you press the enter key it picks up whats in the edit box and writes it and a count of how many times you pressed enter to the console and puts a tooltip up.  But if you try to close the window clicking on the X or using Ctrl-F4 it usually doesn't work. Using the drop down menu on the left and choosing close works pretty well.
If you comment out the Sleep(100) line in the GuiGetMsg loop you pick up some of the enter keys but often miss them.  On the other hand closing the window works as expected.
 
Thanks for your consideration.
 
;Auto complete combobox
#include <GuiComboBox.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include<array.au3>
#include<misc.au3>


Global $g_idCombo

Example()

Func Example()
    ; Create GUI
    GUICreate("ComboBox Auto Complete", 200, 25)
    $g_idCombo = GUICtrlCreateCombo("", 2, 2, 196, 300)
    $myEnter = GUICtrlCreateDummy()
    $myEsc = GUICtrlCreateDummy()
    Global $iCnt = 0

    ;Set GUIAccelerators to capture Enter key
;   Local $aAcc[1][2] = [["{Enter}", $myEnter]]
    Local $aAcc[2][2] = [["{Enter}", $myEnter],["{Esc}", $myEsc]]
    GUISetAccelerators($aAcc)

    GUISetState(@SW_SHOW)

    ; Add files and strings and sort
    ; You could use InsertString at 0 index instead of AddString to see most recent first additions.
    _GUICtrlComboBox_BeginUpdate($g_idCombo)
    _GUICtrlComboBox_AddDir($g_idCombo, @WindowsDir & "\*.exe")
    Global $aStrings[4] = ["Rock","Paper","Scissors","Rubber"]
    for $i = 0 to 3
        _GUICtrlComboBox_AddString($g_idCombo, $aStrings[$i])
    Next
    $aStrings = _GUICtrlComboBox_GetListArray($g_idCombo)
    _ArraySort($aStrings)
    _GUICtrlComboBox_ResetContent($g_idCombo)
    for $i = 0 to UBound($aStrings) -1
        ;ConsoleWrite($aStrings[$i] & @CRLF)
        _GUICtrlComboBox_AddString($g_idCombo, $aStrings[$i])
    Next
    _GUICtrlComboBox_EndUpdate($g_idCombo)

    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

    ; Loop until the user exits.
    Do
        Sleep(100) ;<----- helps get enter key but hurts using close window button X
        Switch GUIGetMsg()
            Case $myEnter
                $iCnt +=1
                $sCtrlRead = GUICtrlRead($g_idCombo)
                ConsoleWrite("Entered " & $iCnt & " " & $sCtrlRead & @CRLF)
                ToolTip("Entered " & $iCnt & " " & $sCtrlRead,10,10)
            Case $myEsc
                GUICtrlSetData($g_idCombo,"Set")
;~              ;GUIDelete()
        EndSwitch
        ;Alternative to Accelerator Keys
;~      if chk_key("0d") then
;~          $iCnt +=1
;~          $sCtrlRead = GUICtrlRead($g_idCombo)
;~          ConsoleWrite("Press-Entered " & $iCnt & " " & $sCtrlRead & @CRLF)
;~      EndIf
;~      if chk_key("1b") then
;~          ConsoleWrite("Esc" & @CRLF)
;~          Exit
;~      EndIf
        ;and WinActive("ComboBox Auto Complete")
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
EndFunc   ;==>Example

func chk_key($sK)
; 0d,1b Enter, Esc
    if _IsPressed($sK) and WinActive("ComboBox Auto Complete") then
        While _IsPressed($sK)
            Sleep(200)
        WEnd
        return True
    EndIf
    return False
EndFunc

Func _Edit_Changed()
    _GUICtrlComboBox_AutoComplete($g_idCombo)
EndFunc   ;==>_Edit_Changed

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg
    Local $hWndFrom, $iIDFrom, $iCode, $hWndCombo
    If Not IsHWnd($g_idCombo) Then $hWndCombo = GUICtrlGetHandle($g_idCombo)
    $hWndFrom = $lParam
    $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word
    $iCode = BitShift($wParam, 16) ; Hi Word
    Switch $hWndFrom
        Case $g_idCombo, $hWndCombo
            Switch $iCode
                Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
                    _DebugPrint("$CBN_CLOSEUP" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_DBLCLK ; Sent when the user double-clicks a string in the list box of a combo box
                    _DebugPrint("$CBN_DBLCLK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_DROPDOWN ; Sent when the list box of a combo box is about to be made visible
                    _DebugPrint("$CBN_DROPDOWN" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_EDITCHANGE ; Sent after the user has taken an action that may have altered the text in the edit control portion of a combo box
                    _DebugPrint("$CBN_EDITCHANGE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    _Edit_Changed()
                    ; no return value
                Case $CBN_EDITUPDATE ; Sent when the edit control portion of a combo box is about to display altered text
                    _DebugPrint("$CBN_EDITUPDATE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_ERRSPACE ; Sent when a combo box cannot allocate enough memory to meet a specific request
                    _DebugPrint("$CBN_ERRSPACE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_KILLFOCUS ; Sent when a combo box loses the keyboard focus
                    _DebugPrint("$CBN_KILLFOCUS" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SELCHANGE ; Sent when the user changes the current selection in the list box of a combo box
                    _DebugPrint("$CBN_SELCHANGE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SELENDCANCEL ; Sent when the user selects an item, but then selects another control or closes the dialog box
                    _DebugPrint("$CBN_SELENDCANCEL" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SELENDOK ; Sent when the user selects a list item, or selects an item and then closes the list
                    _DebugPrint("$CBN_SELENDOK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SETFOCUS ; Sent when a combo box receives the keyboard focus
                    _DebugPrint("$CBN_SETFOCUS" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

Func _DebugPrint($s_Text, $sLine = @ScriptLineNumber)
    ConsoleWrite( _
            "!===========================================================" & @CRLF & _
            "+======================================================" & @CRLF & _
            "-->Line(" & StringFormat("%04d", $sLine) & "):" & @TAB & $s_Text & @CRLF & _
            "+======================================================" & @CRLF)
EndFunc   ;==>_DebugPrint

 

auto_complete combobox.au3

Edited by wolflake
Link to comment
Share on other sites

  • Moderators

wolflake,

You are calling GUIGetMsg twice in your idle loop - once to check for the Accel keys and then again in the Do...Until structure you use to look for the closure [X]. Little wonder you miss the odd event!

Replace the Do...Until with a While...WEnd and add a Case $GUI_EVENT_CLOSE case in the Switch structure and all should work correctly. And you can remove the Sleep too - GUIGetMsg has a built-in pause to keep the CPU from frying.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

  • 3 months later...

 

On 05/11/2018 at 5:32 PM, Melba23 said:

wolflake,

You are calling GUIGetMsg twice in your idle loop - once to check for the Accel keys and then again in the Do...Until structure you use to look for the closure [X]. Little wonder you miss the odd event!

Replace the Do...Until with a While...WEnd and add a Case $GUI_EVENT_CLOSE case in the Switch structure and all should work correctly. And you can remove the Sleep too - GUIGetMsg has a built-in pause to keep the CPU from frying.

M23

Hello
I love using combobox in my applications and I have been using this subtle modification for a long time so that Dropper opens by typing something. most recently I had an unpleasant surprise to press the [ESC] key for 2x
in the first one it collects the Dropper (which would be expected) but when pressing again [ESC] the program simply closes
It must be something so stupid I'm not noticing.

;� ;nunca Apagar
#Region para $EditDebug
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#EndRegion para $EditDebug


#include <GuiComboBox.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global $g_idCombo

Example()

Func Example()
    ; Create GUI
    GUICreate("ComboBox Auto Complete", 600, 600)
    $g_idCombo = GUICtrlCreateCombo("", 2, 2, 396, 296)
        Global $EditDebug = GUICtrlCreateEdit("debug", 2, 600 - 150 - 4, _
            600 - 4, 150, _
            $ES_AUTOVSCROLL + $WS_VSCROLL)

    GUISetState(@SW_SHOW)

    ; Add files
    _GUICtrlComboBox_BeginUpdate($g_idCombo)
    _GUICtrlComboBox_AddDir($g_idCombo, @WindowsDir & "\*.exe")
    _GUICtrlComboBox_EndUpdate($g_idCombo)

    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

    ; Loop until the user exits.
        While 1
        $idMsg = GUIGetMsg()
        Select
            Case $idMsg = $GUI_EVENT_CLOSE
                MsgBox($MB_SYSTEMMODAL, "", "Dialog was closed")
                ExitLoop

        EndSelect
    WEnd

;~  Do
;~  Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
EndFunc   ;==>Example

Func _Edit_Changed()
    If Not __GUICtrlComboBox_IsPressed('08') And Not __GUICtrlComboBox_IsPressed("2E") Then ;backspace pressed or Del
            ;==>> my update:
        _GUICtrlComboBox_ShowDropDown($g_idCombo, True)
        ;<<===
    EndIf
    _GUICtrlComboBox_AutoComplete($g_idCombo)
EndFunc   ;==>_Edit_Changed

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg
    Local $hWndFrom, $iIDFrom, $iCode, $hWndCombo
    If Not IsHWnd($g_idCombo) Then $hWndCombo = GUICtrlGetHandle($g_idCombo)
    $hWndFrom = $lParam
    $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word
    $iCode = BitShift($wParam, 16) ; Hi Word
    Switch $hWndFrom
        Case $g_idCombo, $hWndCombo
            Switch $iCode
                Case $CBN_CLOSEUP ; Sent when the list box of a combo box has been closed
                    _DebugPrint("$CBN_CLOSEUP" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_DBLCLK ; Sent when the user double-clicks a string in the list box of a combo box
                    _DebugPrint("$CBN_DBLCLK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_DROPDOWN ; Sent when the list box of a combo box is about to be made visible
                    _DebugPrint("$CBN_DROPDOWN" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_EDITCHANGE ; Sent after the user has taken an action that may have altered the text in the edit control portion of a combo box
                    _DebugPrint("$CBN_EDITCHANGE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    _Edit_Changed()
                    ; no return value
                Case $CBN_EDITUPDATE ; Sent when the edit control portion of a combo box is about to display altered text
                    _DebugPrint("$CBN_EDITUPDATE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_ERRSPACE ; Sent when a combo box cannot allocate enough memory to meet a specific request
                    _DebugPrint("$CBN_ERRSPACE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_KILLFOCUS ; Sent when a combo box loses the keyboard focus
                    _DebugPrint("$CBN_KILLFOCUS" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SELCHANGE ; Sent when the user changes the current selection in the list box of a combo box
                    _DebugPrint("$CBN_SELCHANGE" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SELENDCANCEL ; Sent when the user selects an item, but then selects another control or closes the dialog box
                    _DebugPrint("$CBN_SELENDCANCEL" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SELENDOK ; Sent when the user selects a list item, or selects an item and then closes the list
                    _DebugPrint("$CBN_SELENDOK" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
                Case $CBN_SETFOCUS ; Sent when a combo box receives the keyboard focus
                    _DebugPrint("$CBN_SETFOCUS" & @CRLF & "--> hWndFrom:" & @TAB & $hWndFrom & @CRLF & _
                            "-->IDFrom:" & @TAB & $iIDFrom & @CRLF & _
                            "-->Code:" & @TAB & $iCode)
                    ; no return value
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

#Region Meu DebugPrint
;incerir esta linha apos a criação fo formulario com 600x600 de tamanho
;Define caixa de texto para o Debug
;   Global $EditDebug = GUICtrlCreateEdit("debug", 2, 600 - 150 - 4, _ ;X,Y
;                                           600 - 4, 150, _ ;Altura, Largura
;                                       $ES_AUTOVSCROLL + $WS_VSCROLL)

Func _DebugPrint($s_Text, $sLine = @ScriptLineNumber)
    If IsDeclared("EditDebug") Then
        GUICtrlSetData($EditDebug, _
                "Dados da Linha[" & $sLine & "]" & @CRLF & _
                "+======================================================" & @CRLF & _
                "-->Line(" & StringFormat("%04d", $sLine) & "):" & @TAB & $s_Text & @CRLF & _
                "+======================================================" & @CRLF, 1)
    Else
        ;se não for possivel encontrar o EditBox então mostrar com msgbox e no console

        MsgBox(0, "Dados da Linha[" & $sLine & "]", _
                "+======================================================" & @CRLF & _
                "-->Line(" & StringFormat("%04d", $sLine) & "):" & @TAB & $s_Text & @CRLF & _
                "+======================================================")
    EndIf
    _DebugPrintConsole($s_Text, $sLine )
EndFunc   ;==>_DebugPrint


Func _DebugPrintConsole($s_Text, $sLine = @ScriptLineNumber)
    ConsoleWrite( _
            "!===========================================================" & @CRLF & _
            "+======================================================" & @CRLF & _
            "-->Line(" & StringFormat("%04d", $sLine) & "):" & @TAB & $s_Text & @CRLF & _
            "+======================================================" & @CRLF)
EndFunc   ;==>_DebugPrintConsole
#EndRegion Meu DebugPrint


PS follows an improvement of AutoComplete => AutoComplete2

Func _GUICtrlComboBox_AutoComplete2($hWnd)
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)

    If Not __GUICtrlComboBox_IsPressed('08') And Not __GUICtrlComboBox_IsPressed("2E") Then ;backspace pressed or Del
        Local $sEditText = _GUICtrlComboBox_GetEditText($hWnd)
        ;==>> my update:
        _GUICtrlComboBox_ShowDropDown($hWnd, True)
        ;<<===
        If StringLen($sEditText) Then
            Local $sInputText
            Local $ret = _GUICtrlComboBox_FindString($hWnd, $sEditText)
            If ($ret <> $CB_ERR) Then
                _GUICtrlComboBox_GetLBText($hWnd, $ret, $sInputText)
                _GUICtrlComboBox_SetEditText($hWnd, $sInputText)
                _GUICtrlComboBox_SetEditSel($hWnd, StringLen($sEditText), StringLen($sInputText))
            EndIf
        EndIf
    EndIf
EndFunc   ;==>_GUICtrlComboBox_AutoComplete2

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...