Jump to content

Parent & child Gui synchronize


Recommended Posts

;https://www.autoitscript.com/wiki/Moving_and_Resizing_PopUp_GUIs
#include <GUIConstantsEx.au3>
#include <GuiConstants.au3>
#include <MsgBoxConstants.au3>

Global $hGUI1
Global $g_hGUI2 = 9999, $g_idButton3 = 9999 ;
Global $ileftspace = 100
Global $itopspace = 100

gui1()

Func gui1()
    $hGUI1 = GUICreate("Gui 1", 200, 200, 100, 100,$WS_THICKFRAME)
    Local $idButton1 = GUICtrlCreateButton("Msgbox 1", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Show Gui 2", 10, 60, 80, 30)
    
    $ParentPosArr = WinGetPos($hGUI1)

    GUISetState(@SW_SHOW, $hGUI1)
    GUIRegisterMsg (0x0003,"Move")

    GUISetState(@SW_SHOW)

    Local $aMsg 
    While 1
        $aMsg = GUIGetMsg(1) ; Use advanced parameter to get array
        Switch $aMsg[1] ; check which GUI sent the message
        
            Case $hGUI1
                Switch $aMsg[0] ; Now check for the messages for $hGUI1
                    Case $GUI_EVENT_CLOSE ; If we get the CLOSE message from this GUI - we exit <<<<<<<<<<<<<<<
                        ExitLoop
                    Case $idButton1
                        MsgBox($MB_OK, "MsgBox 1", "Test from Gui 1")
                    Case $idButton2
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        gui2()
                EndSwitch
                
            Case $g_hGUI2
                Switch $aMsg[0] ; Now check for the messages for $g_hGUI2
                    Case $g_idButton3 ; If we get the CLOSE message from this GUI - we just delete the GUI <<<<<<<<<<<<<<<
                        GUIDelete($g_hGUI2)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                EndSwitch
        EndSwitch
    WEnd
EndFunc   ;==>gui1

Func gui2()
    $g_hGUI2 = GUICreate ("", 200 - 2, 200, $ileftspace , $itopspace + 210, BitOR($WS_POPUPWINDOW , $WS_THICKFRAME),-1, $hGUI1) 
    $g_idButton3 = GUICtrlCreateButton("Close", 10, 10, 80, 30)
    GUISetState()
EndFunc   ;==>gui2

func Move($hWndGUI)
    if $hWndGUI=$hGUI1 then
        $ParentPosArr = WinGetPos($hGUI1)
        
        $ileftspace = $ParentPosArr[0]
        $itopspace = $ParentPosArr[1]
        WinMove($g_hGUI2, "", $ParentPosArr[0], $ParentPosArr[1]+$ParentPosArr[3])
    EndIf
EndFunc

Code is working the way I wanted.
but still want it to be checked by Autoit Expert for bug / silly mistake :).

Link to comment
Share on other sites

Here something that you could use :

#include <GUIConstantsEx.au3>
#include <GuiConstants.au3>
#include <MsgBoxConstants.au3>

Global $hGUI1, $g_hGUI2 = 9999, $g_idButton3

gui1()

Func gui1()
  $hGUI1 = GUICreate("Gui 1", 200, 200, 100, 100, $WS_THICKFRAME)
  Local $idButton1 = GUICtrlCreateButton("Msgbox 1", 10, 10, 80, 30)
  Local $idButton2 = GUICtrlCreateButton("Show Gui 2", 10, 60, 80, 30)

  GUISetState(@SW_SHOW, $hGUI1)
  GUIRegisterMsg($WM_MOVE, "Move")
  GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")

  GUISetState(@SW_SHOW)

  Local $aMsg
  While 1
    $aMsg = GUIGetMsg(1)     ; Use advanced parameter to get array
    Switch $aMsg[1]     ; check which GUI sent the message

      Case $hGUI1
        Switch $aMsg[0]         ; Now check for the messages for $hGUI1
          Case $GUI_EVENT_CLOSE           ; If we get the CLOSE message from this GUI - we exit <<<<<<<<<<<<<<<
            ExitLoop
          Case $idButton1
            MsgBox($MB_OK, "MsgBox 1", "Test from Gui 1")
          Case $idButton2
            GUICtrlSetState($idButton2, $GUI_DISABLE)
            gui2()
        EndSwitch

      Case $g_hGUI2
        Switch $aMsg[0]         ; Now check for the messages for $g_hGUI2
          Case $g_idButton3, $GUI_EVENT_CLOSE           ; If we get the CLOSE message from this GUI - we just delete the GUI <<<<<<<<<<<<<<<
            GUIDelete($g_hGUI2)
            GUICtrlSetState($idButton2, $GUI_ENABLE)
        EndSwitch
    EndSwitch
  WEnd
EndFunc   ;==>gui1

Func gui2()
  Local $aPos = WinGetPos($hGUI1)
  $g_hGUI2 = GUICreate("", 200 - 2, 200, $aPos[0], $aPos[1]+$aPos[3], $WS_THICKFRAME, -1, $hGUI1)
  $g_idButton3 = GUICtrlCreateButton("Close", 10, 10, 80, 30)
  GUISetState()
