views:

111

answers:

2

Windows in my application are popping up off the edge of the screen, and this of course is a problem because some of the windows are modal and can't be dismissed (you don't even know they are there).

I'm using the TurboPower Orpheus component which remembers the location and size of each form, then restores it when the form is shown again. It saves the size and placement in an INI file.

What can I do to prevent windows from ever showing off the side of the screen?

+5  A: 

It's common for this sort of thing to happen if you use multiple monitors and then disconnect one, such as when undocking a laptop. Or if you dock a laptop to a screen with a higher resolution. Or use remote desktop, etc.. The remedy is to override the "remember my position" behavior with a sanity check, to see if the left+width exceeds the width of the screen (Screen.Monitors array, actually - thanks guys), and vice-versa for the top+height.

Ideally, you "bump" by subtracting the difference, so you're butting up against the edge that the window wanted to straddle.

Also, see if there are updates to Orpheus that fix this. If not, you can get the source, make the correction (optional), and contribute it back to the project. It's OSS, as I recall.

Chris Thornton
This logic can become pretty complex if you are dealing with 2+ monitors. I was hoping there was a component or some library which handled this type of thing. I could write it myself though if need be.
Daisetsu
@Daisetsu: It's not that complicated, even with more than 2 monitors. What I do is 1) looping through all currently attached monitors to see whether the centre point of the window to be placed is in the area of one of the monitors. If so the coordinates of the window can be adjusted so that it doesn't intersect the monitor borders (that's not optimal though, because a user could have left the window partially off-screen intentionally). 2) If 1) fails, then the window is placed on the monitor whose centre is closest to the centre of the window to be placed.
mghie
@Daisetsu, dealing with multiple monitors is not that bad: Take a look at Screen.Monitors and Screen.MonitorFromPoint; Each TMonitor object has a "WorkareaRect" property you can use.
Cosmin Prund
@Chris Thornton: Since Delphi 4 the width and height of the "screen" have no meaning any more, the array of `Monitors` (and their respective coordinates) is the only important thing. Apart from that I agree with your answer, +1.
mghie
@mghie - you're right, thanks. And that reminds me to mention that it's no longer ok to use poDesktopCenter for the initial form position. It'll come up split between the monitors. A little off-topic, but worth mentioning here.
Chris Thornton
@Chris, yeah I noticed that. I've been using doScreenCenter to fix that and in most cases it works, but aparently not here.
Daisetsu
+1  A: 

You may want to give a look at their DefaultMonitor property and read the code from TCustomForm.SetWindowToMonitor to see how to deal with positioning relatively to Screen.Monitors.

Use DefaultMonitor to associate a form with a particular monitor in a multi-monitor application. The following table lists the possible values: 

Value        Meaning  
dmDesktop    No attempt is made to position the form on a specific monitor.   
dmPrimary    The form is positioned on the first monitor listed in the global screen object's Monitors property.   
dmMainForm   The form appears on the same monitor as the application's main form.   
dmActiveForm The form appears on the same monitor as the currently active form.   

Note: DefaultMonitor has no effect if the application does not have a main form.
François