Windows系统是由消息机制驱动的每个线程如果建立了一个窗口则由系统分配一个消息队列用于窗口消息的处理另外消息也可以不经过消息队列而利用SendMessage函数直接发送给窗口窗口过程将处理这个消息但只有当消息被处理之后SendMessage才能返回到调用程序下面结合两个Delphi程序讨论如何利用SendMessage向控件发送消息和控件对这种消息的响应
用SendMessage向控件发送消息
在编程中有时需要控件以特殊的风格显示而这种要求又无法通过设置控件属性实现例如读取客户列表并显示在下拉框供用户选择如果下拉框宽度太窄则不能全部显示如果将宽度定得太宽界面又有不紧凑之感因此希望能在运行期动态地确定下拉框显示区域的宽度这种要求如果不用SendMessage函数就很难实现
解决办法是在读数据库时计算字符串的显示宽度用显示宽度的最大值确定下拉框显示区域的宽度再用SendMessage函数向下拉框发送CB_SETDROPPEDWIDTH消息和宽度值下拉框根据消息中传来的信息就可以进行正确显示
部分源程序代码如下
i:=; //计数
MaxWidth:=;
QuerySQLClear;
QuerySQLAdd(select Company from Customer);
QueryOpen;
//读客户列表到下拉框
while not QueryEof do begin
ComboBoxItemsadd(QueryFieldByName
(Company)AsString);
Width:=ComboBoxFontSize * Length
(ComboBoxItems[i]);
if Width>MaxWidth then
MaxWidth:=Width; //找出最大值
QueryNext;
i:=i+;
end;
QueryClose;
ComboBoxText:=ComboBoxItems[];
//发送消息以确定显示区域的宽度
SendMessage(ComboBoxHandle
CB_SETDROPPEDWIDTHMaxWidth);
利用SendMessage函数还可以实现一些有趣的效果例如在按钮的Click事件中加入如下语句
SendMessage(ButtonHandleBM_SETSTYLE
BS_RADIOBUTTON)
运行后点击按钮就可以把按钮变成一个收音机按钮
控件接收SendMessage消息
上面讨论了用SendMessage向控件发送消息的过程但凡事有利就有弊用SendMessage发送的消息在处理上存在着一定困难因为该消息不经过消息队列所以无法用OnMessage方式来指定对消息的响应甚至用HookMainWindow也不行因为消息直接发送到控件绕过了主窗体要对这种类型的消息作出响应需要重载控件的WndProc方法
例如对于一个列表框滚动条的滚动消息就是用SendMessage方式发送的因此该消息不在TlistBox的事件列表中下面是处理控件响应该滚动消息的具体步骤
首先从TlistBox继承一个TmyListBox类并重载WndProc方法在程序中加入下列定义
type
TMyListBox=class(TListBox)
private
procedure WndProc(var Msg: TMessage);
override;
//重载WndProc处理发送到控件的消息
public
end;
其中WndProc方法指定控件对消息的响应输入参数是TMessage类型该数据类型是一个记录包含了消息代码和消息的参数消息参数可以用Longint或Word方式获得
对滚动事件做出响应在WndProc方法中加入如下处理代码
if (MsgMsg=WM_VSCROLL) and
(MsgWParamLo=SB_ENDSCROLL) then
begin
//获得鼠标位置对应的列
ItemIndex:=ItemAtPos(Pointtrue);
FormEditText:=inttostr(ItemIndex);
inherited;
end
else
inherited;
当程序接收到WM_VSCROLL消息且WParamLo参数为SB_ENDSCROLL时表示竖直滚动条停止滚动就可以用ItemAtPos方法确定与鼠标位置对应的ItemIndexItemAtPos方法的Point参数是一个TPoint类型的变量用来保存鼠标的位置
定义方法ListBoxMouseMove在鼠标移动时将当前位置保存在Point中
procedure TFormListBoxMouseMove(Sender:
TObject; Shift: TShiftState; XY: Integer);
begin
PointX:=X;
PointY:=Y;
end;
在运行期创建和初始化列表框并指定列表框的MouseMove事件对应上一步定义的ListBoxMouseMove方法在主窗体的Create事件中输入下面的代码begin
PointX:=;
PointY:=;
//创建自定义列表框
List:=TMyListBoxCreate(Form);
ListParent:=Form;
ListLeft:=;
ListTop:=;
ListWidth:=;
ListHeight:=;
for i:= to do
begin
ListItemsAdd(inttostr(i)); //初始化
end;
//指定处理MouseMove事件的方法
ListOnMouseMove := ListBoxMouseMove;
end;