views:

138

answers:

2

I am writing a screensaver in Delphi. I want is to display a TpresentationFrm on each monitor, fullscreen. To this end, I have written the following (incomplete) program:

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.

When the ssmDisplay code is executed, two forms are indeed created (yes, I have exactly two monitors). But they both appear on the first monitor (index 0, but not the primary one).

When stepping through the code, I see that the Screen.Monitors[i].BoundsRect are correct, but for some reason the forms obtain incorrect bounds:

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))

The first form get the desired position, but the second does not. Instead of going from x=0 to 1920, it occupies x=-1920 to 0, i.e. it appears on the first monitor, above the first form. What is wrong? What is the proper procedure to accomplish what I want?

A: 

Apparently I try to set the position prematurely.

Replace the for loop block with

Application.CreateForm(TpresentationFrm, presentationForms[i]);
presentationForms[i].Tag := i;
presentationForms[i].Visible := true;

and then write

procedure TpresentationFrm.FormShow(Sender: TObject);
begin
  BoundsRect := Screen.Monitors[Tag].BoundsRect;
end;
Andreas Rejbrand
+2  A: 

The form has to be visible in order to set the bounds using BoundRect.

Reverse the lines like this:

presentationForms[i].Visible := true;
presentationForms[i].BoundsRect := Screen.Monitors[i].BoundsRect;
Marcus Adams
Yes, I just have to swap the two lines in the `for` loop: set the visibility first, and then change the bounds!
Andreas Rejbrand