深入VCL理解BCB的消息机制3

水瓶毁

水瓶毁

2016-02-19 15:31

想不想get新技能酷炫一下,今天图老师小编就跟大家分享个简单的深入VCL理解BCB的消息机制3教程,一起来看看吧!超容易上手~

  方法3 来自TApplication的方法

  不用我多废话,大家都知道TApplication在BCB中的重要性。在BCB的帮助中指出:TApplication、TScreen和TForm构成了所有BCB风格的Win32 GUI程序的脊梁,他们控制着您程序的行为。TApplication类提供的属性和方法封装了标准Windows程序的行为。TApplication表现了在Windows操作系统中创建、运行、支持和销毁应用程序的基本原理。因此,TApplication大大简化了开发者和Windows环境之间的接口。这正是BCB的RAD特性。

  TApplication封装的标准Windows行为大致包括如下几部分:

  1 Windows 消息处理

  2 上下文关联的在线帮助

  3 菜单的快捷键和键盘事件处理

  4 异常处理

  5 管理由操作系统定义的程序基础部分,如:MainWindow 主窗口、WindowClass 窗口类等。

  一般情况下,BCB会为每个程序自动生成一个TApplication类的实例。这部分源码可以在yourproject.cpp文件中见到(这里假定您的工程名称就叫yourproject.bpr)。

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

  当然TApplication是不可见的,他总是在您的Form背后默默的控制着您的程序的行为。但也不是找不到蛛丝马迹。如果您新建一个程序(New Application),然后不作任何改动,编译运行的话,你会发现程序窗体的Caption是Form1,但在Windows的状态条上的Caption确写着project1的字样。这就是TApplication存在的证据。当然,这只是一种臆测,实战的方法应该打开BCB附带的WinSight来查看系统的进程。您可以清楚的看到TApplication类的存在,他的大小是0(隐藏的嘛),然后才是TForm1类。

  好了,既然TApplication封装了消息处理的内容。我们就研究一下TApplication的实际动作吧。实际上消息到达BCB程序时,最先得到它们的就是TApplication对象。经由TApplication之后,才传递给Form的。以前的方法都是重载TForm的方法,显然要比本文所提到的方法要晚一些收到消息。对您来说,是不是希望在第一时间收到消息并处理它们呢?

  要清楚的知道TApplication的处理机制还是深入VCL源码。首先看一看最最普通的一段代码吧。

  

#include vcl.h #pragma hdrstop USERES("Project1.res"); USEFORM("Unit1.cpp", Form1);
//--------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{ try { // 初始化Application Application-Initialize(); // 创建主窗口,并显示
Application-CreateForm(__classid(TForm1), &Form1); // 进入消息循环,直到程序退出Application-Run();
}
catch (Exception &exception)
{ Application-ShowException(&exception);
}
return 0;
}

  短短的几行代码就可以让您的BCB程序自如运行。因为一切都已经被VCL在后台封装好了。Application-Run()方法进入程序的消息循环,直到程序退出。一起跟进VCL源码看个究竟吧。TApplication的定义在forms.pas中。procedure TApplication.Run;

  

begin FRunning := True;
try AddExitProc(DoneApplication);
if FMainForm nil then begin // 设置主窗口的显示属性
case CmdShow of
SW_SHOWMINNOACTIVE: FMainForm.FWindowState := wsMinimized; SW_SHOWMAXIMIZED: MainForm.WindowState := wsMaximized;
end;
if FShowMainForm then
if FMainForm.FWindowState = wsMinimized then
Minimize else
FMainForm.Visible := True;
// 看见了吧,这里有个循环,直到Terminated属性为真退出。Terminated什么意思,就是取消,结束
repeat
HandleMessage
until Terminated;
end;
finally
FRunning := False;
end;
end;

  消息处理的具体实现不在Run方法中,很显然关键在HandleMessage方法,看看这函数名字-消息处理。只有跟进HandleMessage瞧瞧喽。

  

procedure TApplication.HandleMessage;
var
Msg: TMsg;
begin
if not ProcessMessage(Msg) then Idle(Msg);
end;

  咳,这里也不是案发现场。程序先将消息交给ProcessMessage方法处理。如果没什么要处理的,就转入Application.Idle方法程序在空闲时调用的方法。

  呼呼,再跟进ProcessMessage方法吧。

  

function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
Handled: Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
begin
Result := True;
if Msg.Message WM_QUIT then
begin
Handled := False;
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end
else
FTerminate := True;
end;
end;

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

  哎呀呀,终于有眉目了。ProcessMessage采用了一套标准的Windows API 函数PeekMessage .... TranslateMessage;DispatchMessage。

  有人说:Application-OnMessage = MyOnMessage; //不能响应SendMessage的消息,但是可以响应PostMessage发送的消息,也就是消息队列里的消息

  SendMessage和PostMessage最主要的区别在于发送的消息有没有通过消息队列。

  原因就在这里。ProcessMessage使用了PeekMessage(Msg, 0, 0, 0, PM_REMOVE) 从消息队列中提取消息。然后先检查是不是退出消息。不是的话,检查是否存在OnMessage方法。如果存在就转入OnMessage处理消息。最后才将消息分发出去。

  这样重载Application的OnMessage方法要比前两种方法更早得到消息,可以说是最快速的方法了吧。举个例子:

  

