Delphi:如何在监视器配置发生变化时恢复表单的原始位置?

Ted*_*d W 2 forms delphi

我有一个多表单应用程序,其中子窗体在启动时位于第二个监视器上,此时它的BoundsRect被保存.

当计算机的显示配置更改时,Windows会将表单移动到第一个(主)监视器.我可以用WM_DISPLAYCHANGE来捕捉这个变化:

procedure WMDisplayChange(var msg: TWMDisplayChange); message WM_DISPLAYCHANGE;
Run Code Online (Sandbox Code Playgroud)

我感兴趣的是当子窗体重新出现在配置中时(即Screen.MonitorCount从1变为2),将子窗体移回第二个监视器,例如:

childForm.BoundsRect := childForm.m_WorkingBounds;
// (or)
childForm.BoundsRect := Screen.Monitors[Screen.MonitorCount-1].BoundsRect;
Run Code Online (Sandbox Code Playgroud)

但是这个赋值没有任何影响 - 子表单保留在监视器0上.

我尝试过其他方法,比如SetWindowPos(),没有成功......

Dal*_*kar 5

问题的根源在于Delphi VCL在实际更改时不会刷新其内部监视器列表.你必须自己强制刷新.

监视器使用TScreen.GetMonitors不幸的私有方法刷新,因此您无法直接调用它.

但是,TApplication.WndProc(var Message: TMessage)进程WM_WTSSESSION_CHANGE和收到该消息时它会调用Screen.GetMonitors - 这是实现目标的最良性方式.

当您收到监视器已更改的通知时,只需将其发送到应用程序:

SendMessage(Application.Handle, WM_WTSSESSION_CHANGE, 0, 0);
Run Code Online (Sandbox Code Playgroud)