引言
通常情況下,利用vc為應用程式建立對話方塊需要使用對話方塊模板資源。通過vc++整合式開發環境中的對話方塊編輯器以可視化的方式建立對話方塊資源,這種方法可以應用於大多數對話方塊編程的情況下。但涉及對話方塊的程式模組必然依賴於開發項目資源,不能作為多個開發項目共用的公用程式模組。比如,筆者開發的一系列應用程式,都需要一個使用者輸入註冊資訊的功能。通常情況下,可以將公用程式模組引入不同的開發項目,而實際程式檔案只有唯一的備份。這樣便於程式的維護,避免公用模組存在多個不一致拷貝的情況。但如果在公用程式模組中存在使用者介面,則不能簡單引入不同開發項目(因為不同項目都有各自的資源,其資源定義不免存在衝突)。另外如果開發過程中需要使用大量的對話方塊,這些對話方塊內容相似,但又略有不同,用對話方塊模板資源,也顯得較為煩瑣。本文介紹了在Visualc++中不使用常規的對話方塊資源模板的情況下,動態建立對話方塊的方法。
1、基本原理
如何不使用對話方塊模板資源,建立對話方塊應用,正是本文探討的問題。如果仔細閱讀MSDN中有關CDialog的內容會發現
CDialogCreateIndriect和
CDialogInitModalIndirect兩個成員函數。正是這兩個成員函數可以利用記憶體中的對話方塊資源建立對話方塊。
CDialogCreateIndriect用於建立無強制回應對話方塊,
CDialogInitModalIndirect可以建立模式對話方塊。
這兩個成員函數都包含參數
LPCDLGTEMPLATElpDialogTemplate,它指向包含對話方塊和控制項資源的記憶體位置。該段記憶體的具體內容包括兩部分:
1.1對話方塊資源
最開始為DLGTEMPLATE結構,指出對話方塊視窗的位置、大小和風格,緊接其後的是指向菜單資源的數組(前兩個位元組為0x0000表示沒有菜單),
接下來的UniCode字串數組表示控制項對應的註冊類名(前兩個位元組為0x0000表示使用預設的預定義類),然後是UniCode字串數組表示的對話方塊標題,雙位元組的字型長度和字型名。
1.2對話方塊控制項資源
緊跟對話方塊資源之後的是一個或多個對話方塊控制項資源,每個控制項資源最開始為DLGITEMTEMPLATE結構,指出控制項視窗的位置、大小和風格,然後是控制項對應的的註冊類名,(如果前兩個位元組為0xFFFF表示使用預定義類),此時後兩個位元組指出具體類見表1,然後是控制項標題(如果前兩個位元組為0xFFFF表示將使用ICON資源),接下來的資料用於建立控制項時使用,由系統發送WM_CREATE訊息時,被lParam參數引用,可以用0x0000表示省略該部分資料。
0x0080 |
Button |
0x0081 |
Edit |
0x0082 |
Static |
0x0083 |
List box |
0x0084 |
Scroll bar |
0x0085 |
Combo box |
表1
其中DLGTEMPLATE結構為
typedefstruct//dltt
DWORDstyle
DWORDdwExtendedStyle
WORD cdit
shortx
shorty
shortcx
shortcy
DLGTEMPLATE
style和dwExtendedStyle為對話方塊的風格,cdit表示對話方塊包含的控制項個數,x,y,cx,cy表示視窗的大小。DLGITEMTEMPLATE結構與此類似,僅多了一項標識id。
通過上面的描述,可以知道只須自行申請記憶體空間,按要求在記憶體中定義對話方塊和控制項的資源,就可以不再依賴項目資源。實際編程中,因為在對話方塊類中定義和建立控制項比較容易,因此往往可以僅定義記憶體對話方塊資源而省略控制項資源部分,通過常規方法動態建立就可以了。
2、實現方法與步驟
下面結合一個進度顯示對話方塊執行個體介紹具體實現的步驟:
首先從CDialog中派生一個類CMemoryDialog,作為所有無模板對話方塊的基類。選擇菜單Insert->NewClass彈出New Class對話方塊,在Name項鍵入CMemoryDialog,BaseClass項選擇
CDialog,按確定按鈕。ClassWizard提示使用者首先建立對話方塊模板資源,對此不與理會,繼續建立。在建立成功的.
h檔案中找到enum IDD = _UNKNOWN_RESOURCE_ID_ ,表示未知的資源ID將這行代碼刪除。
定義成員變數:
CStringm_StrTitle//對話方塊標題
DLGTEMPLATEm_dlgTempl//記憶體對話方塊模板
定義成員函數:
intDoModalMemoryDialog//用於建立模式對話方塊
voidCreateMemoryDialog//用於建立無強制回應對話方塊
其中DoModalMemoryDialog的代碼清單如下:
intCMemoryDialogDoModalMemoryDialog
intr
WCHAR szFontName = L″ARIAL″ //字型名
WCHAR pszBoxCaption //標題
int nLenTitle=m_StrTitle.GetLength+1
pszBoxCaption = new WCHARnLenTitle
//將標題轉換為Unicode字串
MultiByteToWideCharCP_ACP0m_StrTitle-1 pszBoxCaptionnLenTitle
TRY
//分配儲存資源的記憶體
intnBufferSize=
sizeofDLGTEMPLATE+2 sizeofWORD/menu and class/ + nLenTitlesizeofWCHAR
nBufferSize+=sizeofWORD+sizeofszFontName/fontinformation/ +
nBufferSize=nBufferSize+2&2//adjustsize to make first control DWORD aligned
HLOCALhLocal
hLocal = LocalAllocLHND nBufferSize
if hLocal == NULL
AfxThrowMemoryException
BYTE pBuffer=BYTELocalLockhLocal
if pBuffer == NULL
LocalFreehLocal
AfxThrowMemoryException
BYTE pdest=pBuffer
// 拷貝DLGTEMPLATE 結構
memcpypdest &m_dlgTempl sizeofDLGTEMPLATE
pdest+=sizeofDLGTEMPLATE
WORDpdest=0//表示沒有菜單
WORDpdest+1=0//使用預設類
pdest+=2sizeofWORD
//拷貝標題字串
memcpypdestpszBoxCaptionnLenTitlesizeofWCHAR
pdest+=nLenTitlesizeofWCHAR
WORDpdest=11//字型名的長度
pdest+=sizeofWORD
//拷貝字型名字串
memcpypdestszFontNamesizeofszFontName
pdest+=sizeofszFontName
delete pszBoxCaption
//建立模式對話方塊
InitModalIndirectDLGTEMPLATEpBuffer
r=DoModal
LocalUnlockhLocal
LocalFreehLocal
CATCHCMemoryExceptione
AfxMessageBox″Memory allocation failed″
END_CATCH
return r
CreateMemoryDialog與此類似,只需將
InitModalIndirectDLGTEMPLATEpBuffer
r=DoModal
兩行替換為
CreateIndirectDLGTEMPLATEpBuffer
ShowWindowSW_SHOW
並且去掉傳回值。
然後從CMemoryDialog再次派生新類CCustomProgressDialog。在.h檔案中加入成員CProgressCtrlm_ProCtrl,並覆蓋基類的OnInitDialog成員函數。在OnInitDialog中動態建立CProgressCtrl對象。
這樣一個簡單的進度顯示對話方塊就建立好了,使用者可以根據需要派生更多的對話方塊類,也可隨時添加更多的控制項對象。
3、結論
通過上述進度顯示對話方塊的實現步驟,可以看到建立無模板資源對話方塊的實現方法。使用者可以根據需要派生更多的對話方塊類,也可隨時添加更多的控制項對象。而且這些模組都與資源無關,可以同時被多個開發項目包含,維護起來十分方便。