为啥 TForm.Handle 是一个吸气剂而不是一个字段?

Posted

技术标签:

【中文标题】为啥 TForm.Handle 是一个吸气剂而不是一个字段?【英文标题】:Why TForm.Handle is a getter instead of a field?为什么 TForm.Handle 是一个吸气剂而不是一个字段? 【发布时间】:2016-10-03 12:10:29 【问题描述】:

我最近在调试一个复杂的错误。这是由访问不存在的Form.Handle(垃圾指针)引起的。这个错误以一种让我意想不到的方式暴露出来——访问表单Handle 导致调整大小和重绘。

我希望通过垃圾指针访问Form.Handle 只会返回一些垃圾THandle。期望 Handle 在表单创建时创建一次,并且在表单被销毁之前保持不变。

问题

为什么会这样,TForm.Handle 不是在创建表单时被初始化并通过以下方式访问的字段

property Handle: Integer read FHandle;

,但是是一个吸气剂

property Handle: Integer read GetHandle;

在首次访问时创建句柄甚至窗口 (CreateWnd)?

【问题讨论】:

见Delphi XE2, vcl styles recreating window handle 和PostMessage returns “invalid window handle” in thread。简而言之,windows在某些情况下需要重新创建句柄。 了解 VCL 窗口娱乐 因为更改窗口的某些属性需要销毁并重新创建它(请参阅RecreateWnd 并计算在表单单元中调用它的次数)。 complicated bug 是由于您没有正确理解 Form.Handle 引起的,而不是 TForm 如何使用它的句柄的问题。 :-) 这个问题似乎将属性的结构与窗口 [re]creation 关联/混合。这就是为什么您会在其中一个主题上获得 cmet,而在另一个主题上获得答案。 不是错误,而是严重的误解。你的假设是完全无效的。见***.com/questions/21011780和***.com/questions/582903 【参考方案1】:

即使底层操作系统 window 不存在,表单 object 也可以存在。在那些时候,Handle 字段将为 0,这对于需要有效窗口句柄的代码没有帮助。为确保每次需要时都能获得有效句柄,您需要在引用 Handle 字段之前调用 HandleNeeded。作为带有getter的属性,该属性可以自动为您调用HandleNeeded,让Handle属性的使用更加方便。

【讨论】:

“让它变得更容易”,除了从不同线程访问句柄的时候,现在看来这是一个非常糟糕的主意。 是的。在这些情况下,首先调用HandleAllocated,以猜测Handle 的后续访问是否有效。您无法知道,因为主线程可能会在检查时间和使用时间之间破坏窗口。最终,关于在其他线程中做 UI 的东西。如果另一个线程需要知道一个窗口句柄,让主线程将句柄提供给另一个线程(而不是另一个线程自己获取句柄),同时让主线程承担责任确保提供的句柄在其他线程需要时保持有效。 @Kromster,如果您想从线程访问表单句柄以发送/发布消息,最好在主线程中分配带有AllocateHwnd() 的句柄,并让线程将消息发布到此句柄。从那里可以将消息转发到 VCL。 我比@LURD 说得更强烈。规则是您从不在主线程之外使用 VCL 窗口句柄,因为它们需要重新创建。因此,您使用的窗口句柄不是,例如来自 AllocateHWnd 的窗口句柄。

以上是关于为啥 TForm.Handle 是一个吸气剂而不是一个字段?的主要内容,如果未能解决你的问题,请参考以下文章

了解 Nuxt.js 中的状态和吸气剂:吸气剂不起作用

Android Studio:房间:错误:找不到字段的吸气剂

类内的吸气剂模式?

为啥 Vuex 状态将数组作为对象返回

c++11 - 所有权和吸气剂

包含 Handler 的吸气剂