第一講 用Create()方法建立一個表單應用程式
一般來講,大多數Windows應用程式的介面都是由一個或數個表單構成。
而VC++中提供了豐富的類庫,用於建立Windows表單應用程式。
我們一般可以通過CFreameWnd類中的Create()方法來建立一個表單,Create()
函數的定義如下:
BOOL Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle = WS_OVERLAPPEDWINDOW,
const RECT& rect = rectDefault,
CWnd* pParentWnd = NULL, // != NULL for popups
LPCTSTR lpszMenuName = NULL,
DWORD dwExStyle = 0,
CCreateContext* pContext = NULL);
這是一個虛函數①,第一個參數lpszClassName是一個表單類名字串的指標
(一個WNDCLASS②結構體)。此類名可以是任意的由全域函數AfxRegisterWndClass
註冊過的預定義控制項類名。如果為空白,則使用CWnd類的預設屬性。第二個參數
lpszWindowName是作為表單標題的字串指標。
第三個參數dwStyle是宏定義的表單類型,具體定義如下:
WS_BORDER 建立一個有邊框的表單。
WS_CAPTION 建立一個有標題列的表單(隱含了WS_BORDER). 不能和WS_DLGFRAME
一起使用.
WS_CHILD 建立一個子表單。不能和WS_POPUP一起使用。
WS_CLIPCHILDREN 不包括在父表單中被子表單佔用的地區。用於建立父表單。
WS_CLIPSIBLINGS 使子表單彼此別住;就是當一個指定的子表單接收到一個
paint訊息時,WS_CLIPSIBLINGS類型將別住所有重疊的子窗
體超過地區的部分一起更新,(如果沒有使用WS_CLIPSIBLINGS
並且子表單重疊,當你在一個子表單的客戶區繪圖時,可能
會繪圖到鄰近的子表單的客戶區。)只與WS_CHILD一起使用。
WS_DISABLED 建立一個初始停用表單。
WS_DLGFRAME 建立一個有雙邊但無標題的表單。
WS_GROUP 指定一個使用者可以用方向鍵從一個控制項移到另一個控制項的控
件組的第一個控制項。All controls defined with the WS_GROUP
style FALSE after the first control belong to the same
group. The next control with the WS_GROUP style starts
the next group (that is, one group ends where the next
begins).
WS_HSCROLL 建立一個帶水平捲軸的表單。
WS_MAXIMIZE 建立一個最大尺寸的表單。
WS_MAXIMIZEBOX 建立一個有最大化按扭的表單。
WS_MINIMIZE 建立一個初始最小化的表單。只與WS_OVERLAPPED一起使用。
WS_MINIMIZEBOX 建立一個有最小化按扭的表單。
WS_OVERLAPPED 建立一個重疊表單。一個重疊表單一般有標題和邊框。
WS_OVERLAPPEDWINDOW 建立一個和WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU,
WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX一
使用的重疊表單。
WS_POPUP 建立一個彈出式表單。不能和WS_CHILD一起使用。
WS_POPUPWINDOW 建立一個和WS_BORDER, WS_POPUP, and WS_SYSMENU一起使
用的彈出式表單。WS_CAPTION必須和WS_POPUPWINDOW組合使
用才能讓控制項菜單可見。
WS_SYSMENU 建立一個在標題列有控制項菜單框的表單。只能和有標題列的
表單一起使用。
WS_TABSTOP 指定任意數量控制項中的一個可以由使用者使用TAB鍵移動到的
控制項。TAB鍵使使用者移動到由WS_TABSTOP指定的下一個控制項。
WS_THICKFRAME 建立一個有厚邊框的Window,使其可以改變大小。
WS_VISIBLE 建立一個初始可見的表單。
WS_VSCROLL 建立一個有垂直捲軸的表單。
由於上表中常量可以進行組合,用按位或運算,所以常量名的值被定義為類似於
0x00C00000L的32位16進位數型式。例如進行WS_SYSMENU|WS_MINIMIZEBOX運算時即
0x00080000L|0x00020000L。數字前面的0x是16位元的標識符,L表示32位,上式的演
算式可表示如下:
=
00000000000010000000000000000000
(|) 00000000000000100000000000000000
------------------------------------------
00000000000010100000000000000000 = 0X000A0000L = 655360;
當你用十進位數655360替代WS_SYSMENU|WS_MINIMIZEBOX作為實參時,你會看到相
同的結果。
第四個參數rect是一個RECT結構體的對象,用於指定表單的尺寸和位置。RECT結
構體的定義如下:
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;
我們可以利用從tagRECT結構體派生出的CRect類的建構函式來初始化一個RECT結構
體。CRect的一個重載建構函式定義如下:
// from left, top, right, and bottom
CRect(int l, int t, int r, int b);
第五個參數pParentWnd用於指定父表單,這是一個指向CWnd類對象的指標。第六
個參數nID用於指定作為子表單的表單ID。最後一個參數是關於建立內容的指標,已
被預設為NULL,不用理會。
注釋:
① 虛函數的作用:如果沒有把需要在衍生類別中重載的同名
基類函數定義為虛函數,則當用基類定義的指標指向衍生類別對象的地址時(賦
值相容規則),通過此指標調用的該同名函數是在基類中定義的;反之如果定
義的虛函數,則通過指標調用的該同名函數是在指標指向的對象中定義的。
第二講 Create()方法的應用
下面是一個用CFrameWnd類的Create()函數建立一個表單的例子:
/////////////////////////////////////////////
#include <afxwin.h>
class CMyWnd:public CFrameWnd
{
public:
CMyWnd()
{
Create(AfxRegisterWndClass(CS_DBLCLKS,0,HBRUSH(COLOR_WINDOWFRAME),AfxGetApp()->LoadStandardIcon(IDI_APPLICATION)),__T("Creamdog"),WS_SYSMENU,CRect(100, 100, 500, 500),this,NULL);
ShowWindow(SW_SHOWNORMAL);
};
};
class CMyApp:public CWinApp
{
public:
virtual BOOL InitInstance()
{
m_pMainWnd=new CMyWnd;
return TRUE;
};
};
CMyApp myApp;
/////////////////////////////////////////
首先從其類CFrame中派生出CMyWnd類,並定義建構函式,用於產生一個新表單。
在建構函式中是使用Creat()函數建立表單的,其中系統全域函數AfxRegisterWndClass()
用於註冊一個表單類,該函數的具體定義如下:
LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle, HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0);
第一個參數nClassStyle指定了表單類的類型,如果為NULL則所有參數都使用
預設值。具體預設值為:
nClassStyle=CS_DBLCLKS;//響應雙擊事件
hCursor=IDC_ARROW;//標準箭頭
hbrBackground=Null;//不更新背景
hIcon=IDI_APPLICATION;//Windows徽標(在WinXP中為小視窗)
由於用預設值時表單不會更新,一般函數的四個參數需要人為指定,第一個參數
設為為CS_DBLCLKS即可。CS_DBLCLKS是表單類型的一個宏定義,下表列出了所有表單
類型的宏定義。
CS_BYTEALIGNCLIENT 在位元組邊界(在X方向)上對齊表單的客戶區。此類型將影
響到在表單顯示時它的寬度和它的水平位置。
CS_BYTEALIGNWINDOW 在位元組邊界(在X方向)上對齊表單。此類型將影響到在窗
體顯示時它的寬度和它的水平位置。
CS_CLASSDC 分配一個裝置環境並被類中的所有表單共用。由於表單類
被處理特化,它是可以適用於一個應用程式的若干線程創
建一個相同類的表單。它同樣適用於多個線程試圖同時使
用相同的裝置環境。當此種情況發生時,系統只允許一個
線程去成功的它的繪圖操作。
CS_DBLCLKS 當指標在屬於此類的表單內部,並且使用者雙擊滑鼠時,將
會發送一個雙擊訊息到表單程式。
CS_GLOBALCLASS 指定此表單類是一個應用程式全域類。應用程式全域類是
由一個在進程中對所有模組有效exe或ddl註冊的一個窗
體類。
CS_HREDRAW 如果表單被移動或尺寸調整器改變了客戶區的大小,重繪
全部的表單。
CS_NOCLOSE 關閉按扭不可用。
CS_OWNDC 為此類中的每一個表單分配唯一的裝置環境。
CS_PARENTDC 設定子表單中剪下的矩形到父表單中,以使子窗全可以在父
表單上繪圖。一個具有CS_PARENTDC屬性控制的表單從裝置
環境的系統緩衝中接收到一個規則的裝置環境。它不把父窗
體的裝置環境或裝置環境設定給予子表單。指定CS_PARENTDC
以提高應用程式的效能。
CS_SAVEBITS 儲存被此類的一個表單摭住的螢幕圖象的一部分為位元影像。當
表單被移動,系統使用儲存過的位元影像去恢複螢幕圖象,包括
其它被摭住的表單。因此如果被位元影像使用記憶體沒有被釋放,
並且其它的螢幕動作沒有使儲存的映像無效。系統不會發送
WM_PAINT訊息到被摭蓋的表單。
這種類型對在其它螢幕動作發生時被暫時顯示小表單(如菜
單或對話方塊)很有用。這種類型增加了顯示表單所需的時間,
因為系統必須先分配記憶體去儲存位元影像。
CS_VREDRAW 如果表單被移動或尺寸調整器改變了客戶區的高度,重繪
全部的表單。
上表中的宏定義值是類似於0x0080的16位16進位數,因此它們之間可以用按位
或 | 符號進行組合,原理前面以經介紹過了。
第二個參數hCursor為滑鼠指標的控制代碼,但由於在表單開啟事件發生時,游標就
會被重繪為箭頭,因此在註冊表單類時對此進行設定意義不大,設為0即可。如果需
要定義游標,首先應關閉數標重繪,方法是:重載表單類基類的OnSetCursor()函數,
讓其返回TRUE值,這樣當重繪時調用OnSetCursor()函就不起作用了。可以用下面的
語句進行設定。
SetCursor(AfxGetMainWnd()->LoadStandardCursor(IDC_IBEAM));
其中::SetCursor()是全域函數,用來設定整個常式的游標參數是宏定義游標句
柄。AfxGetMainWnd()是一個系統函數,它返回當前主表單的控制代碼。而CWinApp的
LoadStandardCursor()成員函數用來讀取一個系統指標,每一種系統指標的具體宏
定義如下:
IDC_APPSTARTING 帶小沙漏的標準箭頭
IDC_ARROW 標準箭頭
IDC_CROSS 十字游標(用於定位)
IDC_HAND Windows 2000:手型
IDC_HELP 帶問號的箭頭
IDC_IBEAM I型標
IDC_ICON Obsolete for applications marked version 4.0 or later.
IDC_NO 禁止符號
IDC_SIZE Obsolete for applications marked version 4.0 or later. Use IDC_SIZEALL.
IDC_SIZEALL 十字箭頭
IDC_SIZENESW 指向東北和西南的雙向箭頭
IDC_SIZENS 指向南和北的雙向箭頭
IDC_SIZENWSE 指向西北和東南的雙向箭頭
IDC_SIZEWE 指向東西的雙向箭頭
IDC_UPARROW 上箭頭
IDC_WAIT 沙漏
上表中宏定義值為類似於MAKEINTRESOURCE(32649)的函數,MAKEINTRESOURCE()的
定義如下:
#define MAKEINTRESOURCEW(i) (LPWSTR)((DWORD)((WORD)(i))) //UNICODE
#define MAKEINTRESOURCE MAKEINTRESOURCEW
將其還原為容易理解的C代碼:
char *(unsigned long(unsigned short(32649))
至於為什麼系統要將其倒來倒去,是為了在重載函數中和一般的整形實參相區
別(本人估計)。另外,如果想要使用自訂表徵圖或指標檔案,則牽扯到執行個體資源
分配的問題,將在以後進行說明。
第三個參數hbrBackground,指定表單背景的筆刷資源,應該指定一個,否則
背景將不會更新。此參數可使用系統色彩,定義如下:
COLOR_SCROLLBAR 0
COLOR_BACKGROUND 1
COLOR_ACTIVECAPTION 2
COLOR_INACTIVECAPTION 3
COLOR_MENU 4
COLOR_WINDOW 5
COLOR_WINDOWFRAME 6
COLOR_MENUTEXT 7
COLOR_WINDOWTEXT 8
COLOR_CAPTIONTEXT 9
COLOR_ACTIVEBORDER 10
COLOR_INACTIVEBORDER 11
COLOR_APPWORKSPACE 12
COLOR_HIGHLIGHT 13
COLOR_HIGHLIGHTTEXT 14
COLOR_BTNFACE 15
COLOR_BTNSHADOW 16
COLOR_GRAYTEXT 17
COLOR_BTNTEXT 18
COLOR_INACTIVECAPTIONTEXT 19
COLOR_BTNHIGHLIGHT 20
第四個參數為程式表徵圖的標識符,為0時是預設的Windows徽標。與游標同樣,
需要自訂表徵圖時,添加設定表徵圖的語句,例如:
AfxGetMainWnd()->SetIcon(AfxGetApp()->LoadStandardIcon(IDI_EXCLAMATION),FALSE);
與設定游標不同的是,設定游標的函數是全域函數,而設定表徵圖的函數是
CWinApp類的成員函數(因為表徵圖只在表單內有效),故在函數調用之前需要用系
統函數AfxGetMainWnd()來擷取當前主表單的控制代碼,再用CWinApp的LoadStandardIcon()
成員函數來讀取系統表徵圖並返回一個表徵圖的控制代碼,最後CFrameWnd類的SetIcon()
成員函數將表單的表徵圖設定為剛才返回的表徵圖控制代碼。
回到剛才的Create()語句,第一個參數用的是剛才註冊的類名。第二個參數中
用到了強制類型轉換(__T),這個資料類型不對字串做任何的改變,只是起到規
範化編程的做用。第三個參數是前面提過的表單類型,WS_SYSMENU是使表單具有最
大化、最小化、關閉三個按扭。第四個參數使表單在所給出的位置和尺寸上開啟。
第五個參數this的意義是此表單為父表單。第六個參數表示無子表單。
ShowWindow()故名思意,即顯示表單。其參數nCmdShow是確定表單被怎樣顯示。
它必須是下面宏定義中的一個:
SW_HIDE 0 隱藏此表單並啟用其它表單。
SW_MAXIMIZE 3 啟用並顯示此表單為最大化。
SW_MINIMIZE 6 最小化指定的表單並啟用下一個在Z順序中位
於頂層的表單。
SW_RESTORE 9 啟用並顯示此表單。如果此表單已被最大化或
最小化,系統將恢複此表單至原尺寸和原位置。
一個應用程式應該在恢複一個最小化表單時指
定這個標記。
SW_SHOW 5 在當前尺寸和位置上啟用並顯示此表單。
SW_SHOWMAXIMIZED 3 同SW_MAXIMIZE
SW_SHOWMINIMIZED 2 啟用並顯示此表單為最小化。
SW_SHOWMINNOACTIVE 7 顯示此表單為最小化。這個值類似於SW_SHOWMINIMIZED,
除非表單未被啟用。
SW_SHOWNA 8 在最近一次的尺寸和位置顯示此表單,這個值
類似於SW_SHOWNORMAL,除非表單未被啟用。
SW_SHOWNOACTIVATE 4 在當前的尺寸和位置顯示此表單。這個值類似於SW_SHOW,
除非表單未被啟用。
SW_SHOWNORMAL 1 啟用並顯示一個表單。如果此表單已被最大化
或最小化,系統將恢複此表單至原尺寸和原位置。
一個應用程式應該在第一次開啟這個表單時指定
這個標記。
有關表單架構的定義就結束了,下面是由CWinApp基類派生出的類CMyApp,在
類定義中對基類中的虛成員函數InitInstance()進行了重載,關於虛函數的有關概
念前面以經提過了。在開始說明此函數內部的語句時首先需要對CWinApp的資料成員
m_pMainWnd進行說明。
m_pMainWnd資料成員被用於儲存一個指向你的線程中主表單對向的指標。當涉
及到m_pMainWnd的表單被關閉時,MFC庫將自動的終止你的線程。如果此線程為你的
應用程式中的主線程,應用程式也將同樣被終止。如果此資料成員為NULL,當終止
此線程時,為了應用程式的CWinApp對象的主表單也將常常被終止。m_pMainWnd是
CWnd類指標的一個公有變數。
一般來講,當你重載InitInstance()函數時設定此變數。在一個背景工作執行緒中,
此資料成員的值是從它的父線程中繼承來的。
正如上面所說,例子中在重載InitInstance()函數時對此變數進行了賦值,讓
它指向一個新的架構表單類對象,而這個對象是由剛才定義的衍生類別CMyWnd執行個體化
出來的。下來返回一個真值,表示初始化執行個體成功。
最後,用CMyApp類執行個體化出一個對象,名子隨意。系統將對前面定義的類和函
進行構造,這樣就完成了一個簡單表單的建立。