Jump to content
Sign in to follow this  
AZJIO

Child window is always in the center or in the visible region

Recommended Posts

AZJIO

I have a _ChildCoor function to get the coordinates of the child window.

I found that Regedit creates a child window with the same properties.

The question: which style should I specify to get such properties?

1. Window always in the center of the parent window

2. If the window is moved off screen, the child window will always be in the visible area of the screen.

#include <WindowsConstants.au3>

$Gui = GUICreate('My program', 420, 250)
$MsgBox = GUICtrlCreateButton("Button", 20, 20, 90, 30)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $MsgBox
            _MsgBox()
        Case -3
            Exit
    EndSwitch
WEnd

Func _MsgBox()
    Local $EditBut, $Gui1, $GP, $msg, $StrBut
    $GP = _ChildCoor($Gui, 410, 240)
    GUISetState(@SW_DISABLE, $Gui)

    $Gui1 = GUICreate('Message', $GP[2], $GP[3], $GP[0], $GP[1], $WS_CAPTION + $WS_SYSMENU + $WS_POPUP, -1, $Gui)
    GUICtrlCreateLabel('What do we do now?', 20, 10, 180, 23)
    $EditBut = GUICtrlCreateButton('Editor', 10, 40, 80, 22)
    $StrBut = GUICtrlCreateButton('Calculator', 100, 40, 80, 22)
    GUISetState(@SW_SHOW, $Gui1)
    While 1
        Switch GUIGetMsg()
            Case $EditBut
                Run('Notepad.exe')
            Case $StrBut
                ShellExecute('Calc.exe')
            Case -3
                GUISetState(@SW_ENABLE, $Gui)
                GUIDelete($Gui1)
                ExitLoop
        EndSwitch
    WEnd
EndFunc

; вычисление координат дочернего окна
; 1 - the parent window handle
; 2 - width
; 3 - height
; 4 - 0 - on the Center, 1 - to the left top of the parent window
; 5 - offset from edges
Func _ChildCoor($Gui, $w, $h, $c = 0, $d = 0)
    Local $aWA = _WinAPI_GetWorkingArea(), _
            $GP = WinGetPos($Gui), _
            $wgcs = WinGetClientSize($Gui)
    Local $dLeft = ($GP[2] - $wgcs[0]) / 2, _
            $dTor = $GP[3] - $wgcs[1] - $dLeft
    If $c = 0 Then
        $GP[0] = $GP[0] + ($GP[2] - $w) / 2 - $dLeft
        $GP[1] = $GP[1] + ($GP[3] - $h - $dLeft - $dTor) / 2
    EndIf
    If $d > ($aWA[2] - $aWA[0] - $w - $dLeft * 2) / 2 Or $d > ($aWA[3] - $aWA[1] - $h - $dLeft + $dTor) / 2 Then $d = 0
    If $GP[0] + $w + $dLeft * 2 + $d > $aWA[2] Then $GP[0] = $aWA[2] - $w - $d - $dLeft * 2
    If $GP[1] + $h + $dLeft + $dTor + $d > $aWA[3] Then $GP[1] = $aWA[3] - $h - $dLeft - $dTor - $d
    If $GP[0] <= $aWA[0] + $d Then $GP[0] = $aWA[0] + $d
    If $GP[1] <= $aWA[1] + $d Then $GP[1] = $aWA[1] + $d
    $GP[2] = $w
    $GP[3] = $h
    Return $GP
EndFunc

Func _WinAPI_GetWorkingArea()
    Local Const $SPI_GETWORKAREA = 48
    Local $stRECT = DllStructCreate("long; long; long; long")

    Local $SPIRet = DllCall("User32.dll", "int", "SystemParametersInfo", "uint", $SPI_GETWORKAREA, "uint", 0, "ptr", DllStructGetPtr($stRECT), "uint", 0)
    If @error Then Return 0
    If $SPIRet[0] = 0 Then Return 0

    Local $sLeftArea = DllStructGetData($stRECT, 1)
    Local $sTopArea = DllStructGetData($stRECT, 2)
    Local $sRightArea = DllStructGetData($stRECT, 3)
    Local $sBottomArea = DllStructGetData($stRECT, 4)

    Local $aRet[4] = [$sLeftArea, $sTopArea, $sRightArea, $sBottomArea]
    Return $aRet
EndFunc
Edited by AZJIO

Share this post


Link to post
Share on other sites
AZJIO

It does not contain the answer.

I looked at the styles of the child window in regedit and used them. It has no effect.

Likely using the function calculate the coordinates.

Share this post


Link to post
Share on other sites
UEZ

Sorry, but I cannot fully understand your problem. Can you describe it again?

Further I cannot see any child window in regedit.

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
AZJIO

No good

#include <WindowsConstants.au3>

