?? 03.3.2 在窗口中顯示按鈕(1).txt
字號:
3.3.2 在窗口中顯示按鈕
為了更好地理解窗口類、窗口類對象和窗口之間的關(guān)系,我們接下來實(shí)現(xiàn)在窗口中顯示一個按鈕這一功能,仍在已有的Test程序中實(shí)現(xiàn)。首先需要創(chuàng)建一個按鈕類對象,按鈕對應(yīng)的MFC類是CButton類,其繼承層次結(jié)構(gòu)如圖3.24所示,從而可以得知CButton類派生于CWnd類。
圖3.24 CButton類的繼承層次結(jié)構(gòu)
在MFC提供的資源類中,有些類的對象的構(gòu)造(包括對象構(gòu)造與初始化)直接通過其構(gòu)造函數(shù)就可以完成。也就是說,這些對象的構(gòu)造函數(shù)包含這個對象的初始化操作。但有些對象的產(chǎn)生除了調(diào)用構(gòu)造函數(shù)外,還需要調(diào)用其他一些函數(shù)來進(jìn)行初始化的工作,然后才能使用該對象。
對于一個CButton對象,在定義之后就可以使用了。但是作為一個窗口類對象,即CWnd對象,如果在構(gòu)造之后還需要產(chǎn)生這個窗口的話,還需要調(diào)用CreateEx函數(shù)來完成初始化工作。也就是說,如果要顯示一個按鈕的話,在定義這個CButton類對象之后,即調(diào)用CButton類的構(gòu)造函數(shù)之后,還需要調(diào)用CButton的Create函數(shù)創(chuàng)建這個按鈕窗口,從而把按鈕窗口與CButton對象關(guān)聯(lián)起來。
CButton的Create函數(shù)聲明如下。
BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
各個參數(shù)的意義如下所述。
n lpszCaption
指定按鈕控件的文本。
n dwStyle
指定按鈕控件的風(fēng)格。按鈕控件不僅具有按鈕風(fēng)格類型,還具有窗口風(fēng)格類型。多種風(fēng)格類型可以通過位或操作加以組合。
n rect
指定按鈕控件的大小和位置。該參數(shù)是RECT結(jié)構(gòu)體類型,通過指定左上角和右下角兩個點(diǎn)的坐標(biāo)定義一個矩形。結(jié)構(gòu)體也是一種特殊的類,所以可以用類CRect來構(gòu)造一個RECT結(jié)構(gòu)體。
n pParentWnd
指定按鈕控件的父窗口。這是一個CWnd類型的指針。MFC中不再通過窗口句柄,而是通過一個與窗口相關(guān)的C++窗口類對象指針來傳遞窗口對象。
n nID
指定按鈕控件的標(biāo)識。
為了在框架窗口上產(chǎn)生一個按鈕控件,顯然應(yīng)該是在框架窗口產(chǎn)生之后,再創(chuàng)建該按鈕控件,否則沒有地方放置它。窗口創(chuàng)建時都會產(chǎn)生WM_CREATE消息,CMainFrame類提供一個OnCreate函數(shù),該函數(shù)就是用來響應(yīng)這條窗口創(chuàng)建消息的。該函數(shù)的默認(rèn)實(shí)現(xiàn)代碼如例3-22所示。
例3-22
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
從例3-22所示代碼可知,CMainFrame類的OnCreate函數(shù)首先調(diào)用基類CFrameWnd的OnCreate函數(shù),創(chuàng)建一個窗口,然后創(chuàng)建工具條(m_wndToolBar)和狀態(tài)欄(m_ wndStatusBar)對象。我們可以在該函數(shù)的最后完成按鈕的創(chuàng)建工作,即在return語句之前添加例3-23所示代碼中加灰顯示的代碼。
例3-23
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
CButton btn;
btn.Create("按鈕",WS_CHILD | BS_DEFPUSHBUTTON,CRect(0,0,100,100),this, 123);
return 0;
}
其中,將該按鈕的名稱設(shè)置為“按鈕”,其位置由CRect(0,0,100,100)這一矩形確定,ID號為123。前面已經(jīng)講過,按鈕控件不僅具有按鈕風(fēng)格類型,還具有窗口風(fēng)格類型,因此,在按鈕的Create函數(shù)中指定該按鈕具有WS_CHILD窗口風(fēng)格類型,同時還具有BS_DEFPUSHBUTTON按鈕風(fēng)格類型,即下按按鈕風(fēng)格。
另外,我們知道每個對象都有一個this指針,代表對象本身。為了使按鈕控件的父窗口就是框架窗口,這里可以直接將代表CMainFrame對象的this指針作為參數(shù)傳遞給按鈕的Create函數(shù)。
編譯并運(yùn)行Test程序,但發(fā)現(xiàn)按鈕并沒有顯示出來。問題的原因有兩個:一是這里定義的btn對象是個局部對象,當(dāng)執(zhí)行到OnCreate函數(shù)的右大括號(})時,該對象的生命周期就結(jié)束了,就會發(fā)生析構(gòu)。前面已經(jīng)講過,如果一個窗口與一個C++窗口類對象相關(guān)聯(lián),當(dāng)這個C++對象生命周期結(jié)束時,該對象在析構(gòu)時通常會把與之相關(guān)聯(lián)的窗口資源進(jìn)行回收。這就是說,當(dāng)執(zhí)行到例3-22所示的OnCreate函數(shù)的右大括號時,剛剛創(chuàng)建的btn窗口就被與之相關(guān)的C++對象銷毀了。因此,不能將這個按鈕對象定義為一個局部對象。解決方法是:將其定義為CMainFrame類的一個成員變量,可以將其訪問權(quán)限定義為private類型以實(shí)現(xiàn)信息隱藏。
有多種方法可以定義一個類的成員變量,可以直接在該類的定義中添加成員變量定義代碼,也可以利用VC++提供的工具來定義。后者的方法是:在ClassView標(biāo)簽頁中的類名上單擊鼠標(biāo)右鍵,從彈出的快捷菜單上選擇【Add member variable…】菜單命令,將彈出Add Member Variable對話框。通常,在定義類的成員變量名稱時都以“m_”為前綴,表明這個變量是類的一個成員變量。在添加成員變量對話框的Variable Type(變量類型)文本框中輸入變量類型CButton,Variable Name(變量名稱)文本框中輸入按鈕對象名稱m_btn,并為其選擇private類型的訪問權(quán)限,如圖3.25所示。
圖3.25 Add Member Variable對話框
然后單擊對話框上的【OK】按鈕,即可以在CMainFrame類的頭文件中看到新成員變量的定義,代碼如下:
private:
CButton m_btn;
修改例3-23所示CMainFrame類OnCreate函數(shù)中創(chuàng)建按鈕的代碼,刪除局部按鈕對象的定義,并將按鈕創(chuàng)建函數(shù)的對象名稱改為m_btn,結(jié)果如例3-24所示。
例3-24
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
m_btn.Create("按鈕",WS_CHILD | BS_DEFPUSHBUTTON,CRect(0,0,100,100), this,123);
return 0;
}
再次運(yùn)行Test程序,將會發(fā)現(xiàn)按鈕還沒有出現(xiàn)。這一問題的第二個原因就是在一個窗口創(chuàng)建完成之后,應(yīng)該將這個窗口顯示出來。因此,需要在調(diào)用Create函數(shù)之后再添加一條窗口顯示代碼,如例3-25所示。
例3-25
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
1. m_btn.Create("按鈕",WS_CHILD | BS_DEFPUSHBUTTON,CRect(0,0,100,100), this,123);
2. m_btn.ShowWindow(SW_SHOWNORMAL);
return 0;
}
再次運(yùn)行Test程序,這時就可以看到按鈕出現(xiàn)了,如圖3.26所示。
圖3.26 在框架窗口中顯示按鈕
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -