如何检测到整个应用程序中的表单已被销毁? [英] How to detect that a form is being destroyed across the Application?

查看:99
本文介绍了如何检测到整个应用程序中的表单已被销毁?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的应用程序中有很多表单,我需要一个全局事件处理程序来检测何时破坏其中一种表单(然后采取一些措施)。

We have many forms in our application, and I need a global event handler to detect when one of the forms is being destroyed (and then take some action).

p.s:我想避免在要销毁的每个表单中添加向主表单发送消息的代码。同时大多数表单都是在运行时动态创建和销毁的。

p.s: I want to avoid adding code to each form that will need to send a message to the main form when it's about to destroy. also most of the forms are created and destroyed dynamicaly at run-time.

我当时在考虑使用全局TApplicationEvents。

I was thinking about maybe use a global TApplicationEvents.

什么是最好的方法?

推荐答案

以现有形式修改代码或创建代码的约束从其他答案和评论中可以看出,表格留下了很多麻烦。本地CBT钩子f.i.可能会有点工作,但可能会很好。以下是较简单的hacky解决方案之一。

A constraint on modifying code in existing forms, or creation of forms, as can be seen from other answers and comments, leaves hacks and hooks. A local CBT hook, f.i., would be a little work but probably work fine. Below is one of the simpler hacky solutions.

屏幕全局对象始终通过常规 TList TList 具有虚拟的 Notify 过程,每次添加/删除项目时都会调用该过程。想法是使用 TList 派生方法重写此方法,并在 Screen 对象中使用它。

Screen global object holds a list of forms at all times via a regular TList. TList has a virtual Notify procedure which is called every time an item is added/removed. The idea is to employ a TList derivative that overrides this method and use it in the Screen object.

type
  TNotifyList = class(TList)
  protected
    procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  end;

procedure TNotifyList.Notify(Ptr: Pointer; Action: TListNotification);
begin
  inherited;
  if (Action = lnDeleted) and (csDestroying in TForm(Ptr).ComponentState) and
      (TForm(Ptr) <> Application.MainForm) then
    // do not use ShowMessage or any 'TForm' based dialog here
    MessageBox(0,
        PChar(Format('%s [%s]', [TForm(Ptr).ClassName, TForm(Ptr).Name])), '', 0);
end;

需要测试 csDestroying ,因为屏幕不仅在创建/销毁表单时还将其添加/删除到表单中,而且在激活表单时也将其添加/删除。

Testing for csDestroying is required because the Screen adds/removes forms to its list not only when forms are created/destroyed but also when they are activated etc..

然后使屏幕使用此列表。这需要访问私有字段 黑客,因为 FForms 列表是私有的。您可以在Hallvard Vassbotn的博客上了解有关此黑客的信息。还需要在运行时更改对象的类 hack。您可以在Hallvard Vassbotn的博客上了解有关此黑客的信息。

Then make the Screen use this list. This requires an "accessing private fields" hack, as the FForms list is private. You can read about this hack on Hallvard Vassbotn's blog. It also requires "changing the class of an object at run time" hack. You can read about this hack on Hallvard Vassbotn's blog.

type
  THackScreenFForms = class
{$IF CompilerVersion = 15}
    Filler: array [1..72] of Byte;
{$ELSE}
    {$MESSAGE ERROR 'verify/modify field position before compiling'}
{$IFEND}
    Forms: TList;
  end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  PPointer(THackScreenFForms(Screen).Forms)^ := TNotifyList;
end;

请注意,该通知将针对每次销毁。这还包括通过 MessageDlg ShowMessage 等创建的表单。

Note that the notification will be called for every form destruction. This also includes forms created through MessageDlg, ShowMessage etc..

这篇关于如何检测到整个应用程序中的表单已被销毁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