【问题标题】:VCL event during destruction销毁期间的 VCL 事件
【发布时间】:2011-03-09 10:55:46
【问题描述】:

我遇到了一个问题,即某些 VCL 控件在被销毁时偶尔会触发事件,导致处理程序以已被销毁的子类形式调用(例如,控件被父级的析构函数杀死) TForm。)

这是否是相关(第三方)控件的违约行为,我是否应该在每个事件处理程序中添加“if(open)”保护,或者应该由其他一些机制来处理.我曾经,也许是天真地认为 __published 闭包会被自动注销,有点类似于常规虚函数的工作方式。

【问题讨论】:

    标签: delegates destructor c++builder vcl


    【解决方案1】:

    您的错误控件是否正确设置了“所有者”属性?默认情况下,一个表单拥有它上面的所有控件,它们的“Owner”属性指向 TForm 实例,这个表单负责释放所有拥有的控件。如果您通过 IDE 表单设计器设计表单,这就是工作方式。如果手动创建控件,则必须通过构造函数提供“Owner”属性。检查您是否以“所有者”的身份传递了正确的表格。此外,如果您有自定义控件的源,构建在 TControl 之上,请检查它们的构造函数是否正确地将“所有者”属性传递给底层 TControl 构造函数。

    【讨论】:

    • 是的,这一切都是由设计人员自动创建的,并且 Owner 属性在执行期间和崩溃期间都指向 Form。作为记录,组件似乎在预期的时间被销毁。 ~TWinControl 显然会遍历并杀死所有拥有的组件。然后,有问题的控件的析构函数尝试将一个事件传递给我们的表单,该表单已经被销毁并且此时只剩下一些父类。
    • 为什么要在析构函数中触发事件?在任何情况下,您都可以在调用事件处理程序之前简单地检查 ComponentState 属性中的 csDestroying 标志。
    【解决方案2】:

    __published 闭包不做任何保证,闭包只是一个指向类实例和内部函数的指针。但是,VCL 中还有其他机制可以做到这一点。

    通常,在开发依赖于其他组件的组件时,最好的做法是确保在删除组件时清除对组件的任何内部引用。在 VCL 中,可以通过TComponent 中的免费通知来实现这一点。

    如果您依赖的组件有不同的所有者并且不在表单上,​​那么您必须注册您的组件才能接收这些通知。您可以通过FreeNotification 函数执行此操作(请记住在删除通知组件时再次取消注册您的组件,为此使用RemoveFreeNotification)。每当将控件添加到与此组件相同的表单(或所有者)中时,都会调用函数Notification,并引用添加或删除的组件以及执行的操作。

    所以你只需覆盖Notification 函数,记住也要调用父函数。重载的函数可能如下所示:

    void __fastcall TMyComponent::Notification(TComponent* AComponent, TOperation Operation)
    {
        if (Operation == opRemove && AComponent == interestingComponent)
        {
            this->interestingComponent = NULL;
        }
    
        inherited::Notification(AComponent, Operation);
    }
    

    如果这是第三方控件,他们当然应该确保这一点并确保存在 dangling pointers,因为组件被释放,如果他们出于某种原因忘记了您必须添加该功能,或者通过子类化或按照您的说明重置事件。如果这是您自己的组件,那么您应该确保这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-21
      • 2011-03-18
      • 1970-01-01
      • 2020-01-17
      • 2015-10-28
      • 2023-03-24
      • 2017-12-27
      • 1970-01-01
      相关资源
      最近更新 更多