Page 1 of 1
Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 5:47 am
by Teddy Rogers
Here is some small code to center your window in the middle of the screen. I initially looked for something similar in PureBasic and had to result to Windows API and did not find similar code in the forums. This method should work across multiple monitors quickly and easily, even when the screen resolution or orientation differs from one-to-the-next. Feel free to modify and use the code...
Code: Select all
Declare CenterWindow(hWnd, HMONITOR, WWidth, WHeight)
Define pt.Point
WWidth = 400
WHeight = 200
If OpenWindow(0, 0, 0, WWidth, WHeight, "Center window over multiple monitors...", #PB_Window_SystemMenu | #PB_Window_SizeGadget)
hWnd = WindowID(0)
Repeat
MyEvent = WindowEvent()
If GetCursorPos_(@pt)
HMONITOR = MonitorFromPoint_(PeekQ(@pt), #MONITOR_DEFAULTTONEAREST)
If HMONITOR <> HMONITOROLD
If CenterWindow(hWnd, HMONITOR, WWidth, WHeight)
HMONITOROLD = HMONITOR
Debug "Window changed..."
EndIf
EndIf
EndIf
Until MyEvent = #PB_Event_CloseWindow
EndIf
Procedure CenterWindow(hWnd, HMONITOR, WWidth, WHeight)
Protected Left, Top
Define mi.MONITORINFO
mi\cbSize = SizeOf(mi)
If GetMonitorInfo_(HMONITOR, @mi)
Left = mi\rcMonitor\left + (mi\rcMonitor\right - mi\rcMonitor\left - WWidth) / 2
Top = mi\rcMonitor\top + (mi\rcMonitor\bottom - mi\rcMonitor\top - WHeight) / 2
SetWindowPos_(hWnd, #Null, Left, Top, 0, 0, #SWP_NOSIZE | #SWP_NOZORDER | #SWP_NOACTIVATE)
Else
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndProcedure
Ted.
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 9:58 am
by infratec
Hi,
since I like 'crossplatform',
here is a 'Pure' Basic solution:
Code: Select all
EnableExplicit
Structure DesktopInfoStructure
X1.i
Y1.i
X2.i
Y2.i
EndStructure
Procedure.i GetDesktop(List DesktopList.DesktopInfoStructure())
Protected.i Result, X, Y
Result = -1
ExamineDesktops()
X = DesktopMouseX()
Y = DesktopMouseY()
ForEach DesktopList()
With DesktopList()
If X >= \X1 And X <= \X2 And Y >= \Y1 And Y <= \Y2
Result = ListIndex(DesktopList())
Break
EndIf
EndWith
Next
ProcedureReturn Result
EndProcedure
Define.i Event, Desktops, CurrentDesktop, OldDesktop, Exit, i
NewList DesktopList.DesktopInfoStructure()
Desktops = ExamineDesktops() - 1
If Desktops
For i = 0 To Desktops
AddElement(DesktopList())
DesktopList()\X1 = DesktopX(i)
DesktopList()\Y1 = DesktopY(i)
DesktopList()\X2 = DesktopList()\X1 + DesktopWidth(i)
DesktopList()\Y2 = DesktopList()\Y1 + DesktopHeight(i)
Next i
EndIf
OldDesktop = -1
If OpenWindow(0, 0, 0, 400, 200, "Center window over multiple monitors...", #PB_Window_SystemMenu | #PB_Window_SizeGadget)
PostEvent(#PB_Event_MoveWindow)
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
Exit = #True
Case #PB_Event_MoveWindow
CurrentDesktop = GetDesktop(DesktopList())
If CurrentDesktop <> OldDesktop
With DesktopList()
ResizeWindow(0, \X1 + (\X2 - \X1 - WindowWidth(0)) / 2, \Y1 + (\Y2 - \Y1 - WindowHeight(0)) / 2, #PB_Ignore, #PB_Ignore)
EndWith
OldDesktop = CurrentDesktop
EndIf
EndSelect
Until Exit
EndIf
P.S.: Your solution was not working on my PC: Win 7 x64 with 2 monitors
It get always the same monitor handle back from MonitorFromPoint_()
Bernd
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 10:21 am
by Teddy Rogers
Hmm... its working fine here on both Windows 7 x64 and Windows 8.1 x64 compiled with PB 5.30 and PB 5.22 LTS. What version of PB are you running? Possibly you may need to define pt.Point with...
Out of curiosity has anyone had any joy getting MONITORINFOEX working in PB? I can get the structures size but can't retrieve anything from it. It's nearly identical to MONITORINFO but with an extra member for szDevice...
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
Ted.
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 10:24 am
by infratec
Hi,
I use PB 5.31 x86
And I have also extended your version with EnableExplicit().
So everything was right.
Bernd
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 10:55 am
by Teddy Rogers
Thanks for the info, I just tried compiling with PB x32 compiler and there is an overflow bug, it can be fixed by adding, "Define pt.Point". I corrected the original post...
Ted.
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 12:21 pm
by infratec
Hi,
optimized version, which only fits the needs:
Code: Select all
EnableExplicit
Procedure.i CenterWindowOnDesktop(Window)
Protected.i Result, Desktops, X, Y, X1, Y1, X2, Y2, i
Static OldDesktop.i
Desktops = ExamineDesktops() - 1
X = DesktopMouseX()
Y = DesktopMouseY()
For i = 0 To Desktops
X1 = DesktopX(i)
Y1 = DesktopY(i)
X2 = X1 + DesktopWidth(i)
Y2 = Y1 + DesktopHeight(i)
If X >= X1 And X <= X2 And Y >= Y1 And Y <= Y2
If i <> OldDesktop
ResizeWindow(Window, X1 + (X2 - X1 - WindowWidth(Window)) / 2, Y1 + (Y2 - Y1 - WindowHeight(Window)) / 2, #PB_Ignore, #PB_Ignore)
OldDesktop = i
Result = #True
EndIf
Break
EndIf
Next
ProcedureReturn Result
EndProcedure
Define.i Event, Exit
If OpenWindow(0, 0, 0, 400, 200, "Center window over multiple monitors...", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
Exit = #True
Case #PB_Event_MoveWindow
If CenterWindowOnDesktop(0)
Debug "Centered!"
EndIf
EndSelect
Until Exit
EndIf
Bernd
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 3:02 pm
by Teddy Rogers
Nice! So I don't feel left out here is a version similar to yours using Windows API's; when the window moves to a new screen it will automatically snap the window to the center but can be repositioned whilst still on the existing screen...
Code: Select all
Declare CenterWindowOnDesktop(hWnd)
If OpenWindow(0, 0, 0, 400, 200, "Center window over multiple monitors...", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
Repeat
MyEvent = WaitWindowEvent()
Select MyEvent
Case #PB_Event_MoveWindow
If CenterWindowOnDesktop(WindowID(0))
Debug "Window centered..."
EndIf
EndSelect
Until MyEvent = #PB_Event_CloseWindow
EndIf
Procedure CenterWindowOnDesktop(hWnd)
Protected Left, Top
Static HMONITOROLD
Define mi.MONITORINFO
Define lpRect.RECT
GetWindowRect_(hWnd, @lpRect)
HMONITOR = MonitorFromRect_(lpRect, #MONITOR_DEFAULTTONEAREST)
If HMONITOR <> HMONITOROLD
mi\cbSize = SizeOf(mi)
If GetMonitorInfo_(HMONITOR, @mi)
Left = mi\rcMonitor\left + (mi\rcMonitor\right - mi\rcMonitor\left - (lpRect\right - lpRect\left)) / 2
Top = mi\rcMonitor\top + (mi\rcMonitor\bottom - mi\rcMonitor\top - (lpRect\bottom - lpRect\top)) / 2
SetWindowPos_(hWnd, #Null, Left, Top, 0, 0, #SWP_NOSIZE | #SWP_NOZORDER | #SWP_NOACTIVATE)
HMONITOROLD = HMONITOR
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Ted.
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 3:09 pm
by chi
Teddy Rogers wrote:Out of curiosity has anyone had any joy getting MONITORINFOEX working in PB? I can get the structures size but can't retrieve anything from it. It's nearly identical to MONITORINFO but with an extra member for szDevice...
PB's MONITORINFOEX isn't unicode compatible so you need to define your own structure.
Code: Select all
Structure MONITORINFOEX2
cbSize.i
rcMonitor.RECT
rcWork.RECT
dwFlags.i
szDevice.s{#CCHDEVICENAME}
EndStructure
MonInfo.MONITORINFOEX\cbSize = SizeOf(MONITORINFOEX)
GetMonitorInfo_(MonitorFromPoint_(pt.POINT, #MONITOR_DEFAULTTONEAREST), @MonInfo)
Debug MonInfo\szDevice
Debug MonInfo\rcMonitor\left
Debug MonInfo\rcMonitor\top
Debug MonInfo\rcMonitor\right
Debug MonInfo\rcMonitor\bottom
Re: Center Window Over Multiple Monitors...
Posted: Fri Nov 21, 2014 5:07 pm
by Teddy Rogers
Yes, I realised earlier on after I tried disabling unicode. This is how I had it working by modifying the code in the first post...
Code: Select all
Declare CenterWindow(hWnd, HMONITOR, WWidth, WHeight)
Define pt.Point
WWidth = 400
WHeight = 200
If OpenWindow(0, 0, 0, WWidth, WHeight, "Center window over multiple monitors...", #PB_Window_SystemMenu | #PB_Window_SizeGadget)
hWnd = WindowID(0)
Repeat
MyEvent = WindowEvent()
If GetCursorPos_(@pt)
HMONITOR = MonitorFromPoint_(PeekQ(@pt), #MONITOR_DEFAULTTONEAREST)
If HMONITOR <> HMONITOROLD
If CenterWindow(hWnd, HMONITOR, WWidth, WHeight)
HMONITOROLD = HMONITOR
Debug "Window changed..."
EndIf
EndIf
EndIf
Until MyEvent = #PB_Event_CloseWindow
EndIf
Procedure CenterWindow(hWnd, HMONITOR, WWidth, WHeight)
Protected Left, Top
Structure MONITORINFOEXA
cbSize.l
rcMonitor.RECT
rcWork.RECT
dwFlags.l
szDevice.s {#CCHDEVICENAME}
EndStructure
Define mi.MONITORINFOEXA
mi\cbSize = SizeOf(mi)
If GetMonitorInfo_(HMONITOR, @mi)
Left = mi\rcMonitor\left + (mi\rcMonitor\right - mi\rcMonitor\left - WWidth) / 2
Top = mi\rcMonitor\top + (mi\rcMonitor\bottom - mi\rcMonitor\top - WHeight) / 2
SetWindowPos_(hWnd, #Null, Left, Top, 0, 0, #SWP_NOSIZE | #SWP_NOZORDER | #SWP_NOACTIVATE)
Else
ProcedureReturn #False
EndIf
ProcedureReturn #True
EndProcedure
Ted.