和上一篇創(chuàng)建框架窗口相比,創(chuàng)建控件的工作要輕松很多,信不信由你。在對話框模板中定義的每一個控件,其對應的子窗口將會被創(chuàng)建??丶拇笮『臀恢迷谀0逯惺且訢LU為單位來描述的,所以,理所當然的,我們需要將它們轉換為以像素單位,代碼如下:int x = XDLU2Pix(ItemTemplate.x);int y = YDLU2Pix(ItemTemplate.y);int cx = XDLU2Pix(ItemTemplate.cx);int cy = YDLU2Pix(ItemTemplate.cy);
控件類名和標題也來自于模板。還有一些可選的額外字節(jié)pExtra沒有人使用,但由于歷史原因保留在模板定義中。 一旦收集了這些信息,就該制作”甜甜圈”了。HWND hwndChild = CreateWindowEx(ItemTemplate.dwExStyle | WS_EX_NOPARENTNOTIFY,pszClass, pwzCaption, ItemTemplate.dwStyle,x, y, cx, cy, hdlg, ItemTemplate.dwId,hinst, pExtra);
請注意,對于對話框控件,WS_EX_NOPARENTNOTIFY 樣式是默認啟用的。
下一部分經(jīng)常讓人栽跟頭。 “當我嘗試創(chuàng)建我的對話框時,它失敗了,我不知道為什么?!?這可能是因為無法創(chuàng)建對話框上的某個控件,通常是因為你忘記為該控件注冊窗口類。 (例如,您忘記調(diào)用 InitCommonControlsEx 函數(shù)或忘記 LoadLibrary 適當版本的 RichEdit 控件。)
if (!hwndChild) {DestroyWindow(hdlg);return NULL;}
DS_NOFAILCREATE 樣式禁止了上述失敗檢查。但是,如果確實創(chuàng)建了控件,則需要對其進行初始化。SetWindowContextHelpId(hwndChild, ItemTemplate.dwHelpID);SetWindowFont(hwndChild, hf, FALSE);
對模板中的每個控件重復上面的步驟后,你現(xiàn)在擁有一個包含所有子控件的對話框。 告訴對話過程它可以初始化它的子窗口,如果我們在構建框架時延遲了 WS_VISIBLE 位,則顯示(現(xiàn)在準備好的)對話框,并將對話框返回給我們的調(diào)用者,此時對話框已準備就緒了。// The default focus is the first item that is a valid tab-stop.
HWND hwndDefaultFocus = GetNextDlgTabItem(hdlg, NULL, FALSE);if (SendMessage(hdlg, WM_INITDIALOG, hwndDefaultFocus, lParam)) {SetDialogFocus(hwndDefaultFocus);}if (fWasVisible) ShowWindow(hdlg);return hdlg;}
關于SetDialogFocus,我們之前講過。
至此,你應該明白了對話框是如何創(chuàng)建了。
(實際上,現(xiàn)實情況要復雜得多,因為我跳過了所有應用程序兼容性技巧!例如,有一個程序依賴于細節(jié)的設置和WS_BORDER樣式的缺失來決定控件是組合框還是列表框 . 我猜GetClassName函數(shù)工作量太大了?)
我希望這可以幫助你更好地理解對話模板是如何工作的。
總結
描述性語言,是程序開發(fā)者和操作系統(tǒng)之間的一種十分友好的溝通方式。就好比COM時代的IDL(接口描述語言)。
最后
Raymond Chen的《The Old New Thing》是我非常喜歡的博客之一,里面有很多關于Windows的小知識,對于廣大Windows平臺開發(fā)者來說,確實十分有幫助。本文來自:《The dialog manager, part 3: Creating the controls》