首 页 网络编程
网页制作 图形图象 操作系统 冲浪宝典
软件教学 认证考试

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 网络编程-> Delphi教程
delphi关于线程的消息处理_delphi教程
作者:网友供稿 点击:0
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 
 

在平时写程序时,总是碰到窗体(TForm)与线程(TThread)消息通信问题。令人烦恼的是窗体不能向线程(TThread)发送消息(线程没有窗口句柄)。经过几天的折腾,想出二种解决方案,拿出来跟大家探讨探讨。

第一。我们知道VC++ 中的MFC类库是自已封装了消息处理(BEGINMESSAGE, ENDMESSAGE),在MFC中对消息的处理是通过建立一张消息映射表,而把方法(function)或过程(procedure)的地址保存到映射表里(消息处理实质上是方法或过程的调用),再加上一个消息分发机制,来实现消息的接收发送 <详见VC++技术内幕>。所以我们只要为线程里建立一张消息映射表,并建立相应的消息分发机制。这样就可以处理窗体发送到线程的消息。以下代码是实现消息映射表和消息分发的类(详见 <..\消息处理设计(线程)1\MessageHandle.pas>

unit MessageHandle;

 

interface

uses messages,Classes,SysUtils,Dialogs;

 

const PMSG_BASE = $BE00;   //自定义消息基址;

      PMSG_NUM = 200;      //消息表大小;

 

{**自定义消息处理类

  *;功能 = 建立自定义消息表,处理线程之间

  *   以及与主窗体之间的自定义消息(宏观)

*}

 

  //消息处理句柄

  TMessageHandle = procedure(var Message: TMessage) of Object;

 

  TPDispatcher = class(TObject)

  private

    //消息对应表(消息ID为数组下标);

    MessageHandles: array of TMessageHandle;

    //从消息ID得到数组ID

    function GetIndexFromMsgID(const aMessageID: cardinal): Integer;

  public

    constructor Create;

    destructor Destroy;

    //发送消息

    procedure SendMessage(var Message: TMessage); overload;

    //添加自定义消息到消息对应表;

    procedure AddHandle(const aMessageID: cardinal; aMessageHandle: TMessageHandle);

  end;

  //

 

implementation

 

{ TPDispatcher }

constructor TPDispatcher.Create;

var i: Integer;

begin

  SetLength(MessageHandles,PMSG_NUM);  //200个消息的消息对应表

  //初始化消息队列;

  for i := 0 to Pred(PMSG_NUM) do

    MessageHandles[i] := nil;

end;

 

destructor TPDispatcher.Destroy;

begin

   {释放消息对应表}

  FreeAndNil(MessageHandles);

end;

 

procedure TPDispatcher.AddHandle(const aMessageID: cardinal;

  aMessageHandle: TMessageHandle);

var tID: Integer;

begin

  tID := GetIndexFromMsgID(aMessageID);

  Assert((tID > 0) or (tID < Pred(PMSG_NUM)) );

  Assert(Assigned(aMessageHandle));

  MessageHandles[tID] := aMessageHandle;

end;

 

function TPDispatcher.GetIndexFromMsgID(const aMessageID: cardinal): Integer;

begin

  Result := aMessageID - PMSG_BASE;

end;

 

procedure TPDispatcher.SendMessage(var Message: TMessage);

var tID: Integer;

    tMsgHandle: TMessageHandle;

begin

  tID := GetIndexFromMsgID(Message.Msg);

  Assert((tID > 0) or (tID < Pred(PMSG_NUM)));

  tMsgHandle := MessageHandles[tID];

 

  if Assigned(tMsgHandle) then

    tMsgHandle(Message);

end;

现在我们只需要注册一下自定义的消息,然后通过消息分发类(TPDispatcher),实现对线程消息的处理。代码如下<详见..\消息处理设计(线程)1\test\unit1.pas>

Unit unit1

const

      {自定久线程消息}

      MY_MESSAGE2 = PMSG_BASE + 02; 

type

  TForm1 = class(TForm)

    AddMsgList: TButton;

    SendThead: TButton;

    sendForm: TButton;

    sendOther: TButton;

    procedure SendTheadClick(Sender: TObject);  //发送消息

    procedure FormCreate(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

  private

    Fdispatcher: TPDispatcher;  消息映射表类

    Fhandle: TPHandler;

    FThread:  TPTHread;  自定义线程类

  public

    { Public declarations }

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

procedure TForm1.SendTheadClick(Sender: TObject);

var aMessage: TMessage;begin

    aMessage.Msg := MY_MESSAGE2;

    aMessage.WParam := 1;

    Fdispatcher.SendMessage(aMessage);

  end;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

  {创建消息映射表类}

  Fdispatcher := TPDispatcher.Create;

  Fhandle := TPHandler.Create;

  {创建线程}

    FThread := TPThread.Create(false);

  {向映射表中增加消息}

   Fdispatcher.AddHandle(MY_MESSAGE2,FThread.DoMessage);

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

var i: Integer;

begin

  FreeAndNil(Fdispatcher);

  FreeAndNil(Fhandle);

  for i:= 0 to 3 do

    FreeAndNil(FThread[i]);

end;

 

第二。窗口可以处理消息是因为它有窗口句柄。为了使线程也能处理消息,我们可以通过为线程加上一个相应窗口类的窗口名柄。(源码在 <..\消息处理设计(线程)2 \ pThread.pas >中)

unit pThread;

 

interface

uses classes,sysutils,Windows,Messages,Dialogs;

const MY_MESSAGE1 = $BD00 + 01;

Type

{** 消息处理线程类

  *;功能 = 添加线程处理消息能力,

*}

  TPMsgThread = class(TThread)

  private

    //窗口句柄

    FWndHandle: HWND;

    //窗口数据信息

    FWndClass: WNDCLASS;

    //指向窗口回调函数的指针

    FObjectInstance: Pointer;

    //初始化窗口数据

    procedure InitWnd;

    //创建隐藏窗口

    procedure CreateWnd;

    //注册隐藏窗口

    procedure RegistWnd;

    procedure DestroyWnd;

    //窗口回调函数

    procedure pWndProc(var Message: TMessage); virtual;

  protected

    procedure Execute; override;

    procedure DoTerminate; override;

  public

    constructor Create(CreateSuspended: Boolean); virtual;

    property WndHandle: HWND read FWndHandle write FWndHandle;

  end;

 

implementation

const WND_NAME = PY20;

{ TPMsgThread }

 

constructor TPMsgThread.Create(CreateSuspended: Boolean);

begin

  inherited Create(CreateSuspended);

  FWndHandle := Integer(nil);

  InitWnd;

  RegistWnd;

  CreateWnd;

end;

 

procedure TPMsgThread.CreateWnd;

begin

  if(WndHandle = Integer(nil)) then

    WndHandle := CreateWindow(FWndClass.lpszClassName, FWndClass.lpszClassName,

      WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU

      or WS_MINIMIZEBOX,

      GetSystemMetrics(SM_CXSCREEN) div 2,

      GetSystemMetrics(SM_CYSCREEN) div 2,

      0, 0, 0, 0, FWndClass.hInstance, nil);

  //置换窗口回调函数

  SetWindowLong(WndHandle, GWL_WNDPROC, Longint(FObjectInstance));

end;

 

procedure TPMsgThread.DestroyWnd;

begin

  UnregisterClass(FWndClass.lpszClassName,FWndClass.hInstance);

  DestroyWindow(WndHandle);

end;

 

procedure TPMsgThread.DoTerminate;

begin

  inherited;

  DestroyWnd;

end;

 

procedure TPMsgThread.Execute;

begin

end;

 

procedure TPMsgThread.InitWnd;

begin

  FwndClass.lpszClassName := PChar(WND_NAME);

  FWndClass.hInstance := Handle;

  FWndClass.lpfnWndProc := @DefWindowProc;

end;

 

procedure TPMsgThread.pWndProc(var Message: TMessage);

begin

end;

 

procedure TPMsgThread.RegistWnd;

begin

  FObjectInstance := Classes.MakeObjectInstance(pWndProc);

  if(FWndClass.hInstance <> Integer(nil)) then

    RegisterClass(FWndClass);

end;


文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·ListBox控件基本功能-.NET教程,组件控件开发
·用window.location.href实现刷新另个框架页面-.NET教程,Asp.Net开发
·JSP+STRUTS+EJB+DAO+HIBERNATE实例-JSP教程,Jsp/Servlet
·.NET中的设计模式四:命令模式-.NET教程,Asp.Net开发
·数字转英文(货币)大写-.NET教程,数据库应用
·用户控件用户登录判断-ASP教程,客户端相关
·计数器的另一用法:自动切换首页图片-ASP教程,ASP应用
·漫谈Java数据库存取技术-JSP教程,Java技巧及代码
·正则表达式-.NET教程,Asp.Net开发
·即时通讯靠免费短信能赚10亿?
最新文章
·让flash动画适应任何分辨率的网页_flash教程
·新手必看之网站的定位篇_站长心得
·1000ip的效益也能大于一万ip_网赚技巧
·google adsense课堂:西联快汇知识_网赚技巧
·googleadsense的无效点击_google推广
·google adsense高价关键字[排行榜]_google推广
·google搜索引擎的十大应用_google推广
·windows vista下如何关闭远程控制_windows vista
·修改配置 让windows vista系统实现自动登录_windows vista
·整齐划一 将整个网页保存在一个文件中_站长心得
相关主题
  • delphi命令行参数_delphi教程
  • delphi多线程程序示例(与.net一样简单)_delphi教程
  • delphi面向对象支持特点--保护级类成员的应用_delphi教程
  • delphi中的包(三):bpl和dll_delphi教程
  • delphi中的包(一):关于exe的编译、连接和执行_delphi教程
  • 西部数码虚拟主机

    友情链接
    CNNIC 西部数码
    万网 自助建站
    虚拟主机 asp空间
    域名注册 域名
    域名申请 主页空间
    论坛空间 网站空间
    国际域名 虚拟空间
    空间租用 DDOS防火墙
    成都主机托管 四川主机托管
    主机租用 服务器租用
    网站目录 自助建站
    虚拟主机 网址大全
    软件下载
    自助链接
    虚拟主机资讯 特价虚拟主机
    版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
    关于我们:站长天空:专业提供最新的站长资讯、在线教程、虚拟主机权威评测、虚拟主机性能对比、网站制作教程,开发教程,站长工具。包括网页制作教程、冲浪宝典、编程参考、操作系统、软件教学、行业动态等。
    特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
    发表评论 打印  刷新     关闭