这是它的声明,它的数据成员全部都是Event,而没有真正意义上的数据(如此一来,几乎可以猜测,它本身什么都做不了):

  TCustomApplicationEvents = class(TComponent)
private
FOnActionExecute: TActionEvent;
FOnActionUpdate: TActionEvent;
FOnException: TExceptionEvent;
FOnMessage: TMessageEvent;
FOnHelp: THelpEvent;
FOnHint: TNotifyEvent;
FOnIdle: TIdleEvent;
FOnDeactivate: TNotifyEvent;
FOnActivate: TNotifyEvent;
FOnMinimize: TNotifyEvent;
FOnRestore: TNotifyEvent;
FOnShortCut: TShortCutEvent;
FOnShowHint: TShowHintEvent;
FOnSettingChange: TSettingChangeEvent;
FOnModalBegin: TNotifyEvent;
FOnModalEnd: TNotifyEvent;
procedure DoActionExecute(Action: TBasicAction; var Handled: Boolean);
procedure DoActionUpdate(Action: TBasicAction; var Handled: Boolean);
procedure DoActivate(Sender: TObject);
procedure DoDeactivate(Sender: TObject);
procedure DoException(Sender: TObject; E: Exception);
procedure DoIdle(Sender: TObject; var Done: Boolean);
function DoHelp(Command: Word; Data: Longint; var CallHelp: Boolean): Boolean;
procedure DoHint(Sender: TObject);
procedure DoMessage(var Msg: TMsg; var Handled: Boolean);
procedure DoMinimize(Sender: TObject);
procedure DoRestore(Sender: TObject);
procedure DoShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo);
procedure DoShortcut(var Msg: TWMKey; var Handled: Boolean);
procedure DoSettingChange(Sender: TObject; Flag: Integer; const Section: string; var Result: Longint);
procedure DoModalBegin(Sender: TObject);
procedure DoModalEnd(Sender: TObject);
protected
property OnActionExecute: TActionEvent read FOnActionExecute write FOnActionExecute;
property OnActionUpdate: TActionEvent read FOnActionUpdate write FOnActionUpdate;
property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
property OnDeactivate: TNotifyEvent read FOnDeactivate write FOnDeactivate;
property OnException: TExceptionEvent read FOnException write FOnException;
property OnIdle: TIdleEvent read FOnIdle write FOnIdle;
property OnHelp: THelpEvent read FOnHelp write FOnHelp;
property OnHint: TNotifyEvent read FOnHint write FOnHint;
property OnMessage: TMessageEvent read FOnMessage write FOnMessage;
property OnMinimize: TNotifyEvent read FOnMinimize write FOnMinimize;
property OnRestore: TNotifyEvent read FOnRestore write FOnRestore;
property OnShowHint: TShowHintEvent read FOnShowHint write FOnShowHint;
property OnShortCut: TShortCutEvent read FOnShortCut write FOnShortCut;
property OnSettingChange: TSettingChangeEvent read FOnSettingChange write FOnSettingChange;
property OnModalBegin: TNotifyEvent read FOnModalBegin write FOnModalBegin;
property OnModalEnd: TNotifyEvent read FOnModalEnd write FOnModalEnd;
public
constructor Create(AOwner: TComponent); override;
procedure Activate;
procedure CancelDispatch;
end;

它的构造函数平淡无奇:

constructor TCustomApplicationEvents.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if Assigned(MultiCaster) then
MultiCaster.AddAppEvent(Self);
end; procedure TMultiCaster.AddAppEvent(AppEvent: TCustomApplicationEvents);
begin
if FAppEvents.IndexOf(AppEvent) = - then
FAppEvents.Add(AppEvent);
end;

它的秘密在于:一旦使用了这个控件,那么就会引入AppEvents单元,因此会执行:

initialization
GroupDescendentsWith(TCustomApplicationEvents, Controls.TControl);
MultiCaster := TMultiCaster.Create(Application);
end.

其中GroupDescendentsWith函数来自classes.pas单元:

procedure GroupDescendentsWith(AClass, AClassGroup: TPersistentClass);
begin
RegGroups.Lock;
try
RegGroups.GroupWith(AClass, AClassGroup);
finally
RegGroups.Unlock;
end;
end;

而MultiCaster是AppEvents.pas的全局变量:

var
MultiCaster: TMultiCaster = nil;

其实就是靠创建MultiCaster的时候进行对接:

