Jump to content

[Solved] Parent & Child GUIs and Input control fails


Recommended Posts

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

Opt("GUIOnEventMode", 1)

Global $edit, $GuiChild = 0

GuiExample()

Func GuiExample()
    ; https://www.autoitscript.com/forum/topic/202986-parent-child-guis-and-input-control-fails/
    Local $GuiMain = GUICreate("GuiExample w/child (parent)", 350, 300)
    GUISetOnEvent($GUI_EVENT_CLOSE, "GuiOnEvent_CLOSE", $GuiMain)
    GUISetState(@SW_SHOW, $GuiMain)

    $edit = GUICtrlCreateEdit("", 10, 70, 300, 200) ;  It does not matter what GUI is on,
    GUICtrlSetData($edit, "play around with the inputs" & _ ; the parent's controls will
    @CRLF & "and press enter." & _ ;                          bleed through a $WS_CHILD gui.
    @CRLF & @CRLF & "It should trigger the" & _
    @CRLF & " GUICtrlSetOnEvent()")
    GUICtrlCreateButton("reload alt.", 225, 40, 120, 25) ; run alternate versions,
    GUICtrlSetOnEvent(-1, "OnBttnRunAlt") ;                with and without child GUI.
    GUICtrlSetTip(-1, "run alternate versions," & @LF & "with and without child GUI.")


    ;I need this child(s), but with it, it does not behave as expected.
    ;..for this test you can comment it out, to see that it should work.
    ;..but with the child, instead it executes after clicking another control.
    If Not StringInStr($CmdLineRaw, "/ExampleOnlyParent") Then
        $GuiChild = GUICreate("GuiExample w/child (child)", 320, 280, 5, 5, $WS_CHILD, $WS_TABSTOP, $GuiMain)
    EndIf



    If $GuiChild Then GUISetBkColor(0x888888, $GuiChild) ; for the dramatic effect  :)
    If $GuiChild Then GUISwitch($GuiChild) ; ..just in case.. tho should not matter.
    GUICtrlCreateInput("This text 1", 5, 10, 200, 21, BitOR($GUI_SS_DEFAULT_INPUT, $ES_WANTRETURN))
    GUICtrlSetOnEvent(-1, "OnInputEnterKeyOne")
    GUICtrlCreateInput("This text 2", 5, 35, 200, 21, BitOR($GUI_SS_DEFAULT_INPUT, $ES_WANTRETURN))
    GUICtrlSetOnEvent(-1, "OnInputEnterKeyTwo")
    If $GuiChild Then
        GUICtrlCreateButton("flash child", 220, 8, 120, 25)
        GUICtrlSetOnEvent(-1, "OnFlashBttn")
        GUISetState(@SW_SHOW, $GuiChild)
        OnFlashBttn()
    EndIf



    MainLoopExample()
EndFunc

Func MainLoopExample()
    While 1
        Sleep(100)
    WEnd
EndFunc

Func OnInputEnterKeyOne()
    GUICtrlSetData($edit, @SEC &'.' & @MSEC& ' - Func OnInputEnterKey One ()' & @CRLF)
EndFunc

Func OnInputEnterKeyTwo()
    GUICtrlSetData($edit, @SEC &'.' & @MSEC& ' - Func OnInputEnterKey Two ()' & @CRLF)
EndFunc

Func OnFlashBttn()
    WinSetTrans($GuiChild, "", 50)
    Sleep(300)
    WinSetTrans($GuiChild, "", 255)
EndFunc

Func OnBttnRunAlt()
    If StringInStr($CmdLineRaw, "/ExampleOnlyParent") Then
        ShellExecute(@ScriptFullPath, "")
    Else
        ShellExecute(@ScriptFullPath, "/ExampleOnlyParent")
    EndIf
    GuiOnEvent_CLOSE()
EndFunc

Func GuiOnEvent_CLOSE()
    GUIDelete()
    Exit
EndFunc

I need this child(s), but with it, it does not behave as expected.
..for this test you can comment the child GUI out, to see that it should work.
With the child, instead it executes after clicking another control.

Thanks

Edit: Modified the example for dramatic effect :) 

Edit 2: Solved my problems at a post somewhere down this thread.

Edited by argumentum
solved my problem

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

  • Moderators

argumentum,

If I move the child creation line AFTER the creation of the controls, it seems to work the way you want. I imagine AutoIt is getting very confused by the fact you have 2 GUIs and do not specify which GUI is to receive the controls - it puts the controls in the visible one and is then uncertain of how to act with the child not having a "state" set.

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

  • Moderators

argumentum,

