VCL中訊息處理初探 (轉)
T是基類,所以我們先看一下TObject的DISPATCH方法。Dispatch根據傳入的message來尋找相應的訊息處理方法,如果找不到的話,就繼續向上到父類的訊息處理方法表中尋找響應的處理方法,一直到找到為止,如果找到頂還沒有,則DefaultHandle來處理該訊息。message可以是任何的型別,Dispatch假設message的頭兩位是訊息的ID,它就是根據ID來尋找訊息處理方法的。雖然任何型別的message都可以被接受,但是TObject的子類還是希望傳入的message引數是TMessage的記錄型別或其他證明的記錄型別。
以下宣告和註釋摘自與system.pas:
{ TObject.Dispatch accepts any data type as its Message parameter. The
first 2 bytes of the data are taken as the message id to search for
in the object's message methods. TDispatchMessage is an example of
such a structure with a field for the message id.
}
TDispatchMessage = record
MsgID: Word;
end;
類的繼承關係如下:
TObject->TPersistent->TComponent->TControl
TControl是所以視覺化的父類,TControl提供了一個新的方法,WndProc:
procedure TControl.WndProc(var Message: TMessage);
var
Form: TCustomForm;
KeyState: TKeyboardState;
WheelMsg: TCMMouseWheel;
begin
//如果處在設計期
if (csDesigning in ComponentState) then
begin
Fo:= GetParentForm(Self);//得到擁有該元件的窗體
if (Form <> nil) and (Form.Designer <> nil) and
Form.Designer.IsDesignMsg(Self, Message) then Exit //訊息由窗體來處理
end;
//窗體可以為其擁有的元件來處理鍵盤訊息。
if (Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST) then
begin
Form := GetParentForm(Self);
if (Form <> nil) and Form.WantChildKey(Self, Message) then Exit;
end
//關於滑鼠的訊息
else if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then
begin
//如果元件不可以接受和處理雙擊訊息,就將雙擊訊息對映為單擊訊息。
if not (csDoubleClicks in ControlStyle) then
case Message.Msg of
WM_LBUTTONLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK:
Dec(Message.Msg, WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
end;
case Message.Msg of
WM_MOUSEMOVE: Application.HintMouseMessage(Self, Message);//如果是滑鼠移動的訊息,則出現hint視窗
WM_LBUTTONDOWN, WM_LBUTTONDBLCLK://如果是左鍵被按下,或者雙擊,如果是自動拖動,則開始拖動,並將左鍵按下的狀態加入元件的狀態。
begin
if FDragMode = dmAutomatic then
begin
BeginAutoDrag;
Exit;
end;
Include(FControlState, csLButtonDown);
end;
WM_LBUTTONUP:
Exclude(FControlState, csLButtonDown); //如果是左鍵放開,則將左鍵按下的狀態剔除。
else
with Mouse do
if WheelPresent and (RegWheelMessage <> 0) and //如果滑鼠有滾輪,並且滾輪滑動時發出了訊息
(Message.Msg = RegWheelMessage) then
begin
GetKeyboardState(KeyState); //將256虛擬鍵的狀態複製到快取中去
with WheelMsg do //填充記錄
begin
Msg := Message.Msg;
ShiftState := KeyboardStateToShiftState(KeyState);
WheelDelta := Message.WParam;
P:= TSmallPoint(Message.LParam);
end;
MouseWheelHandler(TMessage(WheelMsg)); //派發滑鼠滾輪的訊息
Exit;
end;
end;
end
else if Message.Msg = CM_VISIBLECHANGED then
with Message do
SendDockNotification(Msg, WParam, LParam); //處理自定義訊息
Dispatch(Message); //派發未處理的訊息
end;
但是隻有TWinControl可以獲得焦點:
procedure TWinControl.WndProc(var Message: TMessage);
var
Form: TCustomForm;
begin
case Message.Msg of
WM_SETFOCUS: //設定的焦點
begin
Form := GetParentForm(Self);
if (Form <> nil) and not Form.SetFocusedControl(Self) then Exit;
end;
WM_KILLFOCUS:
if cocusing in ControlState then Exit;
//當滑鼠有活動的時候發出該訊息,如果滑鼠沒有被捕捉到,則訊息發往滑鼠下面的那個視窗,否則訊息將發往捕捉到滑鼠的那個視窗。
WM_NCHITTEST:
begin
inherited WndProc(Message); //呼叫父類的處理方法
//如果窗體被擋住並且在指定的點沒有控制元件,則返回結果為在client區。
if (Message.Result = HTTRANSPARENT) and (ControlAtPos(ScreenToClient(
SmallPointToPoint(TWMNCHitTest(Message).Pos)), False) <> nil) then
Message.Result := HTCLIENT;
Exit;
end;
WM_MOUSEFIRST..WM_MOUSELAST:
if IntrolMouseMsg(TWMMouse(Message)) then //滑鼠訊息是否直接發往元件的窗體子元件
begin
{ Check HandleAllocated because IsControlMouseMsg might have freed the
window if user code executed something like Parent := nil. }
if (Message.Result = 0) and HandleAllocated then
DefWindowProc(Handle, Message.Msg, Message.wParam, Message.lParam);//呼叫預設的的訊息處理方法對該訊息進行預設處理。
Exit;
end;
WM_KEYFIRST..WM_KEYLAST:
if Dragging then Exit;
WM_CANCELMODE:
if (GetCapture = Handle) and (CaptureControl <> nil) and
(CaptureControl.Parent = Self) then
CaptureControl.Perform(WM_CANCELMODE, 0, 0);
end;
inherited WndProc(Message);
end;
TApplication在中發揮著重要的作用:
Application.Run;
procedure TApplication.Run;
begin
FRunning := True;
try
AddExitProc(DoneApplication);
if FMainForm <> nil then
begin
case CmdShow of
SW_SHOWMINNOACTIVE: FMainForm.Ftate := wsMinimized;
SW_SHOWMAXIMIZED: MainForm.WindowState := wsMaximized;
end;
if FShowMainForm then
if FMainForm.FWindowState = wsMinimized then
Minimize else
FMainForm.Visible := True;
//一個訊息迴圈直到Tenated為True時才退出。
repeat
try
HandleMessage;
except
HandleException(Self);
end;
until Terminated;
end;
finally
FRunning := False;
end;
end;
procedure TApplication.HandleMessage;
var
Msg: TMsg;
begin
if not ProcessMessage(Msg) then Idle(Msg);
end;
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
Handled: Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then //從現成的訊息迴圈中取出訊息並放入指定的訊息結構中。
begin
Result := True;
if Msg.Message <> WM_QUIT then //如果不是退出訊息則進行相應的處理
begin
Handled := False;
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end
else
FTerminate := True;
end;
end;
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1000521/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android中的非同步訊息處理機制Android非同步
- Kafka中消費者延遲處理訊息Kafka
- MPLS RSVP訊息處理——VecloudCloud
- 如何處理錯誤訊息PleaseinstalltheLinuxkernelheaderfilesLinuxHeader
- .net core 訊息流處理流程
- 處理檔案上傳時的訊息格式轉換問題
- 如何處理RabbitMQ 訊息堆積和訊息丟失問題MQ
- SpringBoot:初探 RabbitMQ 訊息佇列Spring BootMQ佇列
- KafkaConsumer對於事務訊息的處理Kafka
- 原始碼分析:Android訊息處理機制原始碼Android
- Android應用程式訊息處理機制Android
- 回轉壽司你一定吃過!——Android訊息機制(處理)Android
- Cloud Foundry架構和訊息處理機制Cloud架構
- Laravel 實現 Kafka 訊息推送與接收處理LaravelKafka
- RocketMQ的事務訊息處理【half-message】MQ
- 【實戰教程】微信卡券訊息處理
- Handler訊息處理機制原始碼解析 上原始碼
- 訊息中介軟體消費到的訊息處理失敗怎麼辦?
- iOS 中多音訊處理iOS音訊
- 《球球大作戰》原始碼解析——(9)訊息處理原始碼
- Spring Cloud Stream如何處理訊息重複消費?SpringCloud
- 聊天列表訊息合併,處理相鄰時間
- 深入理解Android非同步訊息處理機制Android非同步
- Objective-C中的訊息轉發Object
- 處理python中的訊號Python
- 用程式碼理解 ObjC 中的傳送訊息和訊息轉發OBJ
- RabbitMQ,RocketMQ,Kafka 事務性,訊息丟失和訊息重複傳送的處理策略MQKafka
- 阿里雲訊息佇列 RocketMQ 5.0 全新升級:訊息、事件、流融合處理平臺阿里佇列MQ事件
- 如何處理錯誤訊息Please install the Linux kernel header filesLinuxHeader
- 如何處理錯誤訊息Please install the gcc make perl packagesGCPackage
- Kafka是如何處理Netflix每天2萬億條訊息的?Kafka
- 如何處理Docker錯誤訊息:please add——insecure-registryDocker
- 如何用 Golang 的 channel 實現訊息的批量處理Golang
- 如何用 Golang 的 channel 實現訊息的批次處理Golang
- mq要如何處理訊息丟失、重複消費?MQ
- Kafka叢集訊息積壓問題及處理策略Kafka
- 使用FUTURE 中的訊息避免計劃排程的批處理作業 - CodeOpinion
- iOS 訊息轉發iOS
- Spring Boot和Apache Kafka結合實現錯誤處理,訊息轉換和事務支援?Spring BootApacheKafka