$hGui = GUICreate('My program', 1024, 650)
$MsgBox = GUICtrlCreateButton("Button", 20, 20, 90, 30)
GUISetState()
WinMove($hGui, '', -211, 11)
_MsgBox()

Func _MsgBox()
    GUISetState(@SW_DISABLE, $hGui)

    Local $Gui1 = GUICreate('Error message', 110, 150, -1, -1, $GUI_SS_DEFAULT_GUI, $WS_EX_MDICHILD, $hGui)
    GUISetState(@SW_SHOW, $Gui1)
    While 1
        Switch GUIGetMsg()
            Case -3
                GUISetState(@SW_ENABLE, $hGui)
                GUIDelete($Gui1)
                ExitLoop
        EndSwitch
    WEnd
EndFunc[/code]

No good
[code='autoit']#include <WindowsConstants.au3>

$hGui = GUICreate('My program', 420, 250)
$MsgBox = GUICtrlCreateButton("Button", 20, 20, 90, 30)
GUISetState()
WinMove($hGui, '', 11, 11)
_MsgBox()

Func _MsgBox()
    GUISetState(@SW_DISABLE, $hGui)

    Local $Gui1 = GUICreate('In the center of the screen', 410, 240, -1, -1, -1, -1, $hGui)
    GUISetState(@SW_SHOW, $Gui1)
    While 1
        Switch GUIGetMsg()
            Case -3
                GUISetState(@SW_ENABLE, $hGui)
                GUIDelete($Gui1)
                ExitLoop
        EndSwitch
    WEnd
EndFunc[/code]

Very good
[code='autoit']Run('notepad.exe')
$hWnd = WinWait("[CLASS:Notepad]", "", 5)
If Not $hWnd Then Exit
WinMove($hWnd, '', -211, 11, 300, 300)
Send('f')
If @OSLang = 0419 Then
    Send('^а')
Else
    Send('^f')
EndIf
Edited by AZJIO

Share this post


Link to post
Share on other sites
UEZ

Something like that here?

#include <WindowsConstants.au3>

$hGui = GUICreate('My program', 420, 250)
$MsgBox = GUICtrlCreateButton("Button", 20, 20, 90, 30)
WinMove($hGui, '', Random(-200, 500, 1),  Random(0, @DesktopHeight * 0.80, 1))
GUISetState()
_MsgBox()

Func _MsgBox()
    GUISetState(@SW_DISABLE, $hGui)
    $aPos = WinGetPos($hGui)
    Local $Gui1 = GUICreate('In the center of the screen', 410, 240, Min(@DesktopWidth - 420, Max(0, $aPos[0] + 10)), Min(@DesktopHeight - 250, Max(0, $aPos[1] + 30)), -1, -1, $hGui)
    GUISetState(@SW_SHOW, $Gui1)
    While 1
        Switch GUIGetMsg()
            Case -3
                GUISetState(@SW_ENABLE, $hGui)
                GUIDelete($Gui1)
                ExitLoop
        EndSwitch
    WEnd
EndFunc

Func Max($a, $b)
    If $a > $b Then Return $a
    Return $b
EndFunc

Func Min($a, $b)
    If $a < $b Then Return $a
    Return $b
EndFunc

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
AZJIO

UEZ

In the first post, I suggested a better function.

I assumed that there is a native function, i.e. calling DllCall to get the coordinates of the child window.

Share this post


Link to post
Share on other sites
AoRaToS

To make the child window always appear in the center try this:

I use this to make controls always be at the center of a GUI even if i change the GUI or control sizes, without having to measure, you just use (WindowWidth/2 - ControlWidth/2) for the control "left" position and the (WindowHeight/2 - ControlHeight/2) for the "top" position. All you need to do is a GUIGetPos on the GUI and declare ControlWidth and ControlHeight before.In this case I added it to the coordinates of the main window.

#include <WindowsConstants.au3>

Opt("GUICoordMode", 2)

$hGui = GUICreate('My program', 420, 250)
$MsgBox = GUICtrlCreateButton("Button", 20, 20, 90, 30)
WinMove($hGui, '', Random(-200, 500, 1), Random(0, @DesktopHeight * 0.80, 1))
GUISetState()
_MsgBox()

Func _MsgBox()
GUISetState(@SW_DISABLE, $hGui)
$aPos = WinGetPos($hGui)
Local $Gui1w = 320
Local $Gui1h = 200
Local $Gui1 = GUICreate('In the center of the screen', $Gui1w, $Gui1h, $aPos[0] + (($aPos[2]/2) - ($Gui1w/2)), $aPos[1] + (($aPos[3]/2) - ($Gui1h/2)),Default, -1, $hGui)
GUISetState(@SW_SHOW, $Gui1)
While 1
     Switch GUIGetMsg()
         Case -3
             GUISetState(@SW_ENABLE, $hGui)
             GUIDelete($Gui1)
             ExitLoop
     EndSwitch
