4

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?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Daisetsu
  • 4,846
  • 11
  • 50
  • 70
  • Alt+Space, M, Arrow keys. (M as in Move. I have never used an English-language Windows, so I do not know for sure if this is the correct hotkey.) – Andreas Rejbrand Jul 01 '10 at 19:14
  • @Andreas Rejbrand - That may work if I was the only one with the issue but I can't ask users to know that or go through multiple key combinations. Thanks for the idea still, it will probably be helpfull to me in the future. – Daisetsu Jul 01 '10 at 19:19
  • Of course. I just wrote so in case you weren't aware of it. It would aid debugging if nothing else... – Andreas Rejbrand Jul 01 '10 at 19:23
  • @Andreas - FYI, yes M is the appropriate key for the Move task in English-language Windows. – Scott W Jul 01 '10 at 19:40

3 Answers3

9

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
  • 15,620
  • 5
  • 37
  • 62
  • 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 Jul 01 '10 at 19:23
  • 2
    @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 Jul 01 '10 at 19:38
  • 1
    @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 Jul 01 '10 at 19:41
  • 1
    @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 Jul 01 '10 at 19:42
  • 2
    @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 Jul 01 '10 at 21:22
  • @Chris, yeah I noticed that. I've been using doScreenCenter to fix that and in most cases it works, but aparently not here. – Daisetsu Jul 01 '10 at 23:56
  • Instead of validating the position, I use the system of storing the form position + size in a registry branch that includes the full desktop size (ie. CONFIG.1920x1080 and CONFIG.3840x1080). That way, the user can also have different setups with regards to dialogs positions (and sizes) in relation to each other, depending on what the current screen resolution is, ie. a different setup for single monitor and for dual (or triple) monitor. – HeartWare Jan 26 '18 at 07:23
2

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.
Francesca
  • 21,452
  • 4
  • 49
  • 90
2

To recall the previous position of a form, without having it suddenly in an area which is no longer available (due to a plugged off screen or changed resolution), you just call

TForm.MakeFullyVisible;

That's it. See the documentation.

Anse
  • 1,573
  • 12
  • 27