gpt4 book ai didi

delphi - 为什么 TForm.SetBounds 仅在设计时将 TForm.Position 设置为 poDefault 时才能正常工作

转载 作者:行者123 更新时间:2023-12-03 14:53:53 38 4
gpt4 key购买 nike

我注意到一些非常奇怪的事情。我在关闭表单时保留表单的顶部、左侧、宽度和高度属性,并使用此信息在通过使用先前存储的信息调用 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。

有人对这个结果有一个合乎逻辑的解释吗?

最佳答案

poDefault和 friend 的意思是“让 Microsoft Windows 表单创建并显示该表单的窗口时定位它”。

您刚刚创建了 Delphi 对象 - 但我想知道它是否也创建/显示了 Windows 对象( HWND 句柄和所有相应的 Windows 内部结构)。特别是对于主题应用程序,而不是使用标准 XP 之前的外观和感觉的应用程序 - 它们倾向于ReCreateHWND显示时,因为预加载那些精美的 Windows 主题是相对昂贵的操作,并且仅应在需要时才进行。

我认为当您(或 TApplication - 这几乎没有什么区别)时,您的默认边界(构造函数中设置的每个属性值可能被视为默认的未调整值,稍后在构造对象后进行调整)被正确忽略对于这个主题)最后做FormXXX.Show .

在“为我创建一个窗口并显示它”序列期间,您的表单查看其属性并向 MS Windows 告知“现在我想创建您的内部 HWND 对象并将其定位在默认坐标/大小您的自由裁量权”。

这绝对是正确的行为 - 否则什么时候和怎么可能 TForm应用Position属性(property)???向 Windows 询问屏幕上尚不存在且可能永远不会存在的窗口的坐标是没有意义的。 Windows 在被询问的那一刻提供默认坐标/大小,查看还有多少其他窗口以及它们的位置(AMD/NVidia 视频驱动程序也可能对其应用修正)。

现在获取默认值,并在两个小时后应用它们,当时一切可能都会不同 - 不同数量的其他窗口和不同的位置,连接的不同显示器组和不同的分辨率等,这是没有意义的。

只需考虑“台式机替代”类型的笔记本电脑即可。它被放置在连接到大型固定外部显示器的 table 上。然后 - 让我们想象一下 - 我运行您的应用程序,它创建了 tform Delphi 对象,并在构造函数中向 MS Windows 询问位置 - Windows 正确地提供了那个非常次要的大型显示器的位置。但一个小时后,我拔掉了笔记本电脑的电源,然后带着它走开了。现在一小时后,我告诉您的应用程序显示表格 - 它将做什么?使用属于现在已分离的外部显示器的坐标来显示它?在我目前只有笔记本内部显示屏的视口(viewport)之外?该表单是否应该显示在现在“不可见”的位置,只是因为当我启动应用程序时,该位置仍然可见???我认为这是一种让用户感到困惑却没有任何好处的方法。

因此,唯一正确的行为是在表单从隐藏变为可见时立即向 Windows 询问默认坐标,而不是早一秒。

这意味着如果您想移动表单 - 您应该在显示后进行。放置您的Self.SetBounds(500,500,500,500);进入OnShow事件处理程序。因此,让 MS Windows 将您的表单具体化到默认位置,如 poDefault 所要求的那样。在Position属性 - 然后移动你的窗口。尝试移动尚不存在的窗口对我来说看起来是徒劳的。

或者预设您的表单(按构建顺序)以显式忽略 MS Windows 默认值并使用预设线(通过 poDesigned 值),或者让表单询问 Windows 坐标,但使用 SetBounds 移动它之后它通过 OnShow 可见处理程序。

关于delphi - 为什么 TForm.SetBounds 仅在设计时将 TForm.Position 设置为 poDefault 时才能正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39035107/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com