[Windows] - synchronize windows position

Just starting out? Need help? Post your questions and find answers here.
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

[Windows] - synchronize windows position

Post by Michael Vogel »

Hi,

I'd like to snap one window to another, which works fine using callbacks in principle, but depending on the windows flags the second window gets misplaced by some pixels...
...the following code will display window #2 perfectly aligned but windows #3 should be set some pixels up and to the right.

How to get them all arranged in one line?

Code: Select all

OpenWindow(0,20,20,200,200,"1",#PB_Window_SystemMenu)
OpenWindow(1,20,20,200,200,"2",#PB_Window_SystemMenu)
OpenWindow(2,20,20,200,200,"3",#PB_Window_SystemMenu|#PB_Window_SizeGadget)

ResizeWindow(1,WindowX(0)+WindowWidth(0,#PB_Window_FrameCoordinate)+GetSystemMetrics_(#SM_CXSIZEFRAME),WindowY(0),#PB_Ignore,#PB_Ignore)
ResizeWindow(2,WindowX(1)+WindowWidth(1,#PB_Window_FrameCoordinate)+GetSystemMetrics_(#SM_CXSIZEFRAME),WindowY(1),#PB_Ignore,#PB_Ignore)

Delay(3456)
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: [Windows] - synchronize windows position

Post by Dude »

I had a similar problem:

viewtopic.php?f=13&t=66470

Maybe the discussion there can help? It's caused by PB_Window_SizeGadget. :(
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: [Windows] - synchronize windows position

Post by RASHAD »

Hi
Tested PB 5.72 x86 - Windows 10 x64

Code: Select all

OpenWindow(0,20,20,200,200,"1",#PB_Window_SystemMenu)
OpenWindow(1,20,20,200,200,"2",#PB_Window_SystemMenu)
OpenWindow(2,20,20,200,200,"3",#PB_Window_SystemMenu| #PB_Window_SizeGadget)

  AdjustWindowRectEx_(r.RECT,#PB_Window_SizeGadget,0,0)
  AdjustWindowRectEx_(rr.RECT,#PB_Window_SystemMenu,0,0)
  yy = r\bottom - rr\bottom

ResizeWindow(1,230,20,WindowWidth(0),WindowHeight(0))
ResizeWindow(2,440,20,WindowWidth(0),WindowHeight(0)-yy)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
For Vista,7,8 & 8.1
Tested with VirtualBox

Code: Select all

#DWMWA_EXTENDED_FRAME_BOUNDS = 9
Global width.f,height.f

Procedure getwin(hWnd)
  If OSVersion() >= #PB_OS_Windows_Vista And OSVersion() < #PB_OS_Windows_10
    lib = OpenLibrary(#PB_Any, "UxTheme.dll")
    If lib
      *IsThemeActive = GetFunction(lib, "IsThemeActive")
      If *IsThemeActive
        Themed = CallFunctionFast(*IsThemeActive)
      EndIf   
      CloseLibrary(lib)
    EndIf
    If Themed = 1
      Lib = OpenLibrary(#PB_Any, "dwmapi.dll")
      If Lib
        *DwmIsCompositionEnabled = GetFunction(Lib, "DwmIsCompositionEnabled")
        If *DwmIsCompositionEnabled
          CallFunctionFast(*DwmIsCompositionEnabled, @flag)
        EndIf
        If flag = 1
          *DwmGetWindowAttribute = GetFunction(Lib, "DwmGetWindowAttribute")
          If *DwmGetWindowAttribute                 
            CallFunctionFast(*DwmGetWindowAttribute, hWnd,  #DWMWA_EXTENDED_FRAME_BOUNDS, wr.RECT, SizeOf(wr))        
          EndIf
          shadow = initshadow
        Else
          shadow = 0
        EndIf                    
      EndIf                  
      CloseLibrary(Lib)                  
    Else
      shadow = 0
    EndIf
  Else
    shadow = 0
  EndIf
  GetWindowRect_(hWnd, wr.RECT)
  width.f = wr\right-wr\left
  height.f = wr\bottom-wr\top
EndProcedure

OpenWindow(0,20,20,200,200,"1",#PB_Window_SystemMenu)
OpenWindow(1,20,20,200,200,"2",#PB_Window_SystemMenu)
OpenWindow(2,20,20,200,200,"3",#PB_Window_SystemMenu| #PB_Window_SizeGadget)

getwin(WindowID(0))
h0 = height

getwin(WindowID(2))
h2 = height

yy = h2-h0

ResizeWindow(0,20,20,width,height)
ResizeWindow(1,230,20,width,height)
ResizeWindow(2,440,20,width,height-yy)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Egypt my love
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: [Windows] - synchronize windows position

Post by Michael Vogel »

Thanks Dude and Rashad, but still not correctly displayed here (Win 8.1)...
...the real position of the two windows is different to the values which are shown below:

Code: Select all

0:
100 - 100
103 - 126
100 - 306, 100 - 329
1:
100 - 100
101 - 129
95 - 307, 100 - 335
But... the outer frame of window #0 is on the screen position [97|97] while the left top corner of window #1 is at [95 | 100 ]. The real window sizes of both windows is 212 x 235. That means, if the window #1 would have been opened with the parameters (1,102,97,200,200,"1",...) it would be placed exactly on top of window #0.

Code: Select all

Macro ShowDim(r)
Debug Str(r\left)+" - "+Str(r\right)+", "+Str(r\top)+" - "+Str(r\bottom)
EndMacro

OpenWindow(0,100,100,200,200,"0",#PB_Window_SystemMenu)
OpenWindow(1,100,100,200,200,"1",#PB_Window_SystemMenu|#PB_Window_SizeGadget)
GetWindowRect_(WindowID(0),w0.rect)
GetWindowRect_(WindowID(1),w1.rect)

Debug "0:"
Debug Str(WindowX(0,#PB_Window_FrameCoordinate)) + " - " + Str(WindowY(0,#PB_Window_FrameCoordinate))
Debug Str(WindowX(0,#PB_Window_InnerCoordinate)) + " - " + Str(WindowY(0,#PB_Window_InnerCoordinate))
ShowDim(w0)

Debug "1:"
Debug Str(WindowX(1,#PB_Window_FrameCoordinate)) + " - " + Str(WindowY(1,#PB_Window_FrameCoordinate))
Debug Str(WindowX(1,#PB_Window_InnerCoordinate)) + " - " + Str(WindowY(1,#PB_Window_InnerCoordinate))
ShowDim(w1)

;ResizeWindow(1,WindowX(0)+w0\right-w0\left,WindowY(0)+w0\bottom-w0\top-w1\bottom+w1\top,#PB_Ignore,#PB_Ignore)

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow

For my windows here, the following code works perfect - no idea if it will produce strange results for other windows releases...
...Window 1 is placed exactly above window 0, window 2 is also perfectly arranged on the right side of (the hidden) window 0:

Code: Select all

OpenWindow(0,100,100,200,200,"0",#PB_Window_SystemMenu)
OpenWindow(1,100,100,200,200,"1",#PB_Window_SystemMenu|#PB_Window_SizeGadget)
OpenWindow(2,100,100,200,200,"2",#PB_Window_SystemMenu|#PB_Window_SizeGadget)
GetWindowRect_(WindowID(0),w0.rect)
GetWindowRect_(WindowID(1),w1.rect)

ox=WindowX(0,#PB_Window_InnerCoordinate)-WindowX(1,#PB_Window_InnerCoordinate)
oy=WindowY(0,#PB_Window_InnerCoordinate)-WindowY(1,#PB_Window_InnerCoordinate)
oz=w1\right-w1\left-(w0\right-w0\left)
oz=w1\right-w1\left-WindowWidth(0)

Debug ox
Debug oy
Debug oz

ResizeWindow(1,WindowX(1)+ox,WindowY(1)+oy,#PB_Ignore,#PB_Ignore); 						window 1 over window 0
ResizeWindow(2,WindowX(0)+WindowWidth(0)+oz+ox,WindowY(0)+oy,#PB_Ignore,#PB_Ignore);	window 0 and 2 side to side

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
Last edited by Michael Vogel on Thu May 21, 2020 6:49 am, edited 1 time in total.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: [Windows] - synchronize windows position

Post by RASHAD »

Hi MV
New version

Code: Select all

#DWMWA_EXTENDED_FRAME_BOUNDS = 9
Global width.f,height.f

Procedure getwin(hWnd)
  If OSVersion() >= #PB_OS_Windows_Vista And OSVersion() < #PB_OS_Windows_10
    lib = OpenLibrary(#PB_Any, "UxTheme.dll")
    If lib
      *IsThemeActive = GetFunction(lib, "IsThemeActive")
      If *IsThemeActive
        Themed = CallFunctionFast(*IsThemeActive)
      EndIf   
      CloseLibrary(lib)
    EndIf
    If Themed = 1
      Lib = OpenLibrary(#PB_Any, "dwmapi.dll")
      If Lib
        *DwmIsCompositionEnabled = GetFunction(Lib, "DwmIsCompositionEnabled")
        If *DwmIsCompositionEnabled
          CallFunctionFast(*DwmIsCompositionEnabled, @flag)
        EndIf
        If flag = 1
          *DwmGetWindowAttribute = GetFunction(Lib, "DwmGetWindowAttribute")
          If *DwmGetWindowAttribute                 
            CallFunctionFast(*DwmGetWindowAttribute, hWnd,  #DWMWA_EXTENDED_FRAME_BOUNDS, wr.RECT, SizeOf(wr))        
          EndIf
          shadow = initshadow
        Else
          shadow = 0
        EndIf                    
      EndIf                  
      CloseLibrary(Lib)                  
    Else
      shadow = 0
    EndIf
  Else
    shadow = 0
  EndIf
  GetWindowRect_(hWnd, wr.RECT)
  width.f = wr\right-wr\left
  height.f = wr\bottom-wr\top
EndProcedure

OpenWindow(0,20,20,200,200,"1",#PB_Window_SystemMenu)
OpenWindow(1,20,20,200,200,"2",#PB_Window_SystemMenu)
OpenWindow(2,20,20,200,200,"3",#PB_Window_SystemMenu| #PB_Window_SizeGadget)

getwin(WindowID(0))
h0 = height

getwin(WindowID(2))
h2 = height

yy = h2-h0

ResizeWindow(0,20,20,width,height)
ResizeWindow(1,250,20,width,height)
If OSVersion() = #PB_OS_Windows_7
  ResizeWindow(2,480,20,width,height-yy)
ElseIf OSVersion() = #PB_OS_Windows_8 Or OSVersion() = #PB_OS_Windows_8_1  
  ResizeWindow(2,480,20-yy/2,width,height)
ElseIf OSVersion() = #PB_OS_Windows_10
  ResizeWindow(2,480,20,width,height-yy/2)
EndIf

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Egypt my love
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: [Windows] - synchronize windows position

Post by Michael Vogel »

Rashad, perfect for the y values! There's a gap of around 3 pixels between all windows, but that looks fine as well :lol:

I've added a working code in the posting above - but that doesn't mean it will work universally for all windows versions, maybe you can give it a try on your PC?

Here's the short version:

Code: Select all

OpenWindow(0,100,100,200,200,"0",#PB_Window_SystemMenu)
OpenWindow(1,100,100,200,200,"1",#PB_Window_SystemMenu|#PB_Window_SizeGadget)
GetWindowRect_(WindowID(0),w0.rect)
GetWindowRect_(WindowID(1),w1.rect)

ox=w1\right-w1\left-WindowWidth(0)+WindowX(0,#PB_Window_InnerCoordinate)-WindowX(1,#PB_Window_InnerCoordinate)
oy=WindowY(0,#PB_Window_InnerCoordinate)-WindowY(1,#PB_Window_InnerCoordinate)

ResizeWindow(1,WindowX(0)+WindowWidth(0)+ox,WindowY(0)+oy,#PB_Ignore,#PB_Ignore);	window 0 and 1 side to side

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
...and here's a version which should work without doing inital calculations (with hidden windows with specific sizes etc.) - but that was a little bit to optimistic (see Barry's next posting) :wink: :

Code: Select all

Global WinID,MakeID
Global winoffset.point

Procedure WndProc(hwnd,uMsg,wParam,lParam)

	Protected i,w,d,q,p
	Protected r.Rect

	#WM_CAPTURECHANGED=$215

	If hwnd=WinID
		Select uMsg
		Case #WM_SIZE,#WM_MOVE,#WM_PAINT
			ResizeWindow(1,WindowX(0)+WindowWidth(0)+winoffset\x,WindowY(0)+winoffset\y,#PB_Ignore,#PB_Ignore)
		EndSelect

	ElseIf hwnd=MakeID
		#SnapPixel=8
		Select uMsg
		Case #WM_MOVE
			GetWindowRect_(WinID,r)
			w=WindowX(0)+WindowWidth(0)+winoffset\x
			q=WindowX(1)
			If q<w+#SnapPixel And q>w-#SnapPixel
				p=WindowY(0)+winoffset\y
				d=WindowY(1)
				If q<w+#SnapPixel*4 And q>w-#SnapPixel
					ResizeWindow(1,WindowX(0)+WindowWidth(0)+winoffset\x,WindowY(0)+winoffset\y,#PB_Ignore,#PB_Ignore)
				EndIf
			EndIf
		EndSelect
	EndIf

	ProcedureReturn #PB_ProcessPureBasicEvents

EndProcedure

WinID=OpenWindow(0,7,7,102,45,"0",#PB_Window_SystemMenu|#PB_Window_Invisible)
MakeID=OpenWindow(1,0,0,10,30,"1",#PB_Window_Invisible|#PB_Window_SystemMenu|#PB_Window_SizeGadget);,WinID)
GetWindowRect_(WindowID(1),r.rect)
winoffset\x=r\right-r\left-WindowWidth(1)+WindowX(0,#PB_Window_InnerCoordinate)-WindowX(1,#PB_Window_InnerCoordinate)+WindowX(1)-WindowX(0)
winoffset\y=WindowY(0,#PB_Window_InnerCoordinate)-WindowY(1,#PB_Window_InnerCoordinate)+WindowY(1)-WindowY(0)

HideWindow(0,0)
HideWindow(1,0)

Delay(500)
SetWindowCallback(@WndProc())

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
Last edited by Michael Vogel on Thu May 21, 2020 9:12 am, edited 2 times in total.
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: [Windows] - synchronize windows position

Post by BarryG »

Michael, your last two examples don't work here. But this seems to be what you want:

Code: Select all

OpenWindow(0,20,20,200,200,"1",#PB_Window_SystemMenu)
OpenWindow(1,20,20,200,200,"2",#PB_Window_SystemMenu)
OpenWindow(2,20,20,200,200,"3",#PB_Window_SystemMenu|#PB_Window_SizeGadget)

ResizeWindow(1,WindowX(0)+WindowWidth(0,#PB_Window_FrameCoordinate)+GetSystemMetrics_(#SM_CXSIZEFRAME),WindowY(0),#PB_Ignore,#PB_Ignore)
ResizeWindow(2,WindowX(1)+WindowWidth(1,#PB_Window_FrameCoordinate)+GetSystemMetrics_(#SM_CXSIZEFRAME),WindowY(1),#PB_Ignore,WindowHeight(1)-GetSystemMetrics_(#SM_CYSIZEFRAME)+GetSystemMetrics_(#SM_CYBORDER)+GetSystemMetrics_(#SM_CYEDGE))

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
Image
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: [Windows] - synchronize windows position

Post by Michael Vogel »

Barry, the third one is "out of order" here :(...

Do you see the window on screen position 100|100 when placing it there? (I made a screen shot and checked the coordinates within a paint program).
I hate windows :evil: Must check my versions somewhere else to understand what's going on - I don't use special themes or something strange things here (Win 8.1)...
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: [Windows] - synchronize windows position

Post by BarryG »

My screenshot is what my code does. All perfectly aligned at the same Y position and same height. This is on Windows 10, so I don't know why Windows 8.1 is different.
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: [Windows] - synchronize windows position

Post by Michael Vogel »

BarryG wrote:My screenshot is what my code does. All perfectly aligned at the same Y position and same height. This is on Windows 10, so I don't know why Windows 8.1 is different.
Me either. I understood what you said, but I can't understand windows - but at least one thing is simple: my code works here (but nowhere else), your code work there but (at least) not here :wink:

Still interested, if opening a window at 100|100 will show the window exactly there. That would mean, that you'll see also the complete window borders when placing it at 0|0 on the screen...
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1243
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: [Windows] - synchronize windows position

Post by Paul »

I don't know about anyone else but testing on Win7, Win81, Win10 ...
WindowWidth(#Window ,#PB_Window_FrameCoordinate) returns incorrect results.
The returned Width is to small, unless you create your Window with the #PB_Window_SizeGadget flag then the Width is to big.

Only on Windows XP are the results correct.

Maybe Fred needs to take a look at this?
Image Image
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: [Windows] - synchronize windows position

Post by Michael Vogel »

Did anyone find an universal working code to put two windows side by side?

It seems to be impossible to find a routine doing a perfect alignment for all different windows styes and windows versions.

Code: Select all

OpenWindow(0,0,0,300,200,"Main",#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget)
OpenWindow(1,0,0,100,100,"Snap")

ResizeWindow(1,WindowX(0)+WindowWidth(0),WindowY(0),#PB_Ignore,#PB_Ignore)

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: [Windows] - synchronize windows position

Post by BarryG »

I always add #SM_CXBORDER and #SM_CYBORDER:

Code: Select all

OpenWindow(0,0,0,300,200,"Main",#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget)
OpenWindow(1,0,0,100,100,"Snap")

ResizeWindow(1,WindowX(0)+WindowWidth(0)+GetSystemMetrics_(#SM_CXBORDER),WindowY(0),#PB_Ignore,#PB_Ignore)

Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
Post Reply