You do realise that the child never actually appears? Why are you using the $WS_CHILD style when you are explicitly setting the parent parameter?

M23

P.S. Family calls - back tomorrow.

Edited by Melba23

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

36 minutes ago, Melba23 said:

You do realise that the child never actually appears?

I've modified the example to have better visual cues.
 

36 minutes ago, Melba23 said:

Why are you using the $WS_CHILD style when you are explicitly setting the parent parameter?

That style will not overlap the parent GUI, when the child GUI is bigger than the parent GUI.

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

..and to top it off, the OnEvent, triggers when the input control got edited and clicked down another control or tabbing ( basically loosing focus ), with or w/o child GUI, w/o pressing an enter key.

Edited by argumentum
specify the event

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

..here we go: ( is better to look at the next entry down this thread )

#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <WinAPI.au3>
;~ #include <WinAPIDlg.au3>

Opt("GUIOnEventMode", 1)

Global $iIsRegistered = 0, $iCtrlsAndFuncs = 0, $aCtrlsAndFuncs[11][2], $i_Ctrl = 0
Global $edit, $GuiChild = 0
Global $i_IDFrom = 0

GuiExample()

Func GuiExample()
    ; https://www.autoitscript.com/forum/topic/202986-parent-child-guis-and-input-control-fails/
    Local $GuiMain = GUICreate("GuiExample w/child (parent)", 400, 300, -1, -1, BitOR($GUI_SS_DEFAULT_GUI,$WS_MAXIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_TABSTOP))
    GUISetOnEvent($GUI_EVENT_CLOSE, "GuiOnEvent_CLOSE", $GuiMain)
    GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "GuiOnEvent_PRIMARYDOWN_Parent", $GuiMain)
    GUISetState(@SW_SHOW, $GuiMain)

    $edit = GUICtrlCreateEdit("", 10, 70, 300, 200) ;  It does not matter what GUI is on,
    GUICtrlSetData($edit, "play around with the inputs" & _ ; the parent's controls will
            @CRLF & "and press enter." & _ ;                          bleed through a $WS_CHILD gui.
            @CRLF & @CRLF & "It should trigger the" & _
            @CRLF & " GUICtrlSetOnEvent()")
    myColors()

    GUICtrlCreateLabel('v.' & @AutoItVersion, 290, 280)

    GUICtrlCreateButton("reload alt.", 225, 40, 120, 25) ; run alternate versions,
    GUICtrlSetOnEvent(-1, "OnBttnRunAlt") ;                with and without child GUI.
    GUICtrlSetTip(-1, "run alternate versions," & @LF & "with and without child GUI.")


    ;I need this child(s), but with it, it does not behave as expected.
    ;..for this test you can comment it out, to see that it should work.
    ;..but with the child, instead it executes after clicking another control.
    If Not StringInStr($CmdLineRaw, "/ExampleOnlyParent") Then
        $GuiChild = GUICreate("GuiExample w/child (child)", 320, 380, 5, 5, $WS_CHILD, 0x00010000, $GuiMain)
        GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "GuiOnEvent_PRIMARYDOWN_Child", $GuiChild)
    EndIf
    ; so the magic number is $WS_TABSTOP = 0x00010000
    ; added as a magic due to that is "Common Styles" and not "Common Extended Styles"
    ; and does indeed allows to tab around but it also "makes the GUI dragable" and tho,
    ; much desired to those looking for the feature, I need it not.

    ; The again, running under 3.2.12.1 it works as one would expect from $WS_TABSTOP
    ; without the dragging of the child


    If $GuiChild Then GUISetBkColor(0x888888, $GuiChild) ; for the dramatic effect  :)
    If $GuiChild Then GUISwitch($GuiChild) ; ..just in case.. tho should not matter.


    ;----------------------------------------------------------------------------------
    ;;;; this part, the _GUICtrlInputSetOnEventEnterKey() solves the Enter key issue with GUICtrlSetOnEvent()

    Local $iCtrl = GUICtrlCreateInput("This text 1", 5, 10, 200, 21, BitOR($GUI_SS_DEFAULT_INPUT, $ES_WANTRETURN))
;~  GUICtrlSetOnEvent($iCtrl, "OnInputEnterKeyOne") ; ..this line is here for you to campare with the one below,
    _GUICtrlInputSetOnEventEnterKey($iCtrl, "OnInputEnterKeyOne") ;                     if you'd want to compare.
    myColors()

    GUICtrlCreateInput("This text 2", 5, 35, 200, 21, BitOR($GUI_SS_DEFAULT_INPUT, $ES_WANTRETURN))
