【发布时间】:2011-05-18 02:01:06
【问题描述】:
是否有释放 Delphi 控件的故障安全方法?
我有一个 TStringGrid 后代,我在其中“嵌入”了一个自定义控件,用于就地编辑器。当用户通过 tab 键或箭头键在网格的单元格中导航时,如果单元格是可编辑的,我需要创建一个动态控件。我已经挂钩了所需的事件,并正在利用我的自定义控件的 OnKeyDown 事件将导航键传递回父 TStringGrid。
以前,TStringGrid 后代将简单地调用嵌入式控件上的 FreeAndNil,但在某些情况下,这会导致 UpdateUIState/GetParentForm 内部的访问冲突。查看调用堆栈,有时似乎在释放控件后,仍然会出现 WM_KEYDOWN (TWinControl.WMKeyDown) 消息。
我已经准备好查看并实施How to free control inside its event handler? 中讨论的更改。这似乎已经解决了这个问题,但我想知道这种方法是否还有其他需要注意的地方。
实际上,此解决方法只是将控件的销毁延迟到发布 CM_RELEASE 消息时队列中的所有现有消息之后。
难道不可能在 CM_RELEASE 发布后,另一条 WM_KEY* 或类似的消息都已准备好发布到消息队列中吗?
我当前的 CM_RELEASE 处理程序如下所示:
procedure TMyCustomControl.HandleRelease(var Msg: TMessage);
begin
Free;
end;
那么,这在所有情况下都是安全的,还是我应该做一些事情来清除队列中的任何其他消息? (SendMessage(Self.Handle, WM_DESTROY, 0, 0) 浮现在脑海中)
【问题讨论】:
-
在类似的情况下,我不会在每次需要时创建和释放嵌入式组件。相反,我在初始化时创建它,然后根据需要使其可见/不可见。
-
我应该做些什么来清除队列中的任何其他消息吗? 不,这些消息是从
Parent发送给孩子的,AFAIK。 -
CodeInChaos 的答案比 Andreas 的答案更接近,因为我的复合控件本身没有问题。虽然我知道创建和释放控件的设计不是最佳的,但由于单元格的编辑方式,它是必需的。此自定义控件与约束引擎相关联,并且不容易重新连接到其他单元格值。我想我真的很想知道是否有任何方法可以删除在 CM_RELEASE 消息之后可能排队的任何消息。如果可能的话,我当然想避免 Application.ProcessMessages,但这会产生清除任何现有消息的效果。
标签: delphi