我遇到一个问题,某些 VCL 控件在被销毁时偶尔会触发事件,导致在已被销毁的子类表单中调用处理程序(例如,该控件被 TForm 父级的析构函数杀死)。 )
这是有问题的(第三方)控件违反合同吗?我是否应该在每个事件处理程序中添加“if(open)”防护,或者应该由其他机制来处理。我也许天真地认为 __published 闭包会自动取消注册,有点类似于常规虚拟函数的工作方式。
I'm having a problem where certain VCL controls occasionally fire off events while being destroyed, causing handlers to be invoked in a sub-classed form which has already been destroyed (e.g. the control gets killed by the destructor of a parent of the TForm.)
Is this a breach-of-contract by the (third-party) control in question, am I supposed to litter every event handler with "if(open)" guards, or should this be taken care of by some other mechanism. I had, perhaps naively, just assumed that that __published closures would have been unregistered automatically, somewhat akin to how regular virtual functions work.
发布评论
评论(2)
您的错误控件的“Owner”属性设置正确吗?默认情况下,表单拥有其上的所有控件,这些控件的“Owner”属性指向 TForm 实例,并且该表单负责释放所有拥有的控件。如果您通过 IDE 表单设计器设计表单,这就是事情的工作方式。如果手动创建控件,则必须通过构造函数提供“Owner”属性。检查您作为“所有者”是否通过了正确的表格。另外,如果您有构建在 TControl 之上的自定义控件的源,请检查它们的构造函数是否正确地将“Owner”属性传递给底层 TControl 构造函数。
Do you buggy controls have their "Owner" property set correctly? By default, a form owns all controls that are on it, which have their "Owner" property point to TForm instance, and this form is responsible for freeing all owned controls. That is the way how stuff works if you design your forms via IDE Form designer. If you create controls manually, you must provide "Owner" property through constructor. Check if you pass correct Form as an "Owner". Also, if you have sources of your custom-controls, built on a top of TControl, check if their constructor correctly pass "Owner" property to the underlying TControl constructor.
__published 闭包不提供任何此类保证,闭包只是指向类实例和其中的函数的指针。然而,VCL 中还有其他机制可以做到这一点。
通常,在开发依赖于其他组件的组件时,最好确保在删除组件时清除对组件的所有内部引用。在 VCL 中,可以通过
TComponent
中的免费通知来实现这一点。如果您依赖的组件有不同的所有者并且不在表单上,那么您必须注册您的组件才能接收这些通知。您可以通过
FreeNotification
函数(请记住在删除通知组件时再次取消注册您的组件,为此用途删除免费通知
)。每当将控件添加到与此组件相同的表单(或所有者)时,函数 < code>Notification 将通过添加或删除的组件以及执行的操作的引用来调用。因此,您只需覆盖
Notification
函数,记住还要调用父函数。重载函数可能如下所示:如果这是第三方控件,他们当然应该确保这一点并确保有
__published
closures do not make any assurance of that kind, a closure is simply a pointer to a class instance and a function within. However there are other mechanics in the VCL that does.Normally it is good practice when developing components that are dependent on other components, to make sure to clear any internal reference to a component when it is deleted. In the VCL one can achieve this through the free notifications in
TComponent
.If the component you rely on, have a different owner and is not on the form, then you have to register your component to receive these notifications. You do this through the
FreeNotification
function (remember to unregister your component again when you are deleting the notified component, for this useRemoveFreeNotification
). Whenever a control is added to the same form (or owner) as this component the functionNotification
will be called with a reference to the component added or removed and the action performed.So you simply overwrite the
Notification
function, remember to call the parent's function as well. The overloaded function could look like this:If this is a third party control they should of course ensure this and make sure that there are dangling pointers, due to a component being freed, if they for some reason forgot you would have to add that functionality, either by subclassing or by resetting events as you stated. If this is your own component then you should do make sure to do this.