Windows API入门系列之六 -自己实现MessageBox
我在第四篇文章:一個相當簡單的SDK程序?中講到了通過調用MessageBoxAPI函數來彈出一個對話框,那你有沒有想過,我們一句簡單的代碼背后所隱藏的細節是怎么的呢,那時候讓你了解這些未免還早了些,不過現在時機到了,通過一些基本的API函數調用來實現一個自己的對話框其實也不是很難,那么這一篇文章就是這個目的。并順帶介紹一些基本API的應用,由于前面五篇文章的鋪墊,我相信你對SDK的程序的大致結構和相關字符處理都有所了解了,所以在這篇文章中的這些知識點,我就不再多說,以免有些人覺得我實在太過啰嗦。實在疑惑的,可以參看前面的文章。
首先我先大概的列出我們為完成這個任務所要用到的一些API函數他
SetWindowText????設置窗口的標題
GetClientRect?得到窗口客戶區的大小信息
GetWindowLongPtr?通過窗口句柄得到和窗口的相關聯信息
CreateWindowEx?創建窗口
BeginPaint?得到窗口的設備句柄
EndPaint?釋放窗口的設備句柄
DrawText?通過設備句柄在窗口上畫出文字
好了,就這些函數,我們就能自己實現有一個確定按鈕并在確定按鈕正上方顯示提示信息的簡易的對話框了,不過這個對話框可是我們一句一句代碼自己實現的喲~~還是比較有成就感吧~
程序的大體框架呢還是我們上一篇文章中的框架,注冊窗口類,創建一個主窗口,消息循環,窗口消息處理函數。不過要我們需要在窗口消息處理函數中添加一些代碼來完成我們需要的功能。在什么地方添加呢???上個程序,我們只處理WM_DESTROY這個消息。對于這個消息我不再做講解,不懂的或者忘記了的可以自己MSDN或者看上一篇文章,這里我們要添加對兩個消息的處理代碼,首先是WM_CREATE,這個消息會在一個窗口被創建的時候被發送到窗口消息處理函數,如果一些事情需要在一個窗口剛被創建的時候執行,那么通過處理WM_CREATE最合適不過啦,代碼如下:
case?WM_CREATE:
{
RECT?rctClient;?//用來存放主窗口客戶區大小信息
const?int?buttonWidth?=?80;?//按鈕的寬
const?int?buttonHeight?=?25;?/按鈕的高
GetClientRect(?hwnd,?&rctClient?);?//得到主窗口客戶區的大小信息
HINSTANCE?hInst?=?(HINSTANCE)GetWindowLongPtr(?hwnd,?GWLP_HINSTANCE?);
HWND?hButton?=?CreateWindowEx(?0L,?_T("button"),?_T("確定"),?WS_VISIBLE?|??WS_CHILD?,?rctClient.right/2-buttonWidth/2,?rctClient.bottom/2-buttonHeight/2,?buttonWidth,??buttonHeight,?hwnd,?(HMENU)2,?hInst,?NULL?);
SetWindowText(?hwnd,?_T("自定義對話框")?);
break;
}
在WM_CREATE消息的處理中,我們就用到了GetClientRect,它的第一個參數是窗口的句柄,你想要獲取哪個窗口的客戶區大小,你就將傳遞哪個窗口的句柄,第二個參數是一個RECT結構的指針,我上面定義了一個rctClient變量,然后這里把這個變量的地址傳遞給GetClientRect的第二個參數,讓它將所得到的窗口的大小信息保存到這個變量里面。這個函數的具體用法,讀者朋友們還可以自己參考MSDN,如果函數調用成功,那么rctClient這個結構體變量中就存放了這個窗口的大小信息了。
然后,我定義了兩個整形常量buttonWidth,?buttonHeight用來保存我們需要創建的按鈕的寬和高。
再然后我調用GetWindowLongPtr這個函數獲取和窗口有關的信息,這里獲取的是窗口所屬的應用程序實例的句柄,也就是WinMain函數所傳遞進來的第一個參數。在得到這些需要的信息之后,我們就開始著手子窗體的創建了,這里我們要創建的是一個按鈕,按鈕也是一個窗體,所以也需要窗口類,我們并沒有寫按鈕的窗口類進行注冊,那么這個窗口類由誰來注冊呢??其實是有系統創建并注冊了按鈕的窗口類,窗口類的名字是button,所以我們這里只管用這個窗口類來創建窗口就是了,我們創建主窗口是用的WS_OVERLAPPEDWINDOW這個窗口樣式,如果是創建一個子窗口,那么我們需要指定WS_CHILD?,如果我們需要創建的窗口能顯示出來,那么需要指定WS_VISIBLE這個窗口樣式,并且還需要指定創建的窗口所屬的父窗口的句柄,如上代碼所示。其中第五個參數到第八個參數是該按鈕的坐標位置和寬度高度的信息,因為我們需要將該按鈕創建在主窗口的中央,所以有一系列的計算,具體是怎么計算的,就請各位自己仔細根據上面的代碼進行思考了,如果還是有些疑惑,請與我討論或者加入SDK編程(81543028)群進行討論交流。
創建完了按鈕子窗口,我們還需要將我們的主窗口的標題設置為我們想要的,可以通過SetWindowText這個API函數來完成,第一個參數就是要設置的窗口的句柄,這里為主窗口,所以是我們窗口消息處理函數傳遞進來的第一個參數hwnd,?第二個參數就是一個字符串指針,指向一個以零結尾的字符串。這里我們就直接將一個字符串常量的首地址傳遞給它。就完成了主窗口的標題設置。
經過上面這些步驟,我們已經在主窗體的中央顯示了一個按鈕了,并且把主窗口的標題設置為我們自己需要的,但是還要一個問題需要解決,那就是在按鈕的正上方顯示一串提示文本,怎么來完成呢,這就是我們下面要講的。
要在主窗口的按鈕的正上方顯示提示文本信息,就需要得到主窗口的設備句柄,然后通過該設備句柄調用GDI函數DrawText來完成。由于該提示文本需要在每次窗口進行更新的時候繪出,所以我們需要處理WM_PAINT消息來達到這個目的。下面還是先看代碼:
case?WM_PAINT:
{
const?int?buttonWidth?=?80;
const?int?buttonHeight?=?25;
const?int?textHeight?=?25;
PAINTSTRUCT?ps;
HDC?hdc?=?BeginPaint(?hwnd,?&ps?);
RECT?rctClient,rctText;
GetClientRect(?hwnd,?&rctClient?);
rctText.left?=?rctClient.left;
rctText.right?=?rctClient.right;
rctText.top?=?rctClient.bottom/2?-?buttonHeight?-textHeight;
rctText.bottom?=?rctClient.bottom/2?-?buttonHeight;
DrawText(?hdc,?_T("Beyondcode"),?_tcslen(?_T("Beyondcode")),?&rctText,?DT_CENTER??|?DT_SINGLELINE?|?DT_VCENTER?);
EndPaint(?hwnd,?&ps?);
break;
}
首先定義了三個整形常量?buttonWidth,buttonHeight指示剛才創建的按鈕的大小,textHeight指示要顯示在文本的矩形框的高度,矩形框的寬度和主窗口的寬度一直,所以就沒定義了,然后PAINTSTRUCT?是BeginPaint和EndPaint這兩個函數會用到的一個結構體類型,用它定義了一個結構體變量ps,并在調用BeginPaint和EndPaint的時候將它的地址傳遞給他們的第二個參數。獲取一些相關和繪圖有關的信息。不過我們這里不會用到,所以就不做詳細解釋,可以查看MSDN。
注意,BeginPatin這個函數會返回一個設備句柄,然后我們就可以通過這個設備句柄進行繪圖,顯示文字也是一種繪圖,在繪圖完畢后,我們需要調用EndPaint這個函數釋放剛才得到的哪個設備句柄,也就是是剛才哪個設備句柄無效。而所有的繪圖操作,都必須在BeginPaint和EndPatin這兩個函數之間完成。如上面,通過參數hdc調用DrawText這個函數,因為獲取的hdc是通過hwnd這個窗口句柄的,所以這里所有的繪圖都會顯示在hwnd這個句柄所代表的窗口上,也就是主窗口。rctText是顯示文本的矩形的信息,它的大小和位置是通過按鈕的大小和當前主窗口的大小信息計算出來的,具體的計算代碼中已經寫的很清楚了,如有疑惑的可以和我交流交流。?然后還要說的一個就是DT_CENTER?和DT_VCENTER這兩個標志表示在剛才那個矩形框中的水平中央和垂直中央顯示我們的文本,DT_SINGLELINE就是指示單行顯示。
最后留給大家一個問題,以供大家思考,上面的程序中,當你改變窗口的大小的時候,就會出現問題,按鈕就不會再位于主窗口的中央了,怎么解決呢??我提示一下吧,處理WM_SIZE這個消息。好了,留下這個任務給大家,試試吧~~讓按鈕隨時隨地位于主窗口的中央。
更詳細的注釋的完整源代碼我會上傳群空間供各位下載。
Ok,這章就到這里,由于這些天有些忙,沒來得及及時更新,所以多多抱歉了。SDK編程群(81543028)歡迎各位的加入。
總結
以上是生活随笔為你收集整理的Windows API入门系列之六 -自己实现MessageBox的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows API入门系列之五 -一
- 下一篇: Windows API入门系列之七 -完