各位不好意思,前幾天有些事很忙,昨天才稍稍有時間空閒下來,所以我將我的API入門系列文章繼續下去,上一篇《自己實現MessageBox》中我們基本已經實現了一個對話框了,可以在中央顯示自己的文字,並且顯示一個確定按鈕,可是,上一篇完的時候我留下了一個問題,那就是那個確定按鈕並不會根據窗口的大小的改變而改變。那麼我們怎麼來解決這個問題呢?
我給出了提示可以通過處理WM_SIZE來完成這個目的。那麼今天我們就來完成這一遺留的問題。所要使用到的新的API函數也不多,就兩個,要處理的消息也就兩個WM_SIZE和WM_COMMAND
GetDlgItem
MoveWindow
這麼兩個,至於其他的API函數,都是我們以前接觸過的,如果你忘記了,可以自己復習一下使用方 法。
首先,我們先看WM_SIZE消息處理函數是怎麼寫的
case WM_SIZE:
{
const int buttonWidth = 80;
const int buttonHeight = 25;
int buttonx, buttony;
RECT rctClient;
GetClientRect( hwnd, &rctClient );
buttonx = rctClient.right/2 - buttonWidth/2;
buttony = rctClient.bottom/2 - buttonHeight/2;
HWND hButton = GetDlgItem( hwnd, 2 );
MoveWindow( hButton, buttonx, buttony, buttonWidth, buttonHeight, TRUE );
}
break;
由於這篇文章內容比較少,那麼我就可以詳細的介紹一下WM_SIZE這個消息處理函數中實現按鈕始終 保持居中的代碼。WM_SIZE這個消息是當一個窗口的size也就是大小被改變後而被發送到該窗口的消息處 理函數的。我們在這裡通過截獲WM_SIZE就可以在每次窗口大小被改變的時候進行一些處理,我們這裡的 處理就是將該窗口上的一個子窗口,也就是那個確定按鈕移動到中央。
首先,我們還是老規矩,定義buttonWidth,和buttonHeight兩個常整形來存放確定按鈕的長和高。然 後定義了兩個整形變量buttonx,和buttony用來存放後面通過計算得到的確定按鈕的左上角的坐標位置 。
然後定義了一個RECT結構體用來保存後面通過GetClientRect API函數獲取的窗口的長寬,其中 rctClient中right就保存了窗口的長,bottom就保存了窗口的高。我們為了讓按鈕保持在主窗口的中央 ,那麼我們就需要讓按鈕的左上角的x坐標位置在主窗口的長的一半再減去按鈕的長的一半的位置。高也 是一樣的原理。所以 buttonx = rctClient.right/2 - buttonWidth/2; buttony = rctClient.bottom/2 - buttonHeight/2; 這兩句就是根據當前主窗口的長和高計算按鈕應該在的位 置。
計算完成後,我們就只需要移動按鈕就可以了。可是移動按鈕之前,我們需要獲得按鈕的句柄,這個 句柄怎麼獲得呢,有很多中方法,這裡我就用GeDlgItem這個API函數來獲取,它需要兩個參數,第一個 參數是一個主窗口的句柄,這裡我們就傳遞按鈕的主窗口的句柄hwnd,第二個參數是按鈕的一個標識符 ,因為我們在前一篇文章中用CreateWindowEx創建子窗口的時候給按鈕指定的標識符是2,所以這裡我們 就傳遞2,那麼這樣GetDlgItem返回的就是這個按鈕的句柄了。
得到了句柄後,我們就需要用MoveWindow來移動這個子窗口按鈕,到我們需要的位置了。第一個參數 是這個字窗口的句柄,也就是我們上面獲得的句柄,第二個參數和第三個參數是移動到的x,y坐標。這 裡我們傳遞buttonx和buttony,第四個和第五個是移動的窗口的長和高,如果同時還需要改變窗口的長 和高,那麼這裡也可以傳遞改變後的長和高的值,我們這裡只移動位置,不改變大小,所以就傳遞 buttonWidth和buttonHeight。最後一個參數是一個BOOL型的,指示是否需要重繪,這裡傳遞TRUE,也就 是讓它在移動後進行重繪。
好了,現在,當你改變主窗口的大小的時候,裡面的確定按鈕也會跟著改變位置而達到始終保持在主 窗體的中央。
可是還有一個問題就是,當我們點擊按鈕的時候,程序沒有任何的反映,MessageBox的確定按鈕被點 擊的時候一般都會關閉當前對話框,所以我們這裡也需要實現當用戶點擊確定按鈕的時候,將我們的主 窗體關閉。那麼怎麼來實現呢。
在實現之前,我首先要講一講,子窗體是怎麼通知他們的父窗體的,比如說按鈕被點擊的時候是怎麼 通知他們的父窗體的。其實一般就是通過WM_COMMAND來通知的,例如我點擊這個確定按鈕,那麼在這個 確定按鈕的窗口消息處理函數中就會向它的父窗體的窗口消息處理函數發送一條WM_COMMAND消息,並且 WM_COMMAND消息的wParam參數的低16包含的就是一個標識符,指示是哪個子窗體發送的這條消息。至於 wParam的高16和lParam包含的是些什麼信息,就請各位自己查閱MSDN了,這裡我們不會用到,也就不做 講解了。
所以我們要處理在子窗體上發生的事情,就需要在父窗體的消息處理函數中截獲WM_COMMAND消息,並 進行處理。那麼這裡的WM_COMMAND消息處理也很簡單,如下
case WM_COMMAND:
{
if( LOWORD(wParam)==2 )
{
DestroyWindow( hwnd );
}
}
break;
就是用LOWORD這個宏來取出wParam的低16位,並且判斷是不是2,也就是判斷是不是確定按鈕的標識 符,如果是,就表示確定按鈕上發生了事件,具體的事件我們就沒做過細的判斷了,一般來說都是指被 點擊。所以我們就進行處理,調用DestroyWindow這個API來銷毀主窗體。就達到了我們的目的了。
怎麼樣,比較簡單吧~
經過7篇API入門系列文章的介紹,我想你對WIN32 API編程的一般流程還是有了一個大概的了解了吧 。以及對於windows的數據類型,字符編碼方面。API的使用方面,消息的處理方面,因為都不會陌生了 吧·
所以我後面的文章,對於細節就不會這麼細了,對於一個API函數,如果參數不是很復雜,我也不會 做過多的解釋了。而只是說明一下它的作用。至於細節,各位就應該養成MSDN的習慣了。