Opened 10 years ago
Closed 4 years ago
#2786 closed Bug (Wont Fix)
MDI childs don't adjust to parent windows client rect #2
Reported by: | Synix <cross.fire@…> | Owned by: | |
---|---|---|---|
Milestone: | Component: | AutoIt | |
Version: | 3.3.8.1 | Severity: | None |
Keywords: | $WS_EX_MDICHILD, $WS_POPUP | Cc: |
Description
#1013 was about child windows of parent GUIs with $WS_CAPTION style. This is fixed and works fine.
If the parent GUI has the style $WS_POPUP and no caption, the offset of the MDI child window differs with the different border styles and can not be properly aligned on top of the parent GUI. This is a major problem if you e.g. want to work with layered child windows.
I have an example code to show this, with a potential workaround, that at least does work for my Win7 and Win8 machine:
#include <GUIConstants.au3> Global $aSM_CYBORDER = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYBORDER) Global $aSM_CYEDGE = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYEDGE) ;3-D counterpart of SM_CYBORDER Global $aSM_CYDLGFRAME = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYDLGFRAME) ;same as SM_CYFIXEDFRAME Global $aSM_CYFRAME = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYFRAME) ;same as SM_CYSIZEFRAME ;~ Exit MsgBox(0, "", $aSM_CYBORDER[0] & " - " & $aSM_CYEDGE[0] & " - " & $aSM_CYDLGFRAME[0] & " - " & $aSM_CYFRAME[0]) For $i = 1 To 2 $bOffsetFix = ($i = 1 ? False : True) MsgBox(0, "Offset Fix", $bOffsetFix) ;$WS_DLGFRAME + $WS_BORDER = $WS_CAPTION ;$WS_CAPTION always works fine with offset=0 _GUIs($bOffsetFix, 0) _GUIs($bOffsetFix, $WS_DLGFRAME) ;works fine with offset=0 _GUIs($bOffsetFix, $WS_BORDER) _GUIs($bOffsetFix, $WS_THICKFRAME) _GUIs($bOffsetFix, BitOR($WS_THICKFRAME, $WS_DLGFRAME)) _GUIs($bOffsetFix, BitOR($WS_THICKFRAME, $WS_BORDER)) Next Func _GUIs($bOffsetFix, $iBorder) Local $iW = 220, $iH = 220, $iOffset = ($bOffsetFix ? _OffsetFix($iBorder) : 0) $hGUI = GUICreate('MDI Example', $iW, $iH, -1, -1, BitOR($WS_POPUP, $iBorder)) GUISetBkColor(0x000000) $hChild = GUICreate('', $iW, $iH, $iOffset, $iOffset, $WS_POPUP, $WS_EX_MDICHILD, $hGUI) GUISetBkColor(0xdddddd) GUICtrlCreateLabel('Child GUI offset: ' & ($iOffset >= 0 ? '+' : '') & $iOffset & ' px' & @CRLF & _ 'Main GUI style:' & @TAB & ' $WS_POPUP ' & _ (_StyleInStyle($iBorder, $WS_CAPTION) ? @CRLF & @TAB & @TAB & ' +$WS_CAPTION' : '') & _ (_StyleInStyle($iBorder, $WS_BORDER) ? @CRLF & @TAB & @TAB & ' +$WS_BORDER' : '') & _ (_StyleInStyle($iBorder, $WS_THICKFRAME) ? @CRLF & @TAB & @TAB & ' +$WS_THICKFRAME' : '') & _ (_StyleInStyle($iBorder, $WS_DLGFRAME) ? @CRLF & @TAB & @TAB & ' +$WS_DLGFRAME' : '') & _ @CRLF & @CRLF & 'Press [Esc]', 10, 10) GUISetState(@SW_SHOW, $hGUI) GUISetState(@SW_SHOW, $hChild) While GUIGetMsg() <> -3 WEnd GUIDelete($hChild) GUIDelete($hGUI) EndFunc Func _OffsetFix($iBorder) Local $iRet = 0 If Not _StyleInStyle($iBorder, $WS_CAPTION) Then If Not _StyleInStyle($iBorder, $WS_DLGFRAME) Then $iRet += $aSM_CYDLGFRAME[0] ;+3 If _StyleInStyle($iBorder, $WS_BORDER) Then $iRet -= $aSM_CYBORDER[0] ;-1 If _StyleInStyle($iBorder, $WS_THICKFRAME) Then $iRet -= $aSM_CYFRAME[0] ;-8 If _StyleInStyle($iBorder, $WS_DLGFRAME) Then $iRet += $aSM_CYDLGFRAME[0] ;+3 Else $iRet += $aSM_CYBORDER[0] ;+1 EndIf EndIf EndIf Return $iRet EndFunc Func _StyleInStyle($iSrc, $iSearch) Return BitAND($iSrc, $iSearch) = $iSearch EndFunc
In #1866 someone reported this issue and it got rejected. Though it wasn't a great example with all the different border styles demonstrated. So I follow the comment of trancexx from that ticket: "If anyone sees any sense in this then please make another report."
Please try to fix this internally, so an MDI child always aligns correctly with its parent.
Thanks in advance :)
Attachments (0)
Change History (6)
comment:1 Changed 10 years ago by Synix <cross.fire@…>
comment:2 Changed 10 years ago by Synix <cross.fire@…>
Update
$WS_CAPTION does not always work fine (when using $WS_THICKFRAME), see updated example with new offset fix:
#include <GUIConstants.au3> Global $aSM_CYBORDER = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYBORDER) Global $aSM_CYEDGE = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYEDGE) ;3-D counterpart of SM_CYBORDER Global $aSM_CYDLGFRAME = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYDLGFRAME) ;same as SM_CYFIXEDFRAME Global $aSM_CYFRAME = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $SM_CYFRAME) ;same as SM_CYSIZEFRAME ;~ Exit MsgBox(0, "", $aSM_CYBORDER[0] & " - " & $aSM_CYEDGE[0] & " - " & $aSM_CYDLGFRAME[0] & " - " & $aSM_CYFRAME[0]) For $i = 1 To 2 $bOffsetFix = ($i = 1 ? False : True) MsgBox(0, "Offset Fix", $bOffsetFix) ;$WS_DLGFRAME + $WS_BORDER = $WS_CAPTION ;$WS_CAPTION always works fine with offset=0, except together with $WS_THICKFRAME _GUIs($bOffsetFix, 0) _GUIs($bOffsetFix, $WS_DLGFRAME) ;works fine with offset=0 _GUIs($bOffsetFix, $WS_BORDER) _GUIs($bOffsetFix, $WS_THICKFRAME) _GUIs($bOffsetFix, BitOR($WS_THICKFRAME, $WS_DLGFRAME)) _GUIs($bOffsetFix, BitOR($WS_THICKFRAME, $WS_BORDER)) _GUIs($bOffsetFix, BitOR($WS_THICKFRAME, $WS_DLGFRAME, $WS_BORDER)) ;= $WS_CAPTION & $WS_THICKFRAME Next Func _GUIs($bOffsetFix, $iBorder) Local $iW = 220, $iH = 220, $iOffset = ($bOffsetFix ? _OffsetFix($iBorder) : 0) $hGUI = GUICreate('MDI Example', $iW, $iH, -1, -1, BitOR($WS_POPUP, $iBorder)) GUISetBkColor(0x000000) $hChild = GUICreate('', $iW, $iH, $iOffset, $iOffset, $WS_POPUP, $WS_EX_MDICHILD, $hGUI) GUISetBkColor(0xdddddd) GUICtrlCreateLabel('Child GUI offset: ' & ($iOffset >= 0 ? '+' : '') & $iOffset & ' px' & @CRLF & _ 'Main GUI style:' & @TAB & ' $WS_POPUP ' & _ (_StyleInStyle($iBorder, $WS_CAPTION) ? @CRLF & @TAB & @TAB & ' +$WS_CAPTION' : '') & _ (_StyleInStyle($iBorder, $WS_BORDER) ? @CRLF & @TAB & @TAB & ' +$WS_BORDER' : '') & _ (_StyleInStyle($iBorder, $WS_THICKFRAME) ? @CRLF & @TAB & @TAB & ' +$WS_THICKFRAME' : '') & _ (_StyleInStyle($iBorder, $WS_DLGFRAME) ? @CRLF & @TAB & @TAB & ' +$WS_DLGFRAME' : '') & _ @CRLF & @CRLF & 'Press [Esc]', 10, 10) GUISetState(@SW_SHOW, $hGUI) GUISetState(@SW_SHOW, $hChild) While GUIGetMsg() <> -3 WEnd GUIDelete($hChild) GUIDelete($hGUI) EndFunc Func _OffsetFix($iBorder) Local $iRet = 0 If _StyleInStyle($iBorder, $WS_THICKFRAME) Then $iRet -= $aSM_CYFRAME[0] / 2 ;-(8/2) If _StyleInStyle($iBorder, $WS_DLGFRAME) Or _StyleInStyle($iBorder, $WS_BORDER) Then $iRet -= $aSM_CYBORDER[0] ;+1 ElseIf Not _StyleInStyle($iBorder, $WS_CAPTION) Then If Not _StyleInStyle($iBorder, $WS_DLGFRAME) Then $iRet += $aSM_CYDLGFRAME[0] ;+3 If _StyleInStyle($iBorder, $WS_BORDER) Then $iRet -= $aSM_CYBORDER[0] ;-1 EndIf Return $iRet EndFunc Func _StyleInStyle($iSrc, $iSearch) Return BitAND($iSrc, $iSearch) = $iSearch EndFunc
comment:3 Changed 10 years ago by qwert
I would like to confirm that this IS a problem in 3.3.12.0
I've spent many hours trying to get a handle on this. I made a post back in July ("Child window elements become disassociated from parent"), but only today noticed this bug report.
For my application, it somehow seems to be associated the Windows standby mode. I say that because I almost always see the effect when coming out of standby on Windows 8. The child elements are off by a couple hundred pixels, but move "in parallel" when I drag the parent window.
This is a MAJOR PROBLEM that needs a solution or at least a workaround. I'll examine the methods above in detail and try to implement a temporary fix. But I look forward to hearing that there's a solution in the works.
comment:4 Changed 10 years ago by Synix <cross.fire@…>
I also noticed that the offset of an MDI child changes completely, if the child has other styles set than in my example. $WS_CAPTION on the MDI child will cause an offset different from $WS_POPUP. Setting the MDI childs style to 0 will again behave differently.
comment:5 Changed 10 years ago by Synix <cross.fire@…>
Updated my code to fix positioning of windows with captions etc.
The function returns an array with x and y offset values. It's not quite perfect and the bottom half is still a sloppy solution for popupwindows, but it all works pretty well already.
Func _WinMDIGetOffset($hParent, $iStyleChild) ;returns an array with offset values to fix positioning of an MDI child Local $aRet[2] = [0, 0], $iStyleParent $iStyleParent = _WinAPI_GetWindowLong($hParent, $GWL_STYLE) If BitAND($iStyleChild, $WS_BORDER) = $WS_BORDER Or Not (BitAND($iStyleChild, $WS_POPUP) = $WS_POPUP) Then ;add each two horizontal/vertical border sizes of the child window $aRet[0] += _WinAPI_GetSystemMetrics($SM_CXBORDER) * 2 $aRet[1] += _WinAPI_GetSystemMetrics($SM_CYBORDER) * 2 If BitAND($iStyleParent, $WS_BORDER) = $WS_BORDER Or Not (BitAND($iStyleParent, $WS_POPUP) = $WS_POPUP) Then ;subtract the left and top border of the parent window $aRet[0] -= _WinAPI_GetSystemMetrics($SM_CXBORDER) $aRet[1] -= _WinAPI_GetSystemMetrics($SM_CYBORDER) EndIf EndIf If BitAND($iStyleChild, $WS_DLGFRAME) = $WS_DLGFRAME Or Not (BitAND($iStyleChild, $WS_POPUP) = $WS_POPUP) Then ;add each two horizontal/vertical border sizes of the child window $aRet[0] += _WinAPI_GetSystemMetrics($SM_CXDLGFRAME) * 2 $aRet[1] += _WinAPI_GetSystemMetrics($SM_CYDLGFRAME) * 2 If BitAND($iStyleParent, $WS_DLGFRAME) = $WS_DLGFRAME Or Not (BitAND($iStyleParent, $WS_POPUP) = $WS_POPUP) Then ;subtract the left and top border of the parent window $aRet[0] -= _WinAPI_GetSystemMetrics($SM_CXDLGFRAME) $aRet[1] -= _WinAPI_GetSystemMetrics($SM_CYDLGFRAME) EndIf EndIf If BitAND($iStyleChild, $WS_CAPTION) = $WS_CAPTION Then $aRet[1] -= _WinAPI_GetSystemMetrics($SM_CYCAPTION) EndIf If BitAND($iStyleChild, $WS_POPUP) = $WS_POPUP And Not (BitAND($iStyleChild, $WS_CAPTION) = $WS_CAPTION) Then ;child window is a popup without a caption If BitAND($iStyleParent, $WS_THICKFRAME) = $WS_THICKFRAME Then $aRet[0] -= _WinAPI_GetSystemMetrics($SM_CXFRAME) / 2 $aRet[1] -= _WinAPI_GetSystemMetrics($SM_CYFRAME) / 2 If BitAND($iStyleParent, $WS_DLGFRAME) = $WS_DLGFRAME Or BitAND($iStyleParent, $WS_BORDER) = $WS_BORDER Then $aRet[0] -= _WinAPI_GetSystemMetrics($SM_CXBORDER) $aRet[1] -= _WinAPI_GetSystemMetrics($SM_CYBORDER) EndIf ElseIf Not (BitAND($iStyleParent, $WS_CAPTION) = $WS_CAPTION) Then If Not (BitAND($iStyleParent, $WS_DLGFRAME) = $WS_DLGFRAME) Then $aRet[0] += _WinAPI_GetSystemMetrics($SM_CXDLGFRAME) $aRet[1] += _WinAPI_GetSystemMetrics($SM_CYDLGFRAME) EndIf If BitAND($iStyleParent, $WS_BORDER) = $WS_BORDER Then $aRet[0] -= _WinAPI_GetSystemMetrics($SM_CXBORDER) $aRet[1] -= _WinAPI_GetSystemMetrics($SM_CYBORDER) EndIf EndIf EndIf Return $aRet EndFunc
comment:6 Changed 4 years ago by Jpm
- Resolution set to Wont Fix
- Status changed from new to closed
I suppose the proposed solution is OK for everybody so I close it
Guidelines for posting comments:
- You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
- In-depth discussions should take place on the forum.
For more information see the full version of the ticket guidelines here.
I forgot to mention: This issue is still present in v3.3.12.0