WEnd
EndFunc
Edited by AoRaToS

s!mpL3 LAN Messenger

Current version 2.9.8.8 [30/09/2015]

Download Here

s!mpL3

Share this post


Link to post
Share on other sites
AZJIO

AoRaToS

I'm a bit straightened your example, try it now and compare it to mine.

#include <WindowsConstants.au3>

Opt("GUICoordMode", 2)

$hGui = GUICreate('My program', 420, 250)
$MsgBox = GUICtrlCreateButton("Button", 20, 20, 90, 30)
WinMove($hGui, '', Random(-200, 500, 1), Random(0, @DesktopHeight * 0.80, 1))
GUISetState()
WinMove($hGui, '', -380, 11)
_MsgBox()

Func _MsgBox()
GUISetState(@SW_DISABLE, $hGui)
$aPos = WinGetPos($hGui)
Local $Gui1w = 320
Local $Gui1h = 200
Local $Gui1 = GUICreate('In the center of the screen', $Gui1w, $Gui1h, $aPos[0] + (($aPos[2]/2) - ($Gui1w/2)), $aPos[1] + (($aPos[3]/2) - ($Gui1h/2)),Default, -1, $hGui)
GUISetState(@SW_SHOW, $Gui1)
While 1
     Switch GUIGetMsg()
         Case -3
             GUISetState(@SW_ENABLE, $hGui)
             GUIDelete($Gui1)
             ExitLoop
     EndSwitch
WEnd
EndFunc
Edited by AZJIO

Share this post


Link to post
Share on other sites
PlayHD

what you say something like this :

Global $Form = GUICreate("Form Parent", 615, 437)
GUISetState(@SW_SHOW)

_msgBox($Form)
Exit GUIDelete($Form)

Func _msgBox($wHwnd)
;if you don't want to use any parameter remove under comment line bellow and delete the parameter from function and function call
;~ $wHwnd = $Form
GUISetState(@SW_DISABLE,$wHwnd)
Local $lOpt_WinTitleMode = Opt("WinTitleMatchMode",4)
Local $WinPos = WinGetPos($wHwnd)
Local $WinSize = WinGetClientSize($wHwnd)
Local $ChildWidth = 322
Local $ChildHeight = 182
Local $Form_m = GUICreate("Form Child", $ChildWidth, $ChildHeight,$WinPos[0]+ 8 + $WinSize[0]/2-$ChildWidth/2,$WinPos[1]+ 8 + $WinSize[1]/2-$ChildHeight/2,-1,-1,$wHwnd)
Local $nMsg
GUISetState(@SW_SHOW,$Form_m)

While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case -3;$GUI_EVENT_CLOSE
GUIDelete($Form_m)
GUISetState(@SW_ENABLE,$wHwnd)
Return Opt("WinTitleMatchMode",$lOpt_WinTitleMode)
EndSwitch
WEnd
Return 5
EndFunc
Edited by PlayHD

Share this post


Link to post
Share on other sites
AZJIO

PlayHD

I'm a bit straightened your example, try it now and compare it to mine.

Global $Form = GUICreate("Form Parent", 615, 437)
GUISetState(@SW_SHOW)
WinMove($Form, '', -480, 11)

_msgBox($Form)
Exit GUIDelete($Form)

Func _msgBox($wHwnd)
    ;if you don't want to use any parameter remove under comment line bellow and delete the parameter from function and function call
;~ $wHwnd = $Form
    GUISetState(@SW_DISABLE, $wHwnd)
    Local $lOpt_WinTitleMode = Opt("WinTitleMatchMode", 4)
    Local $WinPos = WinGetPos($wHwnd)
    Local $WinSize = WinGetClientSize($wHwnd)
    Local $ChildWidth = 322
    Local $ChildHeight = 182
    Local $Form_m = GUICreate("Form Child", $ChildWidth, $ChildHeight, $WinPos[0] + 8 + $WinSize[0] / 2 - $ChildWidth / 2, $WinPos[1] + 8 + $WinSize[1] / 2 - $ChildHeight / 2, -1, -1, $wHwnd)
    Local $nMsg
    GUISetState(@SW_SHOW, $Form_m)

    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case -3;$GUI_EVENT_CLOSE
                GUIDelete($Form_m)
                GUISetState(@SW_ENABLE, $wHwnd)
                Return Opt("WinTitleMatchMode", $lOpt_WinTitleMode)
        EndSwitch
    WEnd
    Return 5
EndFunc

Now imagine the situation: I move it to the box to the left, and after a time window reports an error. But I do not have access to the child window, but to the ability to kill the process. Do you think this is a normal way of programming? You repeat the previous example.

Edited by AZJIO

Share this post