EndFunc   ;==>gui2

Func Move($hWnd, $Msg, $wParam, $lParam)
  If $hWnd = $hGUI1 Then
    Local $ParentPosArr = WinGetPos($hGUI1)
    WinMove($g_hGUI2, "", $ParentPosArr[0], $ParentPosArr[1] + $ParentPosArr[3])
  EndIf
  Return $GUI_RUNDEFMSG
EndFunc   ;==>Move

Func WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)
  Const $SC_MOVE = 0xF010
  If $hWnd <> $hGUI1 And BitAND($wParam,0xFFF0) = $SC_MOVE Then Return False
  Return $GUI_RUNDEFMSG
EndFunc

 

Link to comment
Share on other sites

Link to comment
Share on other sites

Hello Nine :)
I tried it without using Func Move() , Gui1 having a default style and Gui2 a $WS_EX_MDICHILD extended style.
* Param -3 for left position of Gui2 is equal to Gui1 border size (this will align vertically both Gui's)
* Param 200 - 23 ( = 177) for top position of Gui2 was found after some experimentation, i.e :

=> created Gui1 with its left upper corner placed at Col 0, Row 0
=> height of Gui1 (including title & borders) is 232,  i.e 29 (title) + 200 (user's choice) + 3 (bottom border)
=> tried 0, 0 (left, top) for Gui2, it opens Gui2 at Row 55 (probably by design)
=> 232 - 55 = 177 (same as 200 - 23) it opens Gui2 at Row 232 (no gap, as Gui1 is placed just upper from Row 0 to Row 231)

#include <GuiConstants.au3>
#include <MsgBoxConstants.au3>

Global $hGUI1, $g_hGUI2 = 9999, $g_idButton3
Global Const $SC_MOVE = 0xF010
Gui1()

Func Gui1()
    $hGUI1 = GUICreate("Gui 1", 200, 200, 100, 100)
    Local $idButton1 = GUICtrlCreateButton("Msgbox 1", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Show Gui 2", 10, 60, 80, 30)
    GUISetState()

    GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)
        Switch $aMsg[1]

            Case $hGUI1
                Switch $aMsg[0]
                    Case $GUI_EVENT_CLOSE
                        ExitLoop
                    Case $idButton1
                        MsgBox($MB_OK, "MsgBox 1", "Test from Gui 1")
                    Case $idButton2
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        Gui2()
                EndSwitch

            Case $g_hGUI2
                Switch $aMsg[0]
                    Case $g_idButton3, $GUI_EVENT_CLOSE
                        GUIDelete($g_hGUI2)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                EndSwitch
        EndSwitch
    WEnd
EndFunc   ;==>Gui1

Func Gui2()
    $g_hGUI2 = GUICreate("", 200, 200, -3, 200 - 23, _
        BitXOR($GUI_SS_DEFAULT_GUI, $WS_MINIMIZEBOX), $WS_EX_MDICHILD, $hGUI1)
    $g_idButton3 = GUICtrlCreateButton("Close", 10, 10, 80, 30)
    GUISetState()
EndFunc   ;==>Gui2

Func WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)
    If $hWnd <> $hGUI1 And BitAND($wParam,0xFFF0) = $SC_MOVE Then Return False
    Return $GUI_RUNDEFMSG
EndFunc

 

Edited by pixelsearch
Link to comment
Share on other sites

I totally overlooked about $WS_EX_MDICHILD. Nice going.  Only problem with 200-23 thing with Win7 is that both windows overlap (needed to use 200-19).  Beside that, it is great...

Link to comment
Share on other sites

It was too tempting @pixelsearch.  I needed to find a way to have your approach fitting all OS and configuration.  I think it should work under all cases...

#include <GuiConstants.au3>
#include <MsgBoxConstants.au3>
#include <WinAPISysInternals.au3>
#include <Array.au3>

Global $hGUI1, $hGUI2 = 9999, $idButton3
Global Const $SC_MOVE = 0xF010
Gui1()

Func Gui1()
    $hGUI1 = GUICreate("Gui 1", 200, 200, 100, 100)
    Local $idButton1 = GUICtrlCreateButton("Msgbox 1", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Show Gui 2", 10, 60, 80, 30)
    GUISetState()

    GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)
        Switch $aMsg[1]

            Case $hGUI1
                Switch $aMsg[0]
                    Case $GUI_EVENT_CLOSE
                        ExitLoop
                    Case $idButton1
                        MsgBox($MB_OK, "MsgBox 1", "Test from Gui 1")
                    Case $idButton2
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        Gui2()
                EndSwitch

            Case $hGUI2
                Switch $aMsg[0]
                    Case $idButton3, $GUI_EVENT_CLOSE
                        GUIDelete($hGUI2)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                EndSwitch
        EndSwitch
    WEnd
EndFunc   ;==>Gui1

Func Gui2()
  Local $tRect = _WinAPI_GetClientRect($hGUI1)
  Local $aPos1 = WinGetPos ($hGUI1), $iClientWidth = DllStructGetData($tRect,"Right"), $iClientHeight = DllStructGetData($tRect,"Bottom")
  Local $iBorder = ($aPos1[2]-$iClientWidth)/2
  $hGUI2 = GUICreate("", $iClientWidth, $iClientHeight, -$iBorder, 0, _
        BitXOR($GUI_SS_DEFAULT_GUI, $WS_MINIMIZEBOX), $WS_EX_MDICHILD, $hGUI1)
  $idButton3 = GUICtrlCreateButton("Close", 10, 10, 80, 30)
  $aPos2 = WinGetPos($hGUI2)
  WinMove ($hGUI2, "", $aPos2[0], $aPos2[3]+$aPos1[1])
  GUISetState()
EndFunc   ;==>Gui2

Func WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)
    If $hWnd <> $hGUI1 And BitAND($wParam,0xFFF0) = $SC_MOVE Then Return False
    Return $GUI_RUNDEFMSG