;~  GUICtrlSetOnEvent(-1, "OnInputEnterKeyTwo")
    _GUICtrlInputSetOnEventEnterKey(-1, "OnInputEnterKeyTwo")
    myColors()
    ;----------------------------------------------------------------------------------


    If $GuiChild Then
        GUICtrlCreateButton("flash child", 220, 8, 120, 25)
        GUICtrlSetOnEvent(-1, "OnFlashBttn")
        GUISetState(@SW_SHOW, $GuiChild)
        OnFlashBttn() ; ..in v3.2.12.1 this does not work, and it should not work,
    EndIf ;            but in newer versions it does. ( it may be related to the $WS_TABSTOP )



    MainLoopExample()
EndFunc   ;==>GuiExample

Func myColors()
    GUICtrlSetColor(-1, 0x222222 )
    GUICtrlSetBkColor(-1, 0xEEEEEE )
EndFunc


#Region tha hack for the enter key

Func _GUICtrlInputSetOnEventEnterKey($iCtrl = 0, $sFunc = "", $iInternal_IsFrom_WM_COMMAND = 0)
    ConsoleWrite('+ Func _GUICtrlInputSetOnEventEnterKey($iCtrl = "' & Eval("iCtrl") & '", $sFunc = "' & Eval("sFunc") & '", $iInternal_IsFrom_WM_COMMAND = "' & Eval("iInternal_IsFrom_WM_COMMAND") & '")' & @CRLF)

;~  Local Static $iIsRegistered = 0, $iCtrlsAndFuncs = 0, $aCtrlsAndFuncs[11][2], $i_Ctrl = 0
    If $iIsRegistered = 0 Then $iIsRegistered = Int(Not GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND')) ; or register your own later.

    If Eval("iInternal_IsFrom_WM_COMMAND") Then
        ConsoleWrite(@TAB & "iInternal_IsFrom_WM_COMMAND: " & $iInternal_IsFrom_WM_COMMAND & @CRLF)
        $i_Ctrl = $iInternal_IsFrom_WM_COMMAND
;~      AdlibRegister("_GUICtrlInputSetOnEventEnterKey", 50)
        If StringInStr(@AutoItVersion, "3.2.") = 1 Then
            Execute('AdlibEnable("_GUICtrlInputSetOnEventEnterKey", 50)')
        Else
            Execute('AdlibRegister("_GUICtrlInputSetOnEventEnterKey", 50)')
        EndIf


        Return ; return to the GUIRegisterMsg() ASAP

    ElseIf Eval("iCtrl") Then
        $iCtrlsAndFuncs += 1
        If UBound($aCtrlsAndFuncs) < $iCtrlsAndFuncs + 1 Then ReDim $aCtrlsAndFuncs[UBound($aCtrlsAndFuncs) + 100][2]
        $aCtrlsAndFuncs[0][0] = $iCtrlsAndFuncs ; useless but a force of habit  :)
        If $iCtrl = -1 Then $iCtrl = _WinAPI_GetDlgCtrlID(GUICtrlGetHandle($iCtrl))
        ConsoleWrite(@TAB & "iCtrl: " & $iCtrl & @CRLF)
        $aCtrlsAndFuncs[$iCtrlsAndFuncs][0] = $iCtrl
        $aCtrlsAndFuncs[$iCtrlsAndFuncs][1] = $sFunc
        Return

    Else
;~      AdlibUnRegister("_GUICtrlInputSetOnEventEnterKey")
        If StringInStr(@AutoItVersion, "3.2.") = 1 Then
            Execute('AdlibDisable()')
        Else
            Execute('AdlibUnRegister("_GUICtrlInputSetOnEventEnterKey")')
        EndIf


        ConsoleWrite(@TAB & "run" & @CRLF)
        For $n = 1 To $iCtrlsAndFuncs
            ConsoleWrite("?" & $aCtrlsAndFuncs[$n][0] & " = " & $i_Ctrl & @CRLF)
            If $i_Ctrl = $aCtrlsAndFuncs[$n][0] Then
                ConsoleWrite(@TAB & "run: " & $aCtrlsAndFuncs[$n][1] & @CRLF)
                Call($aCtrlsAndFuncs[$n][1])
                Return
            EndIf
        Next
    EndIf
EndFunc   ;==>_GUICtrlInputSetOnEventEnterKey

#EndRegion tha hack for the enter key

Func GuiOnEvent_PRIMARYDOWN_Parent()
    GUICtrlSetData($edit, @SEC & '.' & Execute("@MSEC") & ' - Func GuiOnEvent_PRIMARYDOWN_Parent ()' & @CRLF)
