I have noticed something very strange. I am persisting the top, left, width, and height properties of a form when it is closing, and using this information to restore the form's last position when it is once again opened by calling SetBounds using the previously stored information. This works well, but only if the form's Position property is set to poDefault at design time. If set to something else, such as poDesigned, poScreenCenter, or poMainFormCenter, SetBounds does not restore the form's previous position and size.
Here's the strange part. What appears to matter is what the Position property is set to at design time. I can change the value of this property at runtime to poDefault and the call to SetBounds still does not work correctly. I have tried something like the following
if Self.Position <> poDefault then
Self.Position := poDefault;
in both the form's OnCreate event handler, as well as from an overridden constructor (and have set Position to poDefault in the constructor, and called SetBounds in the OnCreate event handler). In all cases, changing the form's Position property to poDefault at runtime does not fix the problem that I've observed with SetBounds. The only consistent pattern that I have found is that SetBounds works as it should only if the form's Position property was poDefault at design time.
There are other things that I've noticed with respect to how SetBounds works when a form's Position property is not set to poDefault at design time. For example, a form whose Position property is set to poScreenCenter at design time will not necessarily appear centered on the screen if you call SetBounds. However, it does not appear in the top-left location defined by SetBounds, nor does it respect the width and height specified in the call to SetBounds. Let me repeat, however, that I am setting the Position property of the form to poDefault before calling SetBounds. I've even stuck a call to Application.ProcessMessages between the two operations, but that doesn't fix the problem.
I have tested this extensively with Delphi 10.1 Berlin running on Windows 10. I have also tested it using Delphi XE6 on Windows 7. Same results.
If you have doubts, create a VCL application with four forms. On the first form place three buttons, and add something like the following OnClick to each button:
with TForm2.Create(nil) do
try
ShowModal;
finally
Release;
end;
where the constructor creates TForm2, then TForm3 and TForm4.
On the OnCreate of forms 2 through 4, add the following code:
if Self.Position <> poDefault then
Self.Position := poDefault;
Self.SetBounds(500,500,500,500);
On form2, set Position to poDefault, on form3 set Position to poScreenCenter, and on form4 leave Position set to the default, poDefaultPosOnly. Only form2 will appear at 500, 500, with a width of 500 and a height of 500.
Does anyone have a logical explanation for this result?
procedure CreateParams(var Params: TCreateParams); override;
to protected section of your form definition and write ` inherited; if Self.Position <> poDefault then Self.Position := poDefault; ` in CreateParams implementation. – Infinity