標(biāo)準(zhǔn)的Windows窗口是矩形的,但在有些時候我們需要非矩形的窗口,比如圓形的、甚至是不規(guī)則的。借助CWnd類的SetWindowRgn函數(shù)可以創(chuàng)建不規(guī)則形狀窗口。
CWnd::SetWindowRgn的函數(shù)原型如下:
int SetWindowRgn( HRGN hRgn, // 窗口區(qū)域句柄
BOOL bRedraw ); // 是否重畫窗口
CRgn類封裝了關(guān)于區(qū)域的數(shù)據(jù)和操作。通過(HRGN)強(qiáng)制操作可以從CRgn類中取得其HRGN值。
CRgn提供了CreateRectRgn、CreateEllipticRgn和CreatePolygonRgn成員函數(shù),分別用以創(chuàng)建矩形、(橢)圓形和多邊形區(qū)域。
創(chuàng)建非矩形窗口的方法如下:
首先,在窗口類中定義區(qū)域類成員數(shù)據(jù)(如CRgn m_rgnWnd);
其次,在窗口的OnCreate函數(shù)或?qū)υ捒虻腛nInitDialog函數(shù)中調(diào)用CRgn類的CreateRectRgn、CreateEllipticRgn或CreatePolygonRgn函數(shù)創(chuàng)建所需的區(qū)域,并調(diào)用SetWindowRgn函數(shù)。
下例將生成一個橢圓窗口。
1. 在Developer Studio中選取File菜單中的New命令,在出現(xiàn)的New對話框中選擇創(chuàng)建MFC AppWizard(exe)框架應(yīng)用程序,并輸入項目名為EllipseWnd。設(shè)定應(yīng)用程序類型為基于對話框(Dialog based),其它選項按缺省值創(chuàng)建項目源文件。
2. 使用資源編輯器從主對話框(ID為IDD_ELLIPSEWND_DIALOG)刪除其中的所有控制,并從其屬性對話框(Dialog Properties)中設(shè)定其風(fēng)格為Popup、無標(biāo)題條和邊框。
3. 在EllipseWndDlg.h源文件中給主對話框類CEllipseWndDlg增加一個CRgn類保護(hù)型數(shù)據(jù)成員m_rgnWnd,它將定義窗口的區(qū)域。
4. 在EllipseWndDlg.cpp源文件中修改主對話框類CEllipseWndDlg的OnInitDialog()函數(shù),增加m_rgnWnd的創(chuàng)建,并將其定義為窗口區(qū)域。粗體語句為新增部分。
BOOL CEllipseWndDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX,
strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application’s main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// 設(shè)置窗口標(biāo)題為“橢圓窗口”,雖然對話框沒有標(biāo)題條,
// 但在任務(wù)條的按鈕中仍需要標(biāo)題
SetWindowText(_T("橢圓窗口"));
// 取得屏幕寬、高
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN);
// 設(shè)置橢圓X、Y方向的半徑
int nEllipseWidth = cxScreen/8;
int nEllipseHeight = cyScreen/8;
// 將窗口大小設(shè)為寬nEllipseWidth,高nEllipseHeight
// 并移至左上角
MoveWindow(0, 0, nEllipseWidth, nEllipseHeight);
// 創(chuàng)建橢圓區(qū)域m_rgnWnd
m_rgnWnd.CreateEllipticRgn(0, 0, nEllipseWidth, nEllipseHeight);
// 將m_rgnWnd設(shè)置為窗口區(qū)域
SetWindowRgn((HRGN)m_rgnWnd, TRUE);
return TRUE; // return TRUE unless you set the focus to a control
}
如何在多文檔界面下去掉開始的子窗口
在多文檔界面下,自動生成一個新的子窗口,而一個實際的應(yīng)用系統(tǒng)往往是由用戶操作后再生成新的窗口。為了去掉開始的子窗口,可在應(yīng)用程序文件分析命令行的語句CcommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
后加入:
cmdInfo.m-nShellCommand=CcommandLineInfo::FileNothing;
去掉子窗口后,就只剩下主框架窗口了。因為在多文檔界面中,系統(tǒng)生成兩個菜單:一個是用戶的菜單,另一個是系統(tǒng)主框架菜單。通常用戶工作在用戶菜單。為了保證菜單界面不變,可修改主框架菜單資源,使其與用戶菜單保持一致。
修改窗口標(biāo)題欄
在缺省情況下,窗口標(biāo)題欄中顯示的文檔名為文件名。若要在標(biāo)題欄顯示一個長字符串,而又不修改文件名,則可將項目工作區(qū)轉(zhuǎn)換到Resource View面版,選擇串表(StringTable)資源,在StringTable中雙擊IDR-MAIN-FRAME項,caption中顯示一字符串xx\n\yy......,將第一個參數(shù)修改為用戶自己希望見到的主窗口標(biāo)題即可。
修改主框架窗口、子窗口及其顯示性質(zhì)
可通過覆蓋CWnd的成員函數(shù)PreCreateWindow來修改主窗口和子窗口。PreCreateWindow函數(shù)在即將創(chuàng)建窗口前被調(diào)用,函數(shù)原型為:Virtual BOOL PreCreateWindow函數(shù)(CREATESTRUCT cs)。如果要覆蓋PreCreateWindow函數(shù),則在創(chuàng)建窗口前可以修改CREATESTRUCT結(jié)構(gòu)以替換缺省參數(shù)。CREATESTRUCT結(jié)構(gòu)存放窗口特征,如窗口坐標(biāo)、風(fēng)格等,還可以定義新窗口風(fēng)格?! ∪粝胄薷闹骺蚣艽翱?,則可以在MainFrm.cpp的下列成員函數(shù)中加入待修改的內(nèi)容。例如:
BOOL CmainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
//通過修改CREATESTRUCT結(jié)構(gòu)來修改窗口類或風(fēng)格
//定義新窗口的高度、寬度
cs.cx=450;
cs.cy=300;
//定義新窗口風(fēng)格為去掉主窗口名及化等按鈕
cs.style=ws-POPWINDO;
return CframeWnd::PreCreateWindow(cs);
}
定制子窗口的操作與上述主窗口相同,可在ChildFrm.cpp中加入以下內(nèi)容:
BOOL CmainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
//通過修改CREATESTRUCT結(jié)構(gòu)來修改窗口類或風(fēng)格
return C mdichildWnd::PreCreateWindow(cs);
}
要修改視圖窗口的顯示性質(zhì),則可在視圖文件xxView.cpp的下述成員函數(shù)中加入以下語句:
BOOL xxView::PreCreateWindow(CREATESTRUCT&cs)
{
//增加的語句
cs.lpszClass=AfxRegisterWndClass(cs-HREDRAW|CS-VREDRAW,0,(HBRUSH))::GetStockObject(WHITE-BRUSH),0);
return CscrollView::PreCreateWindow(cs);
}
其中,cs的參數(shù)pszClass用于存放Windows窗口類名稱。要想注冊Windows窗口類,則必須調(diào)用全局函數(shù)AfxRegisterWndClass。該函數(shù)原型為:
LPCTSTR AFXAPI AfxRegisterWndClass(UINTnClassStyle,HCURSOR hCursor=0,HBRUSH hbrBackground=0,HICON hIcon=0)
上述各參數(shù)用于定義風(fēng)格,其含義分別為光標(biāo)資源句柄、背景資源句柄、圖標(biāo)資源句柄。上述增加的語句的作用是:改變窗口大小時重畫窗口、不顯示光標(biāo)圖標(biāo)、設(shè)置白色背景。
窗口的滾動
使用CscrollView代替Cview類即可實現(xiàn)滾動窗口。此時,系統(tǒng)生成OnInitialUpdate()成員函數(shù):
void CmyscrollView::OnInitialUpdat()
{
CscrollView::OnIntialUpdate();
Csize sizeTotal;
SizeTotal.cs=sizeToal.cy=100;
SetScrollSizes(MM-TEXT,sizeTotal);
}
其中,cs和cy分別為滾動窗口的水平、垂直分量,表明窗口的水平、垂直方向尺寸小于100像素單位時將出現(xiàn)水平方向滾動條和垂直方向滾動條。通過修改滾動尺寸,可改變出現(xiàn)滾動條的最小窗口。例如,若“sizeTotal.cx=600;sizeTotal.cy=800;”,則當(dāng)窗口尺寸小于600*800時,就會出現(xiàn)滾動條。
窗口分割
該功能可將窗口分割成多個可滾動的面板,面板之間的邊界稱為分割條,可用分割條來調(diào)整每個面板的相對大小。要想增加窗口分割功能,則必須修改主窗口類。首先,在主窗口類的頭文件MainFrm.h中添加以下代碼:
CsplitterWnd m-SWnd;
Virtual BOOL OnCreateClient (LPCREATESTRUCTcs,CcreateContext *pContext);
再在MainFrm.cpp中添加成員函數(shù)OnCreateClient的定義:
BOOL CmainFrame::OnCreateCline(LPCREATESTRUCTcs,CcreateContext *p Context)
{
return m-SWnd.Creat(this,2,2,Csize(20,20),pContext);
}
新的CsplitterWnd類對象m-SWnd用于創(chuàng)建和管理分割窗口,該窗口中可以包含一個或多個面板。首次創(chuàng)建主窗口時,將調(diào)用成員函數(shù)OnCreateClient。在缺省情況下,該函數(shù)創(chuàng)建一個填充主框窗口客戶區(qū)的視圖窗口。覆蓋該函數(shù)后,將調(diào)用CsplitterWnd的成員函數(shù)Create來創(chuàng)建分割窗口。其中,第一個參數(shù)用于指定分割的父窗口(主窗口);第二個參數(shù)指定垂直方向上的面板個數(shù)為2;第三個參數(shù)指定水平方向上的面板的個數(shù);第四個參數(shù)用于設(shè)置每個面板的最小尺寸;第五個參數(shù)傳遞描述信息。上述分割窗口的每個面板都是由視圖類對象管理的,當(dāng)用戶在某一面板內(nèi)顯示文檔和圖形時,必須在其它面板中重新繪制,從而在多個面板中均顯示相同的內(nèi)容。為此,必須調(diào)用顯示文檔類的UpdateALLView成員函數(shù)來更新其它面板。此時,只需加入pdoc->UpdataALLView(NULL)即可。
CWnd::SetWindowRgn的函數(shù)原型如下:
int SetWindowRgn( HRGN hRgn, // 窗口區(qū)域句柄
BOOL bRedraw ); // 是否重畫窗口
CRgn類封裝了關(guān)于區(qū)域的數(shù)據(jù)和操作。通過(HRGN)強(qiáng)制操作可以從CRgn類中取得其HRGN值。
CRgn提供了CreateRectRgn、CreateEllipticRgn和CreatePolygonRgn成員函數(shù),分別用以創(chuàng)建矩形、(橢)圓形和多邊形區(qū)域。
創(chuàng)建非矩形窗口的方法如下:
首先,在窗口類中定義區(qū)域類成員數(shù)據(jù)(如CRgn m_rgnWnd);
其次,在窗口的OnCreate函數(shù)或?qū)υ捒虻腛nInitDialog函數(shù)中調(diào)用CRgn類的CreateRectRgn、CreateEllipticRgn或CreatePolygonRgn函數(shù)創(chuàng)建所需的區(qū)域,并調(diào)用SetWindowRgn函數(shù)。
下例將生成一個橢圓窗口。
1. 在Developer Studio中選取File菜單中的New命令,在出現(xiàn)的New對話框中選擇創(chuàng)建MFC AppWizard(exe)框架應(yīng)用程序,并輸入項目名為EllipseWnd。設(shè)定應(yīng)用程序類型為基于對話框(Dialog based),其它選項按缺省值創(chuàng)建項目源文件。
2. 使用資源編輯器從主對話框(ID為IDD_ELLIPSEWND_DIALOG)刪除其中的所有控制,并從其屬性對話框(Dialog Properties)中設(shè)定其風(fēng)格為Popup、無標(biāo)題條和邊框。
3. 在EllipseWndDlg.h源文件中給主對話框類CEllipseWndDlg增加一個CRgn類保護(hù)型數(shù)據(jù)成員m_rgnWnd,它將定義窗口的區(qū)域。
4. 在EllipseWndDlg.cpp源文件中修改主對話框類CEllipseWndDlg的OnInitDialog()函數(shù),增加m_rgnWnd的創(chuàng)建,并將其定義為窗口區(qū)域。粗體語句為新增部分。
BOOL CEllipseWndDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX,
strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application’s main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// 設(shè)置窗口標(biāo)題為“橢圓窗口”,雖然對話框沒有標(biāo)題條,
// 但在任務(wù)條的按鈕中仍需要標(biāo)題
SetWindowText(_T("橢圓窗口"));
// 取得屏幕寬、高
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN);
// 設(shè)置橢圓X、Y方向的半徑
int nEllipseWidth = cxScreen/8;
int nEllipseHeight = cyScreen/8;
// 將窗口大小設(shè)為寬nEllipseWidth,高nEllipseHeight
// 并移至左上角
MoveWindow(0, 0, nEllipseWidth, nEllipseHeight);
// 創(chuàng)建橢圓區(qū)域m_rgnWnd
m_rgnWnd.CreateEllipticRgn(0, 0, nEllipseWidth, nEllipseHeight);
// 將m_rgnWnd設(shè)置為窗口區(qū)域
SetWindowRgn((HRGN)m_rgnWnd, TRUE);
return TRUE; // return TRUE unless you set the focus to a control
}
如何在多文檔界面下去掉開始的子窗口
在多文檔界面下,自動生成一個新的子窗口,而一個實際的應(yīng)用系統(tǒng)往往是由用戶操作后再生成新的窗口。為了去掉開始的子窗口,可在應(yīng)用程序文件分析命令行的語句CcommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
后加入:
cmdInfo.m-nShellCommand=CcommandLineInfo::FileNothing;
去掉子窗口后,就只剩下主框架窗口了。因為在多文檔界面中,系統(tǒng)生成兩個菜單:一個是用戶的菜單,另一個是系統(tǒng)主框架菜單。通常用戶工作在用戶菜單。為了保證菜單界面不變,可修改主框架菜單資源,使其與用戶菜單保持一致。
修改窗口標(biāo)題欄
在缺省情況下,窗口標(biāo)題欄中顯示的文檔名為文件名。若要在標(biāo)題欄顯示一個長字符串,而又不修改文件名,則可將項目工作區(qū)轉(zhuǎn)換到Resource View面版,選擇串表(StringTable)資源,在StringTable中雙擊IDR-MAIN-FRAME項,caption中顯示一字符串xx\n\yy......,將第一個參數(shù)修改為用戶自己希望見到的主窗口標(biāo)題即可。
修改主框架窗口、子窗口及其顯示性質(zhì)
可通過覆蓋CWnd的成員函數(shù)PreCreateWindow來修改主窗口和子窗口。PreCreateWindow函數(shù)在即將創(chuàng)建窗口前被調(diào)用,函數(shù)原型為:Virtual BOOL PreCreateWindow函數(shù)(CREATESTRUCT cs)。如果要覆蓋PreCreateWindow函數(shù),則在創(chuàng)建窗口前可以修改CREATESTRUCT結(jié)構(gòu)以替換缺省參數(shù)。CREATESTRUCT結(jié)構(gòu)存放窗口特征,如窗口坐標(biāo)、風(fēng)格等,還可以定義新窗口風(fēng)格?! ∪粝胄薷闹骺蚣艽翱?,則可以在MainFrm.cpp的下列成員函數(shù)中加入待修改的內(nèi)容。例如:
BOOL CmainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
//通過修改CREATESTRUCT結(jié)構(gòu)來修改窗口類或風(fēng)格
//定義新窗口的高度、寬度
cs.cx=450;
cs.cy=300;
//定義新窗口風(fēng)格為去掉主窗口名及化等按鈕
cs.style=ws-POPWINDO;
return CframeWnd::PreCreateWindow(cs);
}
定制子窗口的操作與上述主窗口相同,可在ChildFrm.cpp中加入以下內(nèi)容:
BOOL CmainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
//通過修改CREATESTRUCT結(jié)構(gòu)來修改窗口類或風(fēng)格
return C mdichildWnd::PreCreateWindow(cs);
}
要修改視圖窗口的顯示性質(zhì),則可在視圖文件xxView.cpp的下述成員函數(shù)中加入以下語句:
BOOL xxView::PreCreateWindow(CREATESTRUCT&cs)
{
//增加的語句
cs.lpszClass=AfxRegisterWndClass(cs-HREDRAW|CS-VREDRAW,0,(HBRUSH))::GetStockObject(WHITE-BRUSH),0);
return CscrollView::PreCreateWindow(cs);
}
其中,cs的參數(shù)pszClass用于存放Windows窗口類名稱。要想注冊Windows窗口類,則必須調(diào)用全局函數(shù)AfxRegisterWndClass。該函數(shù)原型為:
LPCTSTR AFXAPI AfxRegisterWndClass(UINTnClassStyle,HCURSOR hCursor=0,HBRUSH hbrBackground=0,HICON hIcon=0)
上述各參數(shù)用于定義風(fēng)格,其含義分別為光標(biāo)資源句柄、背景資源句柄、圖標(biāo)資源句柄。上述增加的語句的作用是:改變窗口大小時重畫窗口、不顯示光標(biāo)圖標(biāo)、設(shè)置白色背景。
窗口的滾動
使用CscrollView代替Cview類即可實現(xiàn)滾動窗口。此時,系統(tǒng)生成OnInitialUpdate()成員函數(shù):
void CmyscrollView::OnInitialUpdat()
{
CscrollView::OnIntialUpdate();
Csize sizeTotal;
SizeTotal.cs=sizeToal.cy=100;
SetScrollSizes(MM-TEXT,sizeTotal);
}
其中,cs和cy分別為滾動窗口的水平、垂直分量,表明窗口的水平、垂直方向尺寸小于100像素單位時將出現(xiàn)水平方向滾動條和垂直方向滾動條。通過修改滾動尺寸,可改變出現(xiàn)滾動條的最小窗口。例如,若“sizeTotal.cx=600;sizeTotal.cy=800;”,則當(dāng)窗口尺寸小于600*800時,就會出現(xiàn)滾動條。
窗口分割
該功能可將窗口分割成多個可滾動的面板,面板之間的邊界稱為分割條,可用分割條來調(diào)整每個面板的相對大小。要想增加窗口分割功能,則必須修改主窗口類。首先,在主窗口類的頭文件MainFrm.h中添加以下代碼:
CsplitterWnd m-SWnd;
Virtual BOOL OnCreateClient (LPCREATESTRUCTcs,CcreateContext *pContext);
再在MainFrm.cpp中添加成員函數(shù)OnCreateClient的定義:
BOOL CmainFrame::OnCreateCline(LPCREATESTRUCTcs,CcreateContext *p Context)
{
return m-SWnd.Creat(this,2,2,Csize(20,20),pContext);
}
新的CsplitterWnd類對象m-SWnd用于創(chuàng)建和管理分割窗口,該窗口中可以包含一個或多個面板。首次創(chuàng)建主窗口時,將調(diào)用成員函數(shù)OnCreateClient。在缺省情況下,該函數(shù)創(chuàng)建一個填充主框窗口客戶區(qū)的視圖窗口。覆蓋該函數(shù)后,將調(diào)用CsplitterWnd的成員函數(shù)Create來創(chuàng)建分割窗口。其中,第一個參數(shù)用于指定分割的父窗口(主窗口);第二個參數(shù)指定垂直方向上的面板個數(shù)為2;第三個參數(shù)指定水平方向上的面板的個數(shù);第四個參數(shù)用于設(shè)置每個面板的最小尺寸;第五個參數(shù)傳遞描述信息。上述分割窗口的每個面板都是由視圖類對象管理的,當(dāng)用戶在某一面板內(nèi)顯示文檔和圖形時,必須在其它面板中重新繪制,從而在多個面板中均顯示相同的內(nèi)容。為此,必須調(diào)用顯示文檔類的UpdateALLView成員函數(shù)來更新其它面板。此時,只需加入pdoc->UpdataALLView(NULL)即可。