EndFunc

Func GuiOnEvent_PRIMARYDOWN_Child()
    GUICtrlSetData($edit, @SEC & '.' & Execute("@MSEC") & ' - Func GuiOnEvent_PRIMARYDOWN_Child ()' & @CRLF)
EndFunc   ;==>GuiOnEvent_PRIMARYDOWN

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam, $lParam

;~  Local Static $i_IDFrom = 0 ; ..you'd have to add this line to your WM_COMMAND

    Local $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word
    Local $iCode = BitShift($wParam, 16) ; Hi Word

;~  ConsoleWrite('+ Func WM_COMMAND(' & $hWnd & ', ' & $iMsg & ', ' & $wParam & ', ' & $lParam & ') $iIDFrom: ' & $iIDFrom & ', $iCode: 0x' & Hex($iCode, 4) & @CRLF)
    If $wParam = 1 And $lParam = 0 Then _GUICtrlInputSetOnEventEnterKey(0, "", $i_IDFrom)
    If $lParam And $iCode Then $i_IDFrom = $iIDFrom ; ..you'd have to add these 2 lines to your WM_COMMAND

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

Func MainLoopExample()
    While 1
        Sleep(100)
    WEnd
EndFunc   ;==>MainLoopExample

Func OnInputEnterKeyOne()
    GUICtrlSetData($edit, @SEC & '.' & Execute("@MSEC") & ' - Func OnInputEnterKey One ()' & @CRLF)
EndFunc   ;==>OnInputEnterKeyOne

Func OnInputEnterKeyTwo()
    GUICtrlSetData($edit, @SEC & '.' & Execute("@MSEC") & ' - Func OnInputEnterKey Two ()' & @CRLF)
EndFunc   ;==>OnInputEnterKeyTwo

Func OnFlashBttn()
    WinSetTrans($GuiChild, "", 50)
    Sleep(300)
    WinSetTrans($GuiChild, "", 255)
EndFunc   ;==>OnFlashBttn

Func OnBttnRunAlt()
    If StringInStr($CmdLineRaw, "/ExampleOnlyParent") Then
        ShellExecute(@AutoItExe, '"' & @ScriptFullPath & '"')
    Else
        ShellExecute(@AutoItExe, '"' & @ScriptFullPath & '" /ExampleOnlyParent')
    EndIf
    GuiOnEvent_CLOSE()
EndFunc   ;==>OnBttnRunAlt

Func GuiOnEvent_CLOSE()
    If $GuiChild Then GUIDelete($GuiChild)
    GUIDelete()
    Exit
EndFunc   ;==>GuiOnEvent_CLOSE

This will run in v3.2.12.1 and v3.3.14.5 and 3.3.15.3.  The reason is to identify behavior.

Regarding the OnEvent behavior, I coded around it to overcome the issue.    but the $WS_TABSTOP = 0x00010000, I can not.

$WS_TABSTOP behaves as expected in v3.2.12.1 but not in the v3.3.x.x versions.

So there is more than one issue to look at. @jpm, would you kindly add them to the ticket tracker ? I don't believe I would do a good job adding them.
If you rather not, let me know and I'll squeeze something out of my brain but again, I'm not the best for discerning each in a clear and explicit format.

Meanwhile, if anyone can code something ( that don't use Send() ) to stop the dragging of the child GUI, I'll appreciate it.  Fortunately found a way ( unless told to not go this way ) with this bellow: ( unless it brakes something else, will see )

ConsoleWrite((GUIRegisterMsg($WM_NCHITTEST, '__WM_NCHITTEST') ? '+ ' : '! ') & 'WM_NCHITTEST' & @CRLF) ; $WM_NCHITTEST = 0x0084

Func __WM_NCHITTEST($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam, $lParam
    ConsoleWrite('+ Func __WM_NCHITTEST(' & $hWnd & ', ' & $iMsg & ', ' & $wParam & ', ' & $lParam & ')' & @CRLF)
    Return 0 ; ..to not continue
;~  Return $GUI_RUNDEFMSG
EndFunc   ;==>__WM_NCHITTEST

...and it broke the resize. I'm using WM_GETMINMAXINFO to snap it back into place.
Edit 3: I'm finally using WM_WINDOWPOSCHANGING to keep it in place, anchored to a Ctrl in the main GUI. 

..and in case someone wants to register almost all 219 messages from the help file, here is the discovery/brute force tool :) 

 

GUIRegisterMsgThemAll_UDF_v2.zip

Edited by argumentum
updated the UDF/tool

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

  • 4 weeks later...

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