Link to post
Share on other sites
KaFu
AoRaToS

Hello again,

I use another function for that which should be called within the _MsgBox(). I don't know if there are any better solutions but what you can do is check the position of the main window and bring it on to screen. I doubt a GUI style can do this.

This should fix your issue.

#include <WindowsConstants.au3>

Opt("GUICoordMode", 2)

$hGui = GUICreate('My program', 420, 250)
$MsgBox = GUICtrlCreateButton("Button", 20, 20, 90, 30)
WinMove($hGui, '', Random(-200, 500, 1), Random(0, @DesktopHeight * 0.80, 1))
GUISetState()
WinMove($hGui, '', -380, 11)
_MsgBox()

Func _MsgBox()
GUISetState(@SW_DISABLE, $hGui)
BringtoScreen()
$aPos = WinGetPos($hGui)
Local $Gui1w = 320
Local $Gui1h = 200
Local $Gui1 = GUICreate('In the center of the screen', $Gui1w, $Gui1h, $aPos[0] + (($aPos[2]/2) - ($Gui1w/2)), $aPos[1] + (($aPos[3]/2) - ($Gui1h/2)),Default, -1, $hGui)
GUISetState(@SW_SHOW, $Gui1)
While 1
     Switch GUIGetMsg()
         Case -3
             GUISetState(@SW_ENABLE, $hGui)
             GUIDelete($Gui1)
             ExitLoop
     EndSwitch
WEnd
EndFunc

Func BringtoScreen()
    Local $x, $y
    $position = WinGetPos($hGui)
    If $position[0] < 0 Then
        $x = -1
    ElseIf $position[0] > @DesktopWidth Then
        $x = 1
    Else
        $x = $position[0]
    EndIf
    If $position[1] < 0 Then
        $y = -1
    ElseIf $position[1] > @DesktopHeight Then
        $y = 1
    Else
        $y = $position[1]
    EndIf
    If $x = -1 Then
        If $y = -1 Then
            WinMove($hGui, "", 0, 0)
        ElseIf $y = 1 Then
            WinMove($hGui, "", 0, @DesktopHeight - ($position[3] + 3))
        Else
            If $y > @DesktopHeight - ($position[3] + 3) Then
                WinMove($hGui, "", 0, @DesktopHeight - ($position[3] + 3))
            Else
                WinMove($hGui, "", 0, $y)
            EndIf
        EndIf
    ElseIf $x = 1 Then
        If $y = -1 Then
            WinMove($hGui, "", @DesktopWidth - $position[2], 0)
        ElseIf $y = 1 Then
            WinMove($hGui, "", @DesktopWidth - $position[2], @DesktopHeight - ($position[3] + 3))
        Else
            If $y > @DesktopHeight - ($position[3] + 3) Then
                WinMove($hGui, "", @DesktopWidth - $position[2], @DesktopHeight - ($position[3] + 3))
            Else
                WinMove($hGui, "", @DesktopWidth - $position[2], $y)
            EndIf
        EndIf
    Else
        If $y = -1 Then
            If $x > @DesktopWidth - $position[2] Then
                WinMove($hGui, "", @DesktopWidth - $position[2], 0)
            Else
                WinMove($hGui, "", $x, 0)
            EndIf
        ElseIf $y = 1 Then
            If $x > @DesktopWidth - $position[2] Then
                WinMove($hGui, "", @DesktopWidth - $position[2], @DesktopHeight - ($position[3] + 3))
            Else
                WinMove($hGui, "", $x, @DesktopHeight - ($position[3] + 3))
            EndIf
        Else
            If $x > @DesktopWidth - $position[2] And $y > @DesktopHeight - ($position[3] + 3) Then
                WinMove($hGui, "", @DesktopWidth - $position[2], @DesktopHeight - ($position[3] + 3))
            ElseIf $x > @DesktopWidth - $position[2] Then
                WinMove($hGui, "", @DesktopWidth - $position[2], $y)
            ElseIf $y > @DesktopHeight - ($position[3] + 3) Then
                WinMove($hGui, "", $x, @DesktopHeight - ($position[3] + 3))
            EndIf
        EndIf
    EndIf
EndFunc   ;==>BringtoScreen

I have been using this in s!mpL3 LAN Messenger to bring the main window on to screen if it is left off screen. I changed it a bit and removed some things that weren't needed in this case.

Another function can be called after, to move the window back to where you had it.

Did the first script I posted answer your first question?

Edited by AoRaToS

s!mpL3 LAN Messenger

Current version 2.9.8.8 [30/09/2015]

Download Here

s!mpL3

Share this post


Link to post
Share on other sites
AZJIO

CalculatePopupWindowPosition

Minimum supported client Windows 7 [desktop apps only]

Share this post


Link to post
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
Sign in to follow this  

×