constructor TMultiCaster.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAppEvents := TComponentList.Create(False);
with Application do
begin
OnActionExecute := DoActionExecute;
OnActionUpdate := DoActionUpdate;
OnActivate := DoActivate;
OnDeactivate := DoDeactivate;
OnException := DoException;
OnHelp := DoHelp;
OnHint := DoHint;
OnIdle := DoIdle;
OnMessage := DoMessage;
OnMinimize := DoMinimize;
OnRestore := DoRestore;
OnShowHint := DoShowHint;
OnShortCut := DoShortcut;
OnSettingChange := DoSettingChange;
OnModalBegin := DoModalBegin;
OnModalEnd := DoModalEnd;
end;
end;

它对消息的处理就是转发,这里举三个例子(OnMessage,OnMinimize,OnException):

procedure TCustomApplicationEvents.DoMessage(var Msg: TMsg; var Handled: Boolean);
begin
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
end; procedure TMultiCaster.DoMessage(var Msg: TMsg; var Handled: Boolean);
var
I: Integer;
begin
BeginDispatch;
try
for I := Count - downto do
begin
AppEvents[I].DoMessage(Msg, Handled);
if FCancelDispatching then Break;
end;
finally
EndDispatch;
end;
end; procedure TCustomApplicationEvents.DoMinimize(Sender: TObject);
begin
if Assigned(FOnMinimize) then FOnMinimize(Sender);
end; procedure TMultiCaster.DoMinimize(Sender: TObject);
var
I: Integer;
begin
BeginDispatch;
try
for I := Count - downto do
begin
AppEvents[I].DoMinimize(Sender);
if FCancelDispatching then Break;
end;
finally
EndDispatch;
end;
end; procedure TCustomApplicationEvents.DoException(Sender: TObject;
E: Exception);
begin
if not (E is EAbort) and Assigned(FOnException) then
FOnException(Sender, E)
end; procedure TMultiCaster.DoException(Sender: TObject; E: Exception);
var
I: Integer;
FExceptionHandled: Boolean;
begin
BeginDispatch;
FExceptionHandled := False;
try
for I := Count - downto do
begin
if Assigned(AppEvents[I].OnException) then
begin
FExceptionHandled := True;
AppEvents[I].DoException(Sender, E);
if FCancelDispatching then Break;
end;
end;
finally
if not FExceptionHandled then
if not (E is EAbort) then
Application.ShowException(E);
EndDispatch;
end;
end;

其实就是这么简单,这个AppEvents.pas单元连finalization模块都没有。。。

不过说真的,这个控件简单实用,在看它的析构函数的时候,我忽然有点明白了,为什么TApplication要处理这么多消息,原本它应该没有机会处理的嘛:

destructor TMultiCaster.Destroy;
begin
MultiCaster := nil;
with Application do
begin
OnActionExecute := nil;
OnActionUpdate := nil;
OnActivate := nil;
OnDeactivate := nil;
OnException := nil;
OnHelp := nil;
OnHint := nil;
OnIdle := nil;
OnMessage := nil;
OnMinimize := nil;
OnRestore := nil;
OnShowHint := nil;
OnShortCut := nil;
OnSettingChange := nil;
OnModalBegin := nil;
OnModalEnd := nil;
end;
FAppEvents.Free;
inherited Destroy;
end;

最后还发现,TApplicationEvents终于也不甘示弱,终于自己处理了一个消息,这可真是不容易呀。但是我搞不明白,为什么会有这里例外,而且在TMultiCaster里同样有定义:

procedure TCustomApplicationEvents.DoHint(Sender: TObject);
begin
if Assigned(FOnHint) then
FOnHint(Sender)
else
with THintAction.Create(Self) do
try
Hint := Application.Hint;
Execute;
finally
Free;
end;
end; procedure TMultiCaster.DoHint(Sender: TObject);
var
I: Integer;
begin
BeginDispatch;
try
for I := Count - downto do
begin
AppEvents[I].DoHint(Sender);
if FCancelDispatching then Break;
end;
finally
EndDispatch;
end;
end;

