Delphi中SendMessage使用技巧


======================================================
注:本文源代码点此下载
======================================================

windows系统是由消息机制驱动的,每个线程如果建立了一个窗口,则由系统分配一个消息队列用于窗口消息的处理。另外,消息也可以不经过消息队列而利用sendmessage函数直接发送给窗口,窗口过程将处理这个消息,但只有当消息被处理之后,sendmessage才能返回到调用程序。下面结合两个delphi程序,讨论如何利用sendmessage向控件发送消息和控件对这种消息的响应。

用sendmessage向控件发送消息

在编程中,有时需要控件以特殊的风格显示,而这种要求又无法通过设置控件属性实现。例如,读取客户列表并显示在下拉框供用户选择,如果下拉框宽度太窄,则不能全部显示;如果将宽度定得太宽,界面又有不紧凑之感。因此希望能在运行期动态地确定下拉框显示区域的宽度,这种要求如果不用sendmessage函数就很难实现。

解决办法是,在读数据库时计算字符串的显示宽度,用显示宽度的最大值确定下拉框显示区域的宽度。再用sendmessage函数向下拉框发送cb_setdroppedwidth消息和宽度值,下拉框根据消息中传来的信息,就可以进行正确显示。

部分源程序代码如下:

i:=0; //计数

maxwidth:=0;

query1.sql.clear;

query1.sql.add(‘select company from customer’);

query1.open;

//读客户列表到下拉框

while not query1.eof do begin

combobox1.items.add(query1.fieldbyname

(‘company’).asstring);

width:=combobox1.font.size * length

(combobox1.items[i]);

if width>maxwidth then

maxwidth:=width; //找出最大值

query1.next;

i:=i+1;

end;

query1.close;

combobox1.text:=combobox1.items[0];

//发送消息以确定显示区域的宽度

sendmessage(combobox1.handle,

cb_setdroppedwidth,maxwidth,0);

利用sendmessage函数还可以实现一些有趣的效果,例如在按钮的click事件中加入如下语句:

sendmessage(button.handle,bm_setstyle,

bs_radiobutton,1);

运行后点击按钮,就可以把按钮变成一个收音机按钮。

控件接收sendmessage消息

上面讨论了用sendmessage向控件发送消息的过程。但凡事有利就有弊,用sendmessage发送的消息在处理上存在着一定困难。因为该消息不经过消息队列,所以无法用onmessage方式来指定对消息的响应,甚至用hookmainwindow也不行,因为消息直接发送到控件,绕过了主窗体。要对这种类型的消息作出响应,需要重载控件的wndproc方法。

例如,对于一个列表框,滚动条的滚动消息就是用sendmessage方式发送的,因此该消息不在tlistbox的事件列表中。下面是处理控件响应该滚动消息的具体步骤。

1.首先从tlistbox继承一个tmylistbox类,并重载wndproc方法。在程序中加入下列定义:

type

tmylistbox=class(tlistbox)

private

procedure wndproc(var msg: tmessage);

override;

//重载wndproc,处理发送到控件的消息

public

end;

其中wndproc方法指定控件对消息的响应,输入参数是tmessage类型,该数据类型是一个记录,包含了消息代码和消息的参数,消息参数可以用longint或word方式获得。

2.对滚动事件做出响应,在wndproc方法中加入如下处理代码:

if (msg.msg=wm_vscroll) and

(msg.wparamlo=sb_endscroll) then

begin

//获得鼠标位置对应的列

itemindex:=itematpos(point,true);

form1.edit1.text:=inttostr(itemindex);

inherited;

end

else

inherited;

当程序接收到wm_vscroll消息,且wparamlo参数为sb_endscroll时,表示竖直滚动条停止滚动,就可以用itematpos方法确定与鼠标位置对应的itemindex。itematpos方法的point参数是一个tpoint类型的变量,用来保存鼠标的位置。

3.定义方法listboxmousemove,在鼠标移动时,将当前位置保存在point中:

procedure tform1.listboxmousemove(sender:

tobject; shift: tshiftstate; x,y: integer);

begin

point.x:=x;

point.y:=y;

end;

4.在运行期创建和初始化列表框,并指定列表框的mousemove事件对应上一步定义的listboxmousemove方法。在主窗体的create事件中输入下面的代码:begin

point.x:=0;

point.y:=0;

//创建自定义列表框

list:=tmylistbox.create(form1);

list.parent:=form1;

list.left:=5;

list.top:=30;

list.width:=150;

list.height:=200;

for i:=0 to 300 do

begin

list.items.add(inttostr(i)); //初始化

end;

//指定处理mousemove事件的方法

list.onmousemove := listboxmousemove;

end;


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值