在Windows應用程式中,表單是由一種稱為“UI線程(User Interface Thread)”的特殊類型的線程建立的。
首先,UI線程是一種“線程”,所以它具有一個線程應該具有的所有特徵,比如有一個線程函數和一個線程ID。
其次,“UI線程”又是“特殊”的,這是因為UI線程的線程函數中會建立一種特殊的對象——表單,同時,還一併負責建立表單上的各種控制項。
表單和控制項大家都很熟悉了,這些對象具有接收使用者操作的功能,它們是使用者使用整個應用程式的媒介,沒有這樣一個媒介,使用者就無法控制整個應用程式的運行和停止,往往也無法直接看到程式的運行過程和最終結果。
那麼,表單和控制項又是如何作到對使用者操作進行響應的呢?這一響應是不是由表單和控制項自己“主動”完成的?
換句話說:
表單和控制項具不具備獨立地響應使用者操作(比如鍵盤和滑鼠操作)的功能?
答案是否定的。
那就奇怪了,比如我們用滑鼠點擊了一個按鈕,並且看到它“陷”下去了,然後又還原,之後,我們確實看到了程式執行了此按鈕所對應的任務。難道不是按鈕來響應使用者操作的嗎?
這實際上是一個錯覺。這個錯覺產生的根源在於不瞭解Windows內部的運作機理。
簡單地說,表單和控制項之所以能響應使用者操作,關鍵在於負責建立它們的UI線程擁有一個“訊息迴圈(Message Loop)”。這個訊息迴圈由線程函數負責啟動,通常具有以下的“模樣”(以C++代碼錶示):
MSG msg; //代表一條訊息
BOOL bRet;
//從UI線程訊息佇列中取出一條訊息
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
//錯誤處理代碼,通常是直接退出程式
}
else
{
TranslateMessage(&msg); //轉換訊息格式
DispatchMessage(&msg); //分發訊息給相應的表單
}
}
可以看到,所謂訊息迴圈,其實就是一個While迴圈語句罷了。
其中,GetMessage()函數每次從訊息佇列中取出一條訊息,此訊息的內容被填充到變數msg中。
TranslateMessage()函數主要用於將WM_KEYDOWN和WM_KEYUP訊息轉換WM_CHAR訊息。