Ensuring window visibility after plugging off a second monitor
I recently connected my new HD TV to my notebook, to test the DVI-to-HDMI adapter I just bought and various resolutions. I played a bit with different resolutions, started HeidiSQL, moved it to the TV which was used as second desktop. Then, after having plugging off the TV I started HeidiSQL again and saw - nothing! No window visible... HeidiSQL remembered its last window position and started in the area where the TV has previously provided its resolution. So, looked like a bug :) Started Delphi and found the place where the main window restores its position (Top, Right) and size (Width, Height) from the last session. I discovered the global Screen object has some Monitor* properties - these are:
Screen.Monitors Screen.MonitorCount Screen.MonitorFromPoint Screen.MonitorFromRect Screen.MonitorFromWindowThe most important property to fix the above described bug seemed to be MonitorFromWindow which tells the TMonitor object of the monitor on which the window is being displayed. The great thing about that is: If there is no second monitor plugged in, MonitorFromWindow returns the first TMonitor object available. So it always returns the best fitting monitor number for the given window handle, but never a no longer plugged monitor. Given this TMonitor object you can check if your window is placed within the monitor's resolution:
var Monitor: TMonitor; const MoveWinThreshold: Byte = 80; begin // ... // 1. Some code to restore the last GUI position and dimension // ... // 2. Detect the relevant monitor object Monitor := Screen.MonitorFromWindow(Self.Handle); // 3. Now ensure the just positioned window is visible to the user // 3.a. Set minimal visible width if Left > Monitor.Left + Monitor.Width - MoveWinThreshold then Left := Monitor.Left + Monitor.Width - MoveWinThreshold; // 3.b. Set minimal visible height if Top > Monitor.Top + Monitor.Height - MoveWinThreshold then Top := Monitor.Top + Monitor.Height - MoveWinThreshold; .. endIf the window (that means: the upper left corner) is placed somewhere outside the monitor's resolution, the above code moves its Left + Top properties so there's a minimal rectangle of 80x80 pixels visible in the current monitor. Given this minimum rectangle, the user can now manually move and resize the window. P.S.: Don't try to Free the TMonitor object afterwards which you got by Screen.MonitorFromWindow - that will lead to an access violation. Most probably MonitorFromWindow returns a reference to that object.
Leave a comment