EndFunc

 

Link to comment
Share on other sites

@Nine : great find, I didn't know at all that instruction _WinAPI_GetClientRect() , it will be very useful.
Am I missing something or this line could be improved :

WinMove ($hGUI2, "", $aPos2[0], $aPos2[3]+$aPos1[1])

Shouldn't it be :

WinMove ($hGUI2, "", $aPos2[0], $aPos1[3]+$aPos1[1])

Could you please try them both after adding a style to Gui1 and let us know your results ?

$hGUI1 = GUICreate("Gui 1", 200, 200, 100, 100, $WS_THICKFRAME)

Thanks :)

 

Link to comment
Share on other sites

8 minutes ago, pixelsearch said:

Shouldn't it be :

WinMove ($hGUI2, "", $aPos2[0], $aPos1[3]+$aPos1[1])

You mean

WinMove ($hGUI2, "", $aPos1[0], $aPos1[3]+$aPos1[1])

Agree, no need for $aPos2 at all...

Link to comment
Share on other sites

Nope, I didn't mean that :)
What I was trying to explain is that WinMove($hGUI2, ...) should always use $aPos1[3] and not $aPos2[3] as shown in the line in your script.

Imagine you add a style to Gui1 (I choose coords top / left to 0, 0 to simplify, in case diagrams will be needed in a further post)

$hGUI1 = GUICreate("Gui 1", 200, 200, 0, 0, BitOr($GUI_SS_DEFAULT_GUI, $WS_THICKFRAME))

Then you will get 2 pixels overlap of Gui2 over Gui 1 with this line of script :

WinMove ($hGUI2, "", $aPos2[0], $aPos2[3]+$aPos1[1])

But not with that one, where alignment should be perfect :

WinMove ($hGUI2, "", $aPos2[0], $aPos1[3]+$aPos1[1])

The reverse scenario would happen if Gui2 got the $WS_THICKFRAME style and not Gui1, for example :

$hGUI1 = GUICreate("Gui 1", 200, 200, 0, 0)
$hGUI2 = GUICreate("", $iClientWidth, $iClientHeight, -$iBorder, 0, _
    BitOr($GUI_SS_DEFAULT_GUI, $WS_THICKFRAME), $WS_EX_MDICHILD, $hGUI1)

Then there would a little gap (2 pixels) between both Gui's if you use $aPos2[3] instead of $aPos1[3] within WinMove($hGUI2, ...)

In the example of your script, both Gui's are well-placed (no overlap or gap) because they don't get any special style that change one Gui's height compared to the other Gui, that's why $aPos2[3] or $aPos1[3] can be used indifferently within WinMove($hGUI2, ...) . As soon as a style modifies the height of one of the Gui's then $aPos2[3] shows wrong results compared to $aPos1[3]

If it's not clear enough, I could post diagrams that may explain it better than words :)
Edit : as diagrams are ready, let's go !

1) Gui1 got no $WS_THICKFRAME style (nor Gui2), alignment of both Gui's is good (no overlap, no gap)

12a.png.1ee73b69b29b37add40a9508912a52b1.png

2) Gui1 got $WS_THICKFRAME style (border is 4 pixels now instead of 3), alignment is bad (2 pixels overlap) due to $aPos2[3] within WinMove($hGUI2, ...)

12b.png.c573eede907a4c93d3460fd8052c196f.png

3) Gui1 got $WS_THICKFRAME style (border is 4 pixels), alignment is good (no overlap) because of $aPos1[3] within WinMove($hGUI2, ...)

12c.png.b5cd1a946888111cf3d6bad24a76c64a.png

Last but not least, even if we are talking here about "only" 2 pixels (overlap or gap), let's not forget the cases where this good script of Nine could be used with Gui2 having a very different height than Gui1.

Then it would be mandatory to use $aPos1[3] within WinMove($hGUI2, ...) or you'd end with dozen of overlapping / gapping pixels if you use $aPos2[3] instead.

Edited by pixelsearch
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...