【问题标题】:Can't Free caller component无法释放调用者组件
【发布时间】:2019-10-17 01:15:09
【问题描述】:

当我单击一个组件时,我正在尝试释放它。所以,我编写了我能想象到的最简单的代码来实现这一点:一个释放它的发送者的过程。但是在 Delphi 7 上(在 Delphi XE 10 上尝试过并且没有错误)它有时会随机抛出访问冲突或抽象错误。复制它的最简单方法是插入 30 个按钮并使用下面的代码分配一个 onclick 过程,然后单击它们。

我在 onclick 上尝试了以下两个代码:

procedure FreeMe(Sender: TObject);
begin
    TButton(Sender).Free;
end;

procedure FreeMe(Sender: TObject);
begin
    (Sender as TButton).Free;
end;

【问题讨论】:

  • 底线是你不能这样做,因为事件处理程序是由按钮对象调用的,当事件处理程序返回时,执行返回到按钮对象的方法。你刚刚杀了它。因此,现在您执行了 Self 无效的方法,已被销毁。
  • 感谢大卫的建议。我看到了您的重复建议,也许我可以尝试 PostMessage 之一。如何使用发布消息释放按钮?
  • 取决于按钮的类型,VCL或FMX等
  • 这是标准的 VCL
  • @DavidHeffernan 你可以随心所欲地讨论它,提到的重复是相似的,但并不是这个问题的真正重复。与此问题不同的答案的不同场景。这就是我重新提出这个问题的原因。这就是我要说的。

标签: delphi delphi-7


【解决方案1】:

您需要延迟释放,直到按钮的OnClick 事件处理程序完全退出。重要的是,当被释放的对象处于空闲状态而不是在处理任何东西时,才会发生释放。

一种方法是使用PostMessage(),例如:

var
  MyReleaseWnd: HWND;

procedure TMyMainForm.FormCreate(Sender: TObject);
begin
  MyReleaseWnd := AllocateHWnd(MyReleaseWndProc);
end;

procedure TMyMainForm.FormDestroy(Sender: TObject);
begin
   DeallocateHWnd(MyReleaseWnd);
end;

procedure TMyMainForm.MyReleaseWndProc(var Message: TMessage);
begin
  if Message.Msg = CM_RELEASE then
    TObject(Msg.LParam).Free
  else
    Message.Result := DefWindowProc(MyReleaseWnd, Message.Msg, Message.WParam, Message.LParam);
end;

procedure DelayFreeMe(Sender: TObject);
begin
  PostMessage(MyReleaseWnd, CM_RELEASE, 0, LPARAM(Sender));
end;

或者,在 10.2 Tokyo 及更高版本中,您可以改用 TThread.ForceQueue()

procedure DelayFreeMe(Sender: TObject);
begin
  TThread.ForceQueue(nil, Sender.Free);
end;

无论哪种方式,您都可以这样做:

procedure TSomeForm.ButtonClick(Sender: TObject);
begin
  DelayFreeMe(Sender);
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    • 2014-07-29
    • 2020-06-25
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    相关资源
    最近更新 更多