Что нового

_MoveWindow() - Установка положения дочернего окна относительно родительского

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,717
Функция перемещает одно окно ($hWnd) относительно клиентской области другого окна ($hParent) на расстояние, заданное параметрами $iX и $iY, как это обычно делает Windows при открытии дочерних окон. Может быть полезна а программах, работающих с несколькими окнами.

Код:
$hParent = GUICreate('Parent', 300, 300)
$hForm = GUICreate('Form', 200, 200)

GUISetState(@SW_SHOW, $hParent)
GUISetState(@SW_SHOW, $hForm)

Sleep(1000)

_MoveWindow($hForm, $hParent, 0, 0)

Do
Until GUIGetMsg() = -3

Func _MoveWindow($hWnd, $hParent = 0, $iX = Default, $iY = Default, $iW = -1, $iH = -1, $fClient = 1, $fResize = 0)

	Local $Area[4], $Wx[2], $Cx[2], $tRect, $pRect, $Pos, $Ret

	$Ret = DllCall('user32.dll', 'long', 'GetWindowLongW', 'hwnd', $hWnd, 'int', -16)
	If (@error) Or (BitAND($Ret[0], 0x21000000)) Then
		Return 0
	EndIf
	$Pos = WinGetPos($hWnd)
	If @error Then
		Return 0
	EndIf
	If $iW = -1 Then
		$iW = $Pos[2]
	EndIf
	If $iH = -1 Then
		$iH = $Pos[3]
	EndIf
	$tRect = DllStructCreate('int;int;int;int')
	$pRect = DllStructGetPtr($tRect)
	$Ret = DllCall('dwmapi.dll', 'uint', 'DwmGetWindowAttribute', 'hwnd', $hWnd, 'dword', 9, 'ptr', $pRect, 'dword', 16)
	If (Not @error) And (Not $Ret[0]) Then
		For $i = 0 To 1
			$Wx[$i] = DllStructGetData($tRect, $i + 3) - DllStructGetData($tRect, $i + 1) - $Pos[$i + 2]
		Next
	Else
		For $i = 0 To 1
			$Wx[$i] = 0
		Next
	EndIf
	$iW += $Wx[0]
	$iH += $Wx[1]
	$Ret = DllCall('user32.dll', 'int', 'SystemParametersInfoW', 'uint', 0x0030, 'uint', 0, 'ptr', $pRect, 'uint', 0)
	If (@error) Or (Not $Ret[0]) Then
		$Area[0] = 0
		$Area[1] = 0
		$Area[2] = @DesktopWidth
		$Area[3] = @DesktopHeight
	Else
		For $i = 0 To 3
			$Area[$i] = DllStructGetData($tRect, $i + 1)
		Next
	EndIf
	Do
		If $hParent Then
			$Ret = DllCall('user32.dll', 'long', 'GetWindowLongW', 'hwnd', $hParent, 'int', -16)
			If @error Then
				Return 0
			EndIf
			If Not BitAND($Ret[0], 0x20000000) Then
				If $fClient Then
					$Ret = DllCall('user32.dll', 'int', 'GetClientRect', 'hwnd', $hParent, 'ptr', $pRect)
					If (@error) Or (Not $Ret[0]) Then
						Return 0
					EndIf
					$Ret = DllCall('user32.dll', 'int', 'ClientToScreen', 'hwnd', $hParent, 'ptr', $pRect)
					If (@error) Or (Not $Ret[0]) Then
						Return 0
					EndIf
					If $iX = Default Then
						$iX = Int((DllStructGetData($tRect, 3) - $iW) / 2)
					EndIf
					If $iY = Default Then
						$iY = Int((DllStructGetData($tRect, 4) - $iH) / 2)
					EndIf
					$iX += DllStructGetData($tRect, 1)
					$iY += DllStructGetData($tRect, 2)
				Else
					$Pos = WinGetPos($hParent)
					If @error Then
						Return 0
					EndIf
					$Ret = DllCall('dwmapi.dll', 'uint', 'DwmGetWindowAttribute', 'hwnd', $hParent, 'dword', 9, 'ptr', $pRect, 'dword', 16)
					If (Not @error) And (Not $Ret[0]) Then
						For $i = 0 To 1
							$Cx[$i] = DllStructGetData($tRect, $i + 3) - DllStructGetData($tRect, $i + 1) - $Pos[$i + 2]
						Next
					Else
						For $i = 0 To 1
							$Cx[$i] = 0
						Next
					EndIf
					If $iX = Default Then
						$iX = Int(($Pos[2] + $Cx[0] - $iW) / 2)
					EndIf
					If $iY = Default Then
						$iY = Int(($Pos[3] + $Cx[1] - $iH) / 2)
					EndIf
					$iX += $Pos[0] - $Cx[0] / 2
					$iY += $Pos[1] - $Cx[1] / 2
				EndIf
				ExitLoop
			EndIf
		EndIf
		If $iX = Default Then
			$iX = Int(($Area[2] - $iW) / 2)
		EndIf
		If $iY = Default Then
			$iY = Int(($Area[3] - $iH) / 2)
		EndIf
		$iX += $Area[0]
		$iY += $Area[1]
	Until 1
	$iX += $Wx[0] / 2
	$iY += $Wx[1] / 2
	If ($fResize) And ($iW > $Area[2] - $Area[0]) Then
		$iW = $Area[2] - $Area[0] - $Wx[0]
	EndIf
	If ($fResize) And ($iH > $Area[3] - $Area[1]) Then
		$iH = $Area[3] - $Area[1] - $Wx[1]
	EndIf
	If $iX > $Area[2] - $iW Then
		$iX = $Area[2] - $iW + $Wx[0] / 2
	EndIf
	If $iX < $Area[0] Then
		$iX = $Area[0] + $Wx[0] / 2
	EndIf
	If $iY > $Area[3] - $iH Then
		$iY = $Area[3] - $iH + $Wx[1] / 2
	EndIf
	If $iY < $Area[1] Then
		$iY = $Area[1] + $Wx[1] / 2
	EndIf
	If WinMove($hWnd, '', $iX, $iY, $iW - $Wx[0], $iH - $Wx[1]) Then
		Return 0
	Else
		Return 1
	EndIf
EndFunc   ;==>_MoveWindow


 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,717
Re: _MoveWindo() - Установка положения дочернего окна относительно родительского

Обновил функцию. Теперь, если $iX = -1 или $iY = -1, дочернее окно располагается в центре клиентской области родительского окна (см. пример).

:smile:
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,717
Полностью переписал функцию. Теперь учитывается рабочая область и Aero (см. скриншоты). Окно может распологаться как относительно родительского окна (левый верхний угол или клиентская область, параметр $fClient), так и относительно рабочей области. Также добавил возможность изменять размеры дочернего окна.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,320
OffTopic:
Yashied
Как ни странно, особенно в последнее время ;D, но у меня на XP работает без проблем. :smile:
 
Верх