我写的自定义控件在销毁时会导致崩溃。 很难确定具体情况,这可能是控制权是第三方控制权的一个因素。
编辑2014年10月8日 我现在有了一个更好的SSCCE来说明在TForm上只使用TMediaPlayer(来自Delphi VCL)的崩溃。所以我删除了很多我以前写的东西。请查看编辑历史记录。 (事实证明,前一个调用堆栈中的CM_EXIT是一个红色鲱鱼。)
这是SSCCE:
unit Unit1;
interface
uses
System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Menus, Vcl.MPlayer;
type
TForm1 = class(TForm)
MainMenu: TMainMenu;
CrashMenuItem: TMenuItem;
procedure CrashMenuItemClick(Sender: TObject);
procedure FormShow(Sender: TObject);
private
fControl : TMediaPlayer;
end;
var
Form1: TForm1;
implementation
uses
Vcl.Dialogs;
{$R *.dfm}
procedure TForm1.CrashMenuItemClick(Sender: TObject);
begin
ShowMessage('Message');
fControl.Free;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
fControl := TMediaPlayer.Create(Form1);
fControl.Parent := Form1;
end;
end.
在释放控件之前立即调用ShowMessage
至关重要。
TMediaPlayer
控件获得WM_SETFOCUS
。TCustomControl.Destroy
释放画布,然后继承TWinControl.Destroy
次调用TWinControl.RemoveFocus
,因此获得WM_KILLFOCUS
。TMediaPlayer.WMKillFocus
直接调用Paint
,尝试使用已释放的画布并崩溃。(之前我有一个自定义控件CMFocusChanged
称为Invalidate
。效果相同,但调用堆栈更多涉及。)
我最初的3个问题,NGLN已在下面回答:
FreeAndNil(fMyControl)
时做错了什么?在破坏它之前我必须先将它取消它吗?但是,对于任何其他控件来说,这似乎并不合适,因此更有可能隐藏底层错误。TWinControl
知道不要重新绘制它?TWinControl.Update
。)但真正的问题仍然存在:我的SSCCE中的代码有什么问题,或者Delphi VCL中是否有错误?
(顺便提一下,TCustomControl
的任何后代都会出现同样的问题。为方便起见,我使用了TMediaPlayer
。)
答案 0 :(得分:2)
我只是在调用
FreeAndNil(fMyControl)
时做错了吗?
不,每个控件都应该能够在任何给定时间释放,只要清除(nilled)对控件的所有引用并且实例的代码不再运行。
在销毁它之前,我是否必须将其取消隐藏?但是,对于任何其他控件来说,这似乎并不合适,因此更有可能隐藏底层错误。
不,确实没必要。
我的控件是否应该在其析构函数中有一些东西来修复它,以便
TWinControl
知道不要尝试重新绘制它?
不,通常没有必要。 VCL已经全部内置。出于测试目的或作为(临时)变通方法,您可以尝试使用PaintWindow
覆盖if not (csDestroying in ComponentState) then
。
第三方家长控件中是否有错误?一旦它开始被销毁,我的控件是否应该肯定不会收到
WM_PRINTCLIENT
消息? (当我控制失去焦点时,第三方控件似乎在接收CM_EXIT
时对其继承的TWinControl.Update进行显式调用。)
父控件确实收到CM_EXIT
,因为它有一个集中控制,现在它已经没有了(即Form.ActiveControl = nil
)。这是正常的行为。至于为什么父母向控件发送WM_PRINTCLIENT
(你怎么知道这个请求来自父母?它似乎从Update
电话开始。)我不知道。要排除有错误的父母的可能性,请使用其他父母重试您的案例。
- 醇>
TMediaPlayer.WMKillFocus
直接致电Paint
......
procedure TMediaPlayer.WMKillFocus(var Message: TWMKillFocus);
begin
Paint;
end;
这是禁忌!这绝对是VCL中的一个错误。除了通过Paint
消息进行绘画的请求之外,永远不应该直接调用WM_PAINT
。我有submitted a report on QC。
(之前我有一个自定义控件
CMFocusChanged
称为Invalidate
。效果相同,但调用堆栈更多涉及。)...
(顺便提一下,
TCustomControl
的任何后代都会出现同样的问题。为方便起见,我使用了TMediaPlayer
。)
D7和XE2中的测试情况并非如此。