📄 delphi中的消息处理机制.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0067)http://blueflybird.silversand.net/Pascal_Delphi/Article/message.htm -->
<HTML><HEAD><TITLE>DELPHI中的消息处理机制</TITLE><!-- #BeginTemplate "/Templates/一般文章.dwt" --><!-- #BeginEditable "doctitle" --><!-- #EndEditable -->
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<META content=编程技术大全,C、C++、Delphi、Java name=编程技术大全>
<META content="编程 C C++ Basic Pascal Java Html 数据库 软件 使用 大全 资料" name=keywords>
<STYLE type=text/css>.unnamed1 {
COLOR: #000000; FONT-SIZE: 9pt; TEXT-DECORATION: none
}
</STYLE>
<META content="MSHTML 5.00.2919.6307" name=GENERATOR></HEAD>
<BODY bgColor=#c9dde0>
<TABLE border=0 width="100%">
<TBODY>
<TR>
<TD width="49%">
<TABLE border=0 width="103%">
<TBODY>
<TR>
<TD width="51%"><A class=unnamed1
href="http://blueflybird.silversand.net/index.html">首页</A> </TD>
<TD bgColor=#ff3333 width="49%">
<DIV align=center><FONT color=#ffff33><B>★</B></FONT><B><A
href="http://home4u.china.com/technology/programming/verybook/"
target=_blank><FONT color=#ffffcc>编程书籍下载</FONT></A></B><FONT
color=#ffff33><B>★</B></FONT></DIV></TD></TR></TBODY></TABLE></TD>
<TD class=unnamed1 width="41%">
<DIV align=right>New Win98帮助格式 本站所有文章都提供打包下载</DIV></TD>
<TD width="10%"><A
href="http://blueflybird.silversand.net/download.html">下载资料</A></TD></TR></TBODY></TABLE>
<DIV align=center>由于碧海银沙有时不支持断线续载,如果您有不能下载的东西,请到<A
href="http://go.163.com/~verybeauty">网易站</A><BR>对于Turbo C、Turbo C++、Turbo
Pascal这些编译器,请到<A href="http://home4u.china.com/technology/programming/verybook/"
target=_blank>快意恩仇书社的编程资料</A>相关栏目下载 <BR></DIV>
<HR SIZE=4>
<TABLE align=center border=0 width="75%">
<TBODY>
<TR>
<TD>
<DIV align=center>
<SCRIPT src="DELPHI中的消息处理机制.files/banneru_bird.js"></SCRIPT>
</DIV></TD></TR></TBODY></TABLE>
<DIV align=center></DIV>
<P><BR></P>
<TABLE align=center border=0 width="80%">
<TBODY>
<TR>
<TD><!-- #BeginEditable "%B7%D6%C0%E0" -->
<P align=center><B>DELPHI中的消息处理机制 </B><BR>(南京理工大学自控系研96马勇 <BR></P>
<P><BR><BR>Delphi是Borland公司提供的一种全新的WINDOWS编程开发工具.由于它采用了具有弹性的和可重用的面向对象Pascal(object-orientedpascal)语言,并有强大的数据库引擎(BDE),快速的代码编译器,同时又提供了众多出色的构件.受到广大编程人员的青睐.在众多的编程语言(如VB,PowerBuilder,Powerpoint等)中脱颖而出.
<BR><BR>其中一个DELPHI强于其他编程语言(如VB4.0)的地方就是在DELPHI中可自定义消息,并可直接处理消息.这对于那些希望编写自己的构件(Component),或者希望截获.过滤消息的用户来说是必不可少的.因为编写构件一般要对相应的消息进行处理.下面就对Delphi中消息处理机制进行一下介绍。
<BR><BR>一.DELPHIVCL中消息的传递
<BR>Delphi中每一个VCL(VisualComponentLibrary)构件(如Tbutton,Tedit等)都有一内在的消息处理机制,其基本点就是构件类接收到某些消息并把它们发送给适当的处理方法,如果没有特定的处理方法,则调用缺省的消息处理句柄。
<BR>下流程图说明了消息传递的一般途径,如图所示:
<BR><BR><BR><BR>其中mainwndproc是定义在Twincontrol类中的一个静态方法,不能被重载(Override)。它不直接处理消息,而是交由wndproc方法处理,并为wndproc方法提供一个异常处理模块。Mainwndproc方法声明如下:
<BR><BR>procedureMainWndProc(varMessage:TMessage);
<BR><BR>Wndproc是在Tcontrol类中定义的一个虚拟方法,由它调用dispatch方法来进行消息的分配,wndproc方法声明如下:
<BR><BR>procedureWndProc(varMessage:TMessage);virtual;
<BR><BR>dispatch方法是在Tobject根类中定义的,其声明如下:
<BR><BR>procedureTobject.dispatch(varMessage);传递给dispatch的消息参数必须是一个记录类型,且这个记录中第一个入点必须是一个cardinal类型的域(field),它包含了要分配的消息的消息号码.例如:
<BR><BR>type <BR>Tmessage=record <BR>Msg:cardinal; <BR>wparam:word;
<BR>lparam:longint;. <BR>result:longint; <BR>end;
<BR><BR>而Dispatch方法会根据消息号码调用构件的最后代类中处理此消息的句柄方法.如果此构件和它的祖先类中都没有对应此消息的处理句柄,Dispatch方法便会调用Defaulthandler方法.Defaulthandler方法是定义于Tobject中的虚拟方法,其声明如下:
<BR>procedureDefaulthandler(varMessage);virtual;
<BR><BR>Tobject类中的Defaulthandler方法只是实现简单的返回而不对消息进行任何的处理.我们可以通过对此虚拟方法的重载,在子类中实现对消息的缺省处理.对于VCL中的构件而言,其Defaulthandler方法会启动windowsAPI函数Defwindowproc对消息进行处理.
<BR><BR>二.DELPHI中的消息处理句柄 <BR>在DELPHI中用户可以自定义消息及消息处理句柄.消息处理句柄的定义有如下几个原则:
<BR>消息处理句柄方法必须是一个过程,且只能传递一个Tmessage型变量参数.
<BR><BR>方法声明后要有一个message命令,后接一个在0到32767之间的消息标号(整型常数).
<BR><BR>消息处理句柄方法不需要用override命令来显式指明重载祖先的一个消息处理句柄,另外它一般声明在构件的protected或private区.
<BR><BR>在消息处理句柄中一般先是用户自己对消息的处理,最后用inherited命令调用祖先类中对应此消息的处理句柄(有些情况下可能正相反).由于可能对祖先类中对此消息的处理句柄的名字和参数类型不清楚,而调用命令inherited可以避免此麻烦,同样如果祖先类中没有对应此消息的处理句柄,inherited就会自动调用Defaulthandler方法.(当然如果要屏蔽掉此消息,就不用inherited命令了)。
<BR>消息处理句柄方法声明为:
<BR>procedureMymsgmethod(varmessage:Tmessage);messageMsgtype;
<BR>同样用户也可以定义自己的消息,用户自定义消息应从WM_USER开始. <BR><BR>自定义消息及消息处理句柄举例如下:
<BR><BR>constmy_paint=Wm_user+1; <BR>type <BR>Tmypaint=record
<BR>msgid:cardinal; <BR>msize:word; <BR>mcolor:longint;
<BR>msgresult:longint; <BR>end; <BR>type
<BR>Tmycontrol=class(TCustomControl) <BR>protected
<BR>procedurechange(varmessage:Tmypaint);messagemy_paint; <BR>.....
<BR>end; <BR>...... <BR>procedureTmycontrol.change(varmessage:Tmypaint);
<BR>begin <BR>size:=message.msize;{设置Tmybutton尺寸属性}
<BR>color:=message.mcolor;{设置Tmybutton颜色属性} <BR>{dosomethingelse}
<BR>inherited;{交由Tcustomcontrol处理} <BR>end; <BR><BR><BR>三.过滤消息
<BR>过滤消息又称消息陷阱。在一定情况下,用户可能需要屏蔽某些消息.或者截获某些消息进行处理。由以上介绍可以看出过滤消息一般有三种途径:(1).重载构件继承的虚拟方法wndproc.(2).针对某消息编写消息处理句柄.(3).重载构件继承的虚拟方法Defhandler,在其中对消息进行处理。其中常用的方法是方法(2),在上节中已介绍过了,方法(1)与方法(3)相似,这里只简单介绍一下方法(1)。
<BR>重载虚拟方法wndproc的一般过程如下:
<BR>procedureTmyobject.wndproc(varmessage:Tmessage); <BR>begin
<BR>{...判断此消息是否该处理..} <BR>inheritedwndproc(message);
<BR>{未处理的消息交由父辈wndproc方法处理} <BR>end;
<BR><BR>由此可以看出在wndproc方法中处理消息的优势是可以过滤整个范围内的消息,而不必为每个消息指定一个处理句柄,事实上Tcontrol构件中就是利用它来过滤并处理所有的鼠标消息的(从WM_mousefirst到WM_mouselast,如下代码示).同样利用它也可以阻止某些消息被发送给处理句柄。
<BR>procedureTControl.WndProc(varMessage:TMessage); <BR>begin
<BR>if(Message.Msg>=WM_MOUSEFIRST)and
<BR>(Message.Msg<=WM_MOUSELAST) <BR>then <BR>ifDraggingthen{处理拖曳事件}
<BR>DragMouseMsg(TWMMouse(Message)) <BR>else <BR>...{处理其他鼠标消息} <BR>end;
<BR>Dispatch(Message); <BR>{否则正常发送消息} <BR>end; <BR><BR>下例为一简单的自定义构件例子:
<BR>Tmyedit类是从Tedit类派生出的一个新类,它的特点是在运行中不能获得焦点,不能由键盘输入(有点类似Tlabel构件).我们可在其wndproc方法中过滤出WM_setfocus,WM_mousemove消息并进行处理来达到上述要求,源程序如下:
<BR><BR>unitmyedit; <BR>interface <BR>uses
<BR>Windows,Messages,SysUtils,Classes,Graphics,
<BR>Controls,Forms,Dialogs, <BR>StdCtrls; <BR>type
<BR>Tmyedit=class(TEdit) <BR>private <BR>{Privatedeclarations}
<BR>protected <BR>{Protecteddeclarations} <BR>{otherfieldsandmethods}
<BR>procedurewndproc(varmessage:Tmessage);override; <BR>public
<BR>{Publicdeclarations} <BR>published <BR>{Publisheddeclarations}
<BR>end; <BR>procedureRegister; <BR>implementation <BR>procedureRegister;
<BR>begin <BR>RegisterComponents('Samples',[Tmyedit]); <BR>end;
<BR>procedureTmyedit.wndproc(varmessage:tmessage); <BR>begin
<BR>ifmessage.msg=wm_mousemovethen <BR>begin <BR>cursor:=crarrow;
<BR>{设置光标为crarrow,而不是缺省的crBeam光标} <BR>exit; <BR>end;
<BR>ifmessage.msg=wm_SetFocusthenexit;
<BR>{屏蔽掉WM_setfocus消息,不让Tmyedit控件获得输入焦点} <BR>inheritedwndproc(message);
<BR>{其他消息交父辈wndproc处理} <BR>end; <BR>end.
<BR><BR>您可以将Tmyedit加到ComponentPalette中检验其性能。
<BR>由以上介绍可以看出,只有清楚了DelphiVCL中的消息处理机制,掌握好处理各种消息的方法和时机(必要时要借助各种工具,如winsight32,spy等),并结合OOP语言的特点,我们才可能编出高质量的构件。这当然要靠读者在实践中不断摸索,积累经验。
<BR></P><!-- #EndEditable --></TD></TR></TBODY></TABLE>
<HR SIZE=4>
<TABLE align=center border=0 width="75%">
<TBODY>
<TR>
<TD>
<DIV align=center>
<SCRIPT src="DELPHI中的消息处理机制.files/bannerd_bird.js"></SCRIPT>
</DIV></TD></TR></TBODY></TABLE><SPAN class=unnamed1><SPAN
class=unnamed1><BR></SPAN></SPAN>
<P align=center><SPAN class=unnamed1><SPAN class=unnamed1><SPAN
class=unnamed1>飞鸟工作室 1999 有任何意见和建议</SPAN></SPAN>请发</SPAN><A
href="mailto:blueflybird@163.net">Email</A></P><!-- #EndTemplate -->
<SCRIPT language=JavaScript>
function showhide() {
var i, ss, cc, rr;
cc = showhide.arguments;
for (i=0; i<(cc.length-2); i+=3)
{ ss = cc[i+2];
if (navigator.appName == 'Netscape' && document.layers != null)
{ rr = eval(cc[i]);
if (rr) rr.visibility = ss;
} else if (document.all != null)
{ if (ss == 'show') ss = 'visible';
if (ss == 'hide') ss = 'hidden'; rr = eval(cc[i+1]);
if (rr) rr.style.visibility = ss;
}
}}
function keepIE(WinName,WinTop,WinLeft) {
document.all[WinName].style.top=WinTop+parseInt(document.body.scrollTop)+document.body.clientHeight-90
document.all[WinName].style.left=WinLeft+parseInt(document.body.scrollLeft)+document.body.clientWidth-80
}
function keepNN(WinName,WinTop,WinLeft) {
document.layers[WinName].moveTo(self.pageXOffset+WinLeft+window.innerWidth-80,self.pageYOffset+WinTop+window.innerHeight-90)}
</SCRIPT>
<DIV id=content>
<P><A name=off></A></P>
<DIV id=Silversand
style="LEFT: 0px; POSITION: absolute; TOP: 0px; Z-INDEX: 1"><A
href="javascript:void(null)"
onclick="showhide('document.layers[\'Win0\']','document.all[\'Win0\']','show')"><IMG
border=0 height=48 src="" width=42 NOSAVE></A></DIV>
<SCRIPT language=JavaScript>
IE4=(document.all)?1:0
NN4=(document.layers)?1:0
if (IE4)
{
if( (document.body.clientHeight>300)&&(document.body.clientWidth>400) )
{
setInterval('keepIE("Silversand",0,0)',1000)
}
else
{
document.all['Silversand'].style.visibility = 'hidden';
}
}
if (NN4)
{
if( this.window.innerHeight<300 )
{
document.layers['Silversand'].visibility = 'hide'
}
if( this.window.innerWidth<400 )
{
document.layers['Silversand'].visibility = 'hide'
}
else
{
setInterval('keepNN("Silversand",0,0)',1000)
}
}
</SCRIPT>
<DIV id=Win0
style="HEIGHT: 120px; POSITION: absolute; VISIBILITY: hidden; WIDTH: 80px; Z-INDEX: 2">
<SCRIPT language=JavaScript>
IE4=(document.all)?1:0
NN4=(document.layers)?1:0
if (IE4)
setInterval('keepIE("Win0",-30,-30)',1000)
if (NN4)
setInterval('keepNN("Win0",-30,-30)',1000)
</SCRIPT>
<TABLE bgColor=#ecf8ff border=0 cellPadding=3 width=80>
<TBODY>
<TR align=middle>
<TD align=middle vAlign=center><SMALL>=========<A
href="http://blueflybird.silversand.net/Pascal_Delphi/Article/message.htm#off"
onmouseover="showhide('document.layers[\'Win0\']','document.all[\'Win0\']','hide')">X</A><BR><A
href="http://www.silversand.net/sub/indextech.html" target=_blank
title=WEB技术、编程、软件、硬件及相关资讯>电脑网络<BR>系列站点</A><BR><BR><A
href="http://bookmark.silversand.net/cgi-bin/bookmark/viewsilversand.cgi"
target=_blank title=碧海银沙全面导航>银沙书签</A><BR><A
href="http://www.silversand.net/"
target=_blank>碧海银沙</A><BR></SMALL></TD></TR></TBODY></TABLE></DIV></DIV>
<DIV></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -