您现在的位置: 中国教师站 >> 教师关注 >> 电脑技术 >> 编程技术 >> Delphi >> 正文

Google
深入Delphi (三)
作者:Siny 文章来源:中国教师站cn-teacher 点击数: 更新时间:2007-4-22 16:01:22

深入Delphi (三)

Windows 消息机制

by machine

  大家是不是很奇怪为什么我还没说到Delphi的控件呢?不过不用着急,有关深入控件的内容,将会很快出现了,但在这之前,还得了解Windows图形界面程序的机制——Windows的消息机制。
  使用过Delphi的朋友都知道,Delphi是一个真正面向对象的编程环境,但是不但如此,Delphi的这种面向对象的机制是单纯的建立在Windows的消息机制上的Delphi代码,而不是像VB、VFP之类的调用DLL、OCX,通过查看Delphi控件的源代码,你可以知道整个机制是怎样组织起来的,而且你可以完完全全地控制这些控件,因为它们只是用Delphi代码编写的,而不是存在在DLL中看不见的东西。
  那么Windows所谓的消息(Message)机制到底是什么呢?还记得以前学Basic的时候,根本没有什么事件之类的东西,整个程序是用流程图来描绘的,在程序需要键盘输入的地方,整个程序就停下来等待输入,然后根据输入来做不同的事情。这样做本来是没什么问题的,但是到了图形界面的时候,情况不同了,鼠标输入成了一个很大的问题,而且在Windows这样的多任务系统下,不可能让一个程序不断的测试设备状态那样子来获得输入。
  总之呢,Windows下的消息机制是完全不同的,即使与单纯的中断事件比起来,还是有很多不同的地方。
  简单的说来,一个线程在创建窗体的时候,会自动生成一个消息队列,但窗体不是必要的,可以通过其他途径来创建消息队列。然后,其他的程序,或者Windows系统本身,可以向这个线程发送消息到它的消息队列中,通知这个线程有什么东西发生了,这就是所谓的事件。每个进程都可以使用GetMessage函数获得它的消息队列中最前面的一个消息,GetMessage同时会自动将此消息从消息队列中删除掉,当然也可以指定不删除消息,这个以后再说。光听可能还是不能想象出来,那就看以下的例子吧:

program Sample3;

uses
 Windows,
 Messages;

var Msg: TMsg;

begin
  PostMessage(0, WM_USER, 0, 0); // 首先强制生成消息队列
  PeekMessage(Msg, 0, WM_USER, WM_USER, 0);
  // 然后这里就是所谓的消息循环,只有当收到WM_QUIT的消息时,GetMessage()才会返回False
  while GetMessage(Msg, 0, 0, 0) do begin
  end;
  // 这里可以做程序结束前(收到WM_QUIT后)的工作
end.

  这个程序运行后不会干任何事情,同时也会忽略一切Windows发给它的消息,除了WM_QUIT之外,因为GetMessage这个函数有一个特点,当收到其他消息的时候,GetMessage的返回值是TRUE,而在收到WM_QUIT的时候返回值则为FALSE,因此消息循环就被打破了。在Windows关闭的时候,Windows会自动发一个WM_QUIT的消息到这个程序的主线程,然后程序就退出了。
  绝大多数的程序的主体就是这个样子,都有一个消息循环,也就是说,每一个程序都是不断的使用GetMessage尝试获得新的消息,然后处理,周而复始,直到收到WM_QUIT为止。而其中高明之处,就是GetMessage在被调用的时候,如果检查出消息队列中没有消息,则函数不会马上返回,而是使线程转入睡眠状态,因而线程不会因为不断的循环而浪费CPU时间。在有新的消息收到之后,线程会重新苏醒,GetMessage把收到的消息放到一个TMsg类型的参数里面返回,于是程序就可以处理这个消息了。
  好了,这个消息机制是如何和窗体程序结合在一起的呢?换句话说,如果程序生成了窗体,那么程序又如何通过这个消息机制获取用户的输入消息呢?这就要从创建窗体的过程说起了。以下是一个比较复杂一点的例子:

program Sample4;

uses
 Windows,
 Messages;

var
 Msg: TMsg;
 wc: TWndClass; // RegisterClass()所需要的参数
 hWnd: THandle; // 主窗体的句柄

const
 ClassName = 'MainWClass';

function MainWndProc(Handle: THandle; MsgID: UINT; wParam, lParam: Integer): LRESULT; stdcall;
begin
  Result := 1;
  case MsgID of

    WM_CLOSE: begin // 关闭窗体所产生的消息
      if MessageBox(Handle,
        '要关闭这个程序吗?',
        '例子程序-4',
        MB_ICONQUESTION or MB_YESNO
          ) = IDYES then
        DestroyWindow(hWnd)
      else
        Result := 0;
      Exit;
    end;

    WM_DESTROY: begin // DestroyWindow()所产生的消息
      PostQuitMessage(0);
    end;

  end;
  // 剩下的消息交给Windows预设的处理函数就可以了,比如画窗体的WM_NCPAINT消息等
  Result := DefWindowProc(Handle, MsgID, wParam, lParam);
end;

begin
  // 首先使用RegisterClass()注册窗体的类,这可不是Delphi数据类型中的类哦!
  wc.style := CS_HREDRAW or CS_VREDRAW;
  wc.lpfnWndProc := @MainWndProc; // 消息处理函数的地址
  wc.hInstance := hInstance; // 程序的句柄,同时也是基地址
  wc.hIcon := LoadIcon(0, PChar(IDI_APPLICATION));
  wc.hCursor := LoadCursor(0, IDC_ARROW); // 图标
  wc.hbrBackground := GetStockObject(WHITE_BRUSH); // 背景画刷
  wc.lpszClassName

[1] [2] 下一页

相关专题:
 
 网友评论:(评论内容只代表网友观点,与本站立场无关!)
GOOGLE广告

阅读排行

| 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 |
中国教师站

中国教师站 版权所有 Copyright © 2006-2020 All Rights Reserved 站长:Sina & Siny
[备用域名:www.JXZYW.Com] 有事请留言有事请留言
【实力成就精品 诚信呵护品牌】

信息产业部备案
苏ICP备06018635号