Как я могу отобразить форму на дополнительном мониторе? - PullRequest
7 голосов
/ 25 июня 2010

Я пишу заставку на 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, то есть он появляется на первом мониторе, над первой формой.Что случилось?Как правильно выполнить то, что я хочу?

Ответы [ 3 ]

7 голосов
/ 25 июня 2010

Форма должна быть видимой, чтобы установить границы с помощью BoundRect.

Переверните строки следующим образом:

presentationForms[i].Visible := true;
presentationForms[i].BoundsRect := Screen.Monitors[i].BoundsRect;
2 голосов
/ 25 июня 2010

Очевидно, я пытаюсь установить позицию преждевременно.

Заменить блок петли 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;
1 голос
/ 14 декабря 2017

Примечание. У вас будут проблемы с мониторами с высоким разрешением, если ваше приложение не включает флаг с поддержкой highdpi в свой манифест. В этом случае 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;
...