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;
From:http://tw.wingwit.com/Article/program/Delphi/201311/24698.html