void __fastcall TForm1::MyOnMessage(tagMSG &Msg, bool &Handled)
{
TMessage Message;
switch (Msg.message)
{
case WM_KEYDOWN:
Message.Msg = Msg.message;
Message.WParam = Msg.wParam;
Message.LParam = Msg.lParam;
MessageDlg("You Pressed Key!", mtWarning, TMsgDlgButtons() mbOK, 0);
Handled = true;
break;
}
}
void __fastcall TForm1::FormCreate(TObject *Sender)
Application-OnMessage = MyOnMessage;
}

  现在可以简短的总结一下VCL的消息机制了。

  标准的BCB程序使用Application-Run()进入消息循环,在Application的ProcessMessage方法中,使用PeekMessage方法从消息队列中提取消息,并将此消息从消息队列中移除。然后ProcessMessage 方法检查是否存在Application-OnMessage方法。存在则转入此方法处理消息。之后再将处理过的消息分发给程序中的各个对象。至此,WndProc方法收到消息,并进行处理。如果有无法处理的交给重载的Dispatch方法来处理。要是还不能处理的话,再交给父类的Dispatch方法处理。最后Dispatch方法实际上将消息转入DefaultHandler方法来处理。

  嘿嘿,实际上,你一样可以重载DefaultHandler方法来处理消息。但是太晚了一点。我想没有人愿意最后一个处理消息吧...:-)

  写到这里似乎可以结束了。但如果您看过上一篇的话,一定会注意到Application-HookMainWindow方法。这又是怎么一回事呢?

  如果您打算使用Application-OnMessage来捕获所有发送至您的应用程序的消息的话,您大概要失望了。原因已经讲过,它无法捕获使用SendMessage直接发送给窗口的消息,因为这不通过消息队列。您也许会说我可以直接重载TApplication的WndProc方法。呵呵,不可以。因为TApplication的WndProc方法被Borland申明为静态的,从而无法重载。显而易见,这么做的原因很可能是Borland担心其所带来的副作用。那该如何是好呢?

  查看TApplication的WndProc的pascal源码可以看到:

  

procedure TApplication.WndProc(var Message: TMessage);
... // 节约篇幅,此处与主题无关代码略去
begin
try
Message.Result := 0;
for I := 0 to FWindowHooks.Count - 1 do
if TWindowHook(FWindowHooks[I]^)(Message) then Exit;
... // 节约篇幅,此处与主题无关代码略去

  WndProc方法一开始先调用HookMainWindow挂钩的自定义消息处理方法,然后再调用缺省过程处理消息。这样使用HookMainWindow就可以在WndProc中间接加入自己的消息处理方法。使用这个方法响应SendMessage发送来的消息很管用。最后提醒一下,使用HookMainWindow挂钩之后一定要对应的调用UnhookMainWindow卸载钩子程序。给个例子:

  

void __fastcall TForm1::FormCreate(TObject *Sender)
{
Application-HookMainWindow(AppHookFunc);
}
bool __fastcall TForm1::AppHookFunc(TMessage &Message)
{
bool Handled ;
switch (Message.Msg)
{
case WM_CLOSE:
mrYes==MessageDlg("Really Close??", mtWarning, TMsgDlgButtons() mbYes mbNo, 0)? Handled = false : Handled = true ;
break;
}
return Handled;
}
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
Application-UnhookMainWindow(AppHookFunc);
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
SendMessage(Application-Handle,WM_CLOSE,0,0);
}

  这样,将本文中的两种方法相结合,您就可以自如的处理到达您的应用程序的各种消息了。(全文完)

展开更多 50%)
分享

猜你喜欢

深入VCL理解BCB的消息机制3

编程语言 网络编程
深入VCL理解BCB的消息机制3

深入VCL理解BCB的消息机制2

编程语言 网络编程
深入VCL理解BCB的消息机制2

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

深入VCL理解BCB的消息机制1

编程语言 网络编程
深入VCL理解BCB的消息机制1

深入理解Delphi的消息机制

Delphi
深入理解Delphi的消息机制

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

理解Windows消息机制

编程语言 网络编程
理解Windows消息机制

在BCB中使用VCL控件数组2

编程语言 网络编程
在BCB中使用VCL控件数组2

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

打印Memo的文本信息

打印Memo的文本信息

也许爱一个人就在拨通电话 - QQ情侣分组

也许爱一个人就在拨通电话 - QQ情侣分组
下拉加载更多内容 ↓