我正在Delphi中编写一个屏幕保护程序。我想要在每个显示器上全屏显示TpresentationFrm。为此,我写了以下(不完整)程序:
program ScrTemplate;
uses
...
{$R *.res}
type
TScreenSaverMode = (ssmConfig, ssmDisplay, ssmPreview, ssmPassword);
function GetScreenSaverMode: TScreenSaverMode;
begin
// Some non-interesting code
end;
var
i: integer;
presentationForms: array of TpresentationFrm;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
case GetScreenSaverMode of
ssmConfig:
Application.CreateForm(TconfigFrm, configFrm);
ssmDisplay:
begin
SetLength(presentationForms, Screen.MonitorCount);
for i := 0 to high(presentationForms) do
begin
Application.CreateForm(TpresentationFrm, presentationForms[i]);
presentationForms[i].BoundsRect := Screen.Monitors[i].BoundsRect;
presentationForms[i].Visible := true;
end;
end
else
ShowMessage(GetEnumName(TypeInfo(TScreenSaverMode), integer(GetScreenSaverMode)));
end;
Application.Run;
end.
执行ssmDisplay
代码时,确实创建了两个表单(是的,我只有两个监视器)。但它们都出现在第一个监视器上(索引0,但不是主监视器)。
当单步执行代码时,我发现Screen.Monitors[i].BoundsRect
是正确的,但由于某种原因,表单获得了不正确的边界:
Watch Name Value (TRect: Left, Top, Right, Bottom, ...)
Screen.Monitors[0].BoundsRect (-1680, 0, 0, 1050, (-1680, 0), (0, 1050))
Screen.Monitors[1].BoundsRect (0, 0, 1920, 1080, (0, 0), (1920, 1080))
presentationForms[0].BoundsRect (-1680, 0, 0, 1050, (-1680, 0), (0, 1050))
presentationForms[1].BoundsRect (-1920, -30, 0, 1050, (-1920, -30), (0, 1050))
第一种形式获得所需的位置,但第二种形式没有。它不是从x = 0到1920,而是占据x = -1920到0,即它出现在第一个监视器上,高于第一个窗体。怎么了?什么是完成我想要的正确程序?
答案 0 :(得分:7)
为了使用BoundRect设置边界,必须显示表单。
反转这样的行:
presentationForms[i].Visible := true;
presentationForms[i].BoundsRect := Screen.Monitors[i].BoundsRect;
答案 1 :(得分:2)
显然我试图过早地设定位置。
用
替换for
循环块
Application.CreateForm(TpresentationFrm, presentationForms[i]);
presentationForms[i].Tag := i;
presentationForms[i].Visible := true;
然后写
procedure TpresentationFrm.FormShow(Sender: TObject);
begin
BoundsRect := Screen.Monitors[Tag].BoundsRect;
end;
答案 2 :(得分:1)
注意:如果您的应用程序在其清单中未包含highdpi aware标志,则在高DPI监视器上将出现问题。在这种情况下,Windows将报告错误的(虚拟化)绑定矩形。
一种解决方案是手动将表单移动到您想要的屏幕上,如下所示:
procedure MoveFormToScreen(Form: TForm; ScreenNo: Integer);
begin
Assert(Form.Position= poDesigned);
Assert(Form.Visible= TRUE);
Form.WindowState:= wsNormal;
Form.Top := Screen.Monitors[ScreenNo].Top;
Form.Left:= Screen.Monitors[ScreenNo].Left;
Form.WindowState:= wsMaximized;
end;
答案 3 :(得分:0)
这一步我成功了
例如,我们要在第二个监视器上显示该窗体,它的索引为1
program ARPMandiri;
uses
Vcl.Forms,
SysUtils,
UMain in 'UMain.pas' {frmMain},
........
..............................;{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
.............
Application.CreateForm(TfrmMain, frmMain);
frmMain.Visible := true;
frmMain.BoundsRect := Screen.Monitors[1].BoundsRect;
ApplyThemes(frmMain);
Application.Run;
end.
procedure TfrmMain.FormCreate(Sender: TObject);
Var
iTm: Integer;
begin
Self.Left:= Screen.Monitors[1].Left;
Self.Top:= Screen.Monitors[1].Top;
Self.Width:= Screen.Monitors[1].Width;
Self.Height:= Screen.Monitors[1].Height;
...............
end;