======================================================
注:本文源代码点此下载
======================================================
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^)/