2010-06-25 2 views
7

Я пишу скринсейвер в 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

Вы будете иметь проблемы на высокий DPI монитора, если ваше приложение не включает highdpi осведомленный флаг в своем манифесте. В этом случае Windows сообщит о неправильном (виртуализированном) связанном прямоугольнике. – Ampere

ответ

7

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

Reverse линии, как это:

presentationForms[i].Visible := true; 
presentationForms[i].BoundsRect := Screen.Monitors[i].BoundsRect; 
+0

Да, мне просто нужно поменять местами две строки в цикле 'for': сначала установите видимость, а затем измените границы! –

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; 
0

Вы будете иметь проблемы на высокий DPI монитора, если ваше приложение не включает 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;