I am working with Delphi 10.4.2 in Windows 10 (virtualized in Parallels) on a dual monitor system. To recreate the problem on a multi-monitor system, create a new Windows VCL Application and place two buttons on the form: btnPrimaryMonitor
and btnSecondaryMonitor
. Then insert this code by creating click handlers for the two buttons:
procedure TForm1.btnPrimaryMonitorClick(Sender: TObject);
begin
RepositionFormToMonitor(0);
EnableDisableButtons;
end;
procedure TForm1.RepositionFormToMonitor(const aMonitor: Integer);
const
offset = 2;
begin
Self.Width := Screen.Monitors[aMonitor].Width - offset;
Self.Height := Screen.Monitors[aMonitor].Height - offset;
Self.Top := Screen.Monitors[aMonitor].Top;
Self.Left := Screen.Monitors[aMonitor].Left;
end;
procedure TForm1.btnSecondaryMonitorClick(Sender: TObject);
begin
RepositionFormToMonitor(1);
EnableDisableButtons;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
EnableDisableButtons;
Self.BorderStyle := bsNone;
Self.FormStyle := fsStayOnTop;
RepositionFormToMonitor(0);
end;
procedure TForm1.EnableDisableButtons;
begin
btnPrimaryMonitor.Enabled := (Self.Monitor.MonitorNum = 1);
btnSecondMonitor.Enabled := (Self.Monitor.MonitorNum = 0);
end;
This works perfectly, but as soon as I set offset = 1
or offset = 0
the screen becomes black!
The purpose of the code is to reposition the maximized stay-on-top Form from the primary monitor to the secondary monitor by clicking on the btnSecondMonitor
button and then back to the primary monitor by clicking on the btnPrimaryMonitor
button.
How can this problem be avoided?
A few issues:
You should not set WindowState
to wsMaximized
. In fact, you shouldn't touch this property at all.
Setting BoundsRect
will set Left
, Top
, Width
, and Height
, so there is no need to set Left
and Top
separately.
To go back to the primary monitor, just set the form's BoundsRect
.
Here's an example:
Create a new VCL project. Set the main form's BorderStyle
to bsNone
.
Then add the following code:
procedure TForm1.FormCreate(Sender: TObject);
begin
for var i := 0 to Screen.MonitorCount - 1 do
begin
var btn := TButton.Create(Self);
btn.Parent := Self;
btn.Caption := i.ToString;
btn.Tag := i;
btn.OnClick := MonitorButtonClick;
btn.Top := 8;
btn.Left := 8 + (btn.Width + 8) * i;
end;
end;
procedure TForm1.MonitorButtonClick(Sender: TObject);
begin
BoundsRect := Screen.Monitors[(Sender as TButton).Tag].BoundsRect;
end;
If this code doesn't work properly on your system, you probably have some problem with that Windows system. This should work flawlessly.