我注意到一些非常奇怪的事情。我在关闭窗体时保留窗体的顶部、左侧、宽度和高度属性,并使用此信息在窗体再次打开时恢复窗体的最后位置,方法是使用先前存储的信息调用 SetBounds。这很好用,但前提是表单的 Position 属性在设计时设置为 poDefault。如果设置为其他值,例如 poDesigned、poScreenCenter 或 poMainFormCenter,SetBounds 不会恢复表单的先前位置和大小。
这是奇怪的部分。重要的是在设计时将 Position 属性设置为什么。我可以在运行时将此属性的值更改为 poDefault,并且对 SetBounds 的调用仍然无法正常工作。我尝试过类似以下的方法
if Self.Position <> poDefault then
Self.Position := poDefault;
在表单的 OnCreate 事件处理程序以及重写的构造函数中(并在构造函数中将 Position 设置为 poDefault,并在 OnCreate 事件处理程序中调用 SetBounds)。在所有情况下,在运行时将表单的 Position 属性更改为 poDefault 并不能解决我在使用 SetBounds 时观察到的问题。我发现的唯一一致的模式是,只有当表单的 Position 属性在设计时是 poDefault 时,SetBounds 才能正常工作。
当表单的 Position 属性在设计时未设置为 poDefault 时,关于 SetBounds 如何工作,我还注意到了其他一些事情。例如,如果您调用 SetBounds,则在设计时将 Position 属性设置为 poScreenCenter 的窗体不一定会在屏幕上居中显示。但是,它不会出现在由 SetBounds 定义的左上角位置,也不会遵守对 SetBounds 的调用中指定的宽度和高度。然而,让我再说一遍,我在调用 SetBounds 之前将表单的 Position 属性设置为 poDefault。我什至在两个操作之间调用了 Application.ProcessMessages ,但这并不能解决问题。
我已经使用在 Windows 10 上运行的 Delphi 10.1 Berlin 对此进行了广泛测试。我还在 Windows 7 上使用 Delphi XE6 对其进行了测试。结果相同。
如果您有疑问,请创建一个具有四种形式的 VCL 应用程序。在第一个表单上放置三个按钮,并为每个按钮添加类似于以下 OnClick 的内容:
with TForm2.Create(nil) do
try
ShowModal;
finally
Release;
end;
其中构造函数创建 TForm2,然后创建 TForm3 和 TForm4。
在表单 2 到 4 的 OnCreate 上,添加以下代码:
if Self.Position <> poDefault then
Self.Position := poDefault;
Self.SetBounds(500,500,500,500);
在 form2 上,将 Position 设置为 poDefault,在 form3 上将 Position 设置为 poScreenCenter,在 form4 上将 Position 设置为默认值 poDefaultPosOnly。只有form2会出现在500、500,宽500,高500。
有人对这个结果有合理的解释吗?