【发布时间】:2013-09-01 06:35:20
【问题描述】:
在通过单击按钮调用的执行块中,我创建了一个弹出菜单以显示在单击按钮的位置。它当前显示正确,其中有几个项目,其中一个有几个子项目。当这个运行一次然后调用析构函数时,就可以了。但是如果我执行它两次(显示弹出窗口并单击一个项目两次)然后破坏,应用程序崩溃。我认为这是因为我没有正确释放弹出窗口(它被声明为私有属性)。
procedure TPlugIn.Execute(AParameters : WideString);
var
i: Integer;
pnt: TPoint;
begin
GetCursorPos(pnt);
FPopup := TPopupMenu.Create(nil);
FPopup.OwnerDraw:=True;
FPopup.AutoHotkeys := maManual;
//SQL Upgrade
Item := TMenuItem.Create(FPopup);
Item.Caption := 'Database Install/Upgrade';
Item.OnClick := ShowItemCaption;
FPopup.Items.Add(Item);
//Language Folder
Item := TMenuItem.Create(FPopup);
Item.Caption := 'Language Folder';
Item.OnClick := ShowItemCaption;
FPopup.Items.Add(Item);
//Machines
Item := TMenuItem.Create(FPopup);
Item.Caption := 'Machines';
MachineItem := TMenuItem.Create(FPopup);
MachineItem.Caption := 'Sample Machine 1';
MachineItem.OnClick := ShowItemCaption;
Item.Add(MachineItem);
MachineItem := TMenuItem.Create(FPopup);
MachineItem.Caption := 'Sample Machine 2';
MachineItem.OnClick := ShowItemCaption;
Item.Add(MachineItem);
FPopup.Items.Add(Item);
Self.FPopup := FPopup;
FPopup.Popup(pnt.X, pnt.Y);
end;
在ShowItemCaption 过程中,我只显示该发送者对象的标题。我还没有编写具体的事件。如果它在执行过程中释放弹出窗口,则不再出现弹出窗口。
destructor TPlugIn.Destroy;
begin
inherited;
FPopup.Free;
//ShowMessage('freed');
end;
【问题讨论】:
-
您必须将
nil分配给您的FPopup变量(因此在FPopup.Free调用之后使用例如FreeAndNil(FPopup)或FPopup := nil)。发生这种情况是因为当您第二次调用FPopup.Free时,FPopup只是一个悬空指针,但仍然是Assigned是什么让Free方法认为后面有一个有效对象,因此它调用Destroy不是现有对象。 -
hmm 结果还是和以前一样。没关系,当我执行两次使用时,基本上我是
FPopup两次并调用Destroy?第二个执行调用是否替换旧的FPopup?我只是想知道它是否为两个实例之一调用Destroy,如果是这样的话。 -
由于您没有在这里讲述整个故事,因此很难说出了什么问题。什么时候调用 TPlugin.Destroy?你在用线程吗?
-
为什么你在按钮点击时创建它(可能发生很多次)但释放它一次?你应该在
TPlugIn.Create中创建你的TPopupMenu。否则,您将在这里发生一些重大的内存泄漏。更不用说,假设弹出菜单甚至从未打开过。所以它一开始就没有被创造出来。然后你尝试释放它,但它没有被创建,所以它会失败。 -
@Craig - 你怎么知道插件析构函数只运行一次?也许 TPlugin 是在每次执行时创建的,然后被销毁。