TApplicationEvents的前世今生(待续)的更多相关文章

  1. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  2. [C#] 回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性

    回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性 序 目前最新的版本是 C# 7.0,VS 的最新版本为 Visual Studio 2017 RC,两者都尚未进入正式阶段.C# 6.0 ...

  3. javascript有用小功能总结(未完待续)

    1)javascript让页面标题滚动效果 代码如下: <title>您好,欢迎访问我的博客</title> <script type="text/javasc ...

  4. docker4dotnet #1 – 前世今生 & 世界你好

    作为一名.NET Developer,这几年看着docker的流行实在是有些眼馋.可惜的是,Docker是基于Linux环境的,眼瞧着那些 java, python, node.js, go 甚至连p ...

  5. ASP.NET MVC 系列随笔汇总[未完待续……]

    ASP.NET MVC 系列随笔汇总[未完待续……] 为了方便大家浏览所以整理一下,有的系列篇幅中不是很全面以后会慢慢的补全的. 学前篇之: ASP.NET MVC学前篇之扩展方法.链式编程 ASP. ...

  6. Atitit 智能云网络摄像机的前世今生与历史 优点  密码默认888888

    Atitit 智能云网络摄像机的前世今生与历史 优点  密码默认888888 用户名admin  密码aaaaaa 网络摄像机是一种结合传统摄像机与网络技术所产生的新一代摄像机,它可以将影像通过网络传 ...

  7. 关于DOM的一些总结(未完待续......)

    DOM 实例1:购物车实例(数量,小计和总计的变化) 这里主要是如何获取页面元素的节点: document.getElementById("...") cocument.query ...

  8. 阿里开源消息中间件RocketMQ的前世今生-转自阿里中间件

    昨天,我们将分布式消息中间件RocketMQ捐赠给了开源软件基金会Apache. 孵化成功后,RocketMQ或将成为国内首个互联网中间件在Apache上的顶级项目. 消息一出,本以为群众的反应是这样 ...

  9. JavaScript的前世今生

    和CSS一样,JavaScript在各浏览器下并非完全一致,它所带来的兼容性问题时常困扰着我们,以至于现在“能否处理流行浏览器的兼容性问题”成为了检验一个程序员是否合格的标准之一.了解JavaScri ...

随机推荐

  1. 【codeforces 782B】The Meeting Place Cannot Be Changed

    [题目链接]:http://codeforces.com/contest/782/problem/B [题意] 每个人都有一个速度,只能往上走或往下走; 然后让你找一个地方,所有人都能够在t时间内到达 ...

  2. 高性能分布式应用开发中间件ICE介绍

    作为一个技术人员,你是否在为不断增长的数据量和日益复杂的业务逻辑而头疼不已,杂乱堆砌在一起的庞大业务让系统越来越脆弱,于是你想到了网格,想到了利用分布式来重组一个健壮的系统架构. 随后,RMI,EJB ...

  3. JS高级程序设计拾遗

    <JavaScript高级程序设计(第三版)>反反复复看了好多遍了,这次复习作为2017年上半年的最后一次,将所有模糊的.记不清的地方记录下来,方便以后巩固. 0. <script& ...

  4. 再议指针---------函数回调(qsort函数原理)

    我们是否能写一个这种函数: 能够对不论什么类型数据排序 不论什么人在使用该函数不须要改动该函数代码(即:用户能够不必看到函数源 码,仅仅会调用即可) 思考: 用户须要排序的数据的类型千变万化,可能是i ...

  5. dotnet core 通过修改文件头的方式隐藏控制台窗口

    原文:dotnet core 通过修改文件头的方式隐藏控制台窗口 在带界面的 dotnet core 程序运行的时候就会出现一个控制台窗口,本文告诉大家使用最简单方法去隐藏控制台窗口. 最近在使用 A ...

  6. Unable to find a single main class from the following candidates

    关于start-class,spring boot官方手册是这么说明的: The plugin rewrites your manifest, and in particular it manages ...

  7. altium designer电气符号和包的常用元素

    1. 标准电阻:RES1.RES2.包裹:AXIAL-0.3至AXIAL-1.0 两port可变电阻器:RES3.RES4.包裹:AXIAL-0.3至AXIAL-1.0 三port可变电阻:RESIS ...

  8. Android官方教程翻译(2)——运行第一个程序

    转载请注明出处:http://blog.csdn.net/dawanganban/article/details/9823623 Running Your App PREVIOUSNEXT THIS ...

  9. mysql升级到5.7时间戳(timestamp)默认值报错

    原文:mysql升级到5.7时间戳报错 往数据库里创建新表的时候报错: [Err] 1067 - Invalid default value for 'updateTime' DROP TABLE I ...

  10. 通用javascript脚本函数库

    /* 名字:Common.js 功能:通用javascript脚本函数库 包括: 1.Trim(str)--去除字符串两边的空格 2.XMLEncode(str)--对字符串进行XML编码 3.Sho ...