摘要:本文通過一個程序實例描述了在VC++6.0下如何在單文檔程序中通過菜單動態控制多個窗體的切換。
一、 引言
我們在編制程序中根據需求的不同會在程序風格上選擇多文檔、單文檔或是對話框模式,對於單文檔模式可能是我們使用比較多的,但有時我們想采用單文檔的形式顯示多個不同的窗體,如作為數據庫前台應用程序就會遇到此類問題,數據庫由大量的表單組成,而同常一個窗體內只用來顯示一個表單,所以要顯示其他的表單時就要用到切換窗體的技術了,下面就通過一個程序說明該技術的實現方法。
二、 實現技術
新建一個基於CFormView的單文檔應用程序,再添加一個窗體和與之對應的基於CFormVIEw的新視類,然後通過在主框架類裡添加控制代碼和菜單控制實現這兩個窗體的動態切換,下面就是具體的實現過程:
(一) 用"MFC AppWizard(exe)"建立一個新項目"SwitchForm",並在第二步的創建類型上選擇為"Single documnet"單文檔模式,第三、四、五、六步均取確省狀態,最後一步選擇"CFormVIEw"作為視類的基類。點按"完成"按鈕,生成了初始工程"SwitchForm"。
(二) 點選菜單"Insert"、"Resource…",在彈出的"Insert Resource"對話框中"Dialog"樹裡的"IDD_FORMVIEW",點擊"New"按鈕,生成了一個新的窗體,將其ID號改為"IDD_NEXTFORM"。在原有的窗體上加一個靜態框"這是第一個窗體";在新建的窗體上也添加一個靜態框"這是第二個窗體"。
(三) 在菜單資源的"IDR_MAINFRAME"上添加一級菜單"窗體切換",及其二級菜單"第一個窗體"、"第二個窗體",其標識號分別為"ID_FIRSTFORM"和"ID_SECONDFORM"。修該"第一個窗體"的屬性為"Checked",表明程序初始時顯示的是第一個窗體。
(四) 在"ClassView"屬性頁裡的"SwitchForm classes"上右鍵,在彈出菜單上選擇"New Class…",彈出"New Class"對話框,選擇"Dialog ID:"為我們剛添加的新窗體"IDD_NEXTFORM",選擇"Base class:"為"CFormView",類名取為"CNextFormVIEw",這樣就把第二個窗體對應的視圖類添加到了工程。
(五) 在框架類裡添加函數SwitchToForm():
void CMainFrame::SwitchToForm(int nForm)
{
file://獲取原來的活動窗體的視圖句柄
CView* pOldActiveView = GetActiveVIEw();
file://獲取由"nForm"標識的窗體所對應的視圖句柄
CView* pNewActiveView = (CVIEw*) GetDlgItem(nForm);
file://若視圖句柄為空,則創建一新的。
if (pNewActiveVIEw == NULL)
{
if (nForm == IDD_SWITCHFORM_FORM)
pNewActiveView = (CView*)new CSwitchFormVIEw;
if (nForm == IDD_NEXTFORM)
pNewActiveView = (CView*)new CNextFormVIEw;
CCreateContext context;
context.m_pCurrentDoc = pOldActiveVIEw->GetDocument();
pNewActiveVIEw->Create(NULL,NULL,0L,
CFrameWnd::rectDefault,
this,nForm,&context);
pNewActiveVIEw->OnInitialUpdate();
}
file://選擇pNewActiveVIEw為活動窗體
SetActiveView(pNewActiveVIEw);
file://顯示活動窗體,隱藏非活動窗體
pNewActiveVIEw->ShowWindow(SW_SHOW);
pOldActiveVIEw->ShowWindow(SW_HIDE);
int ID;
if(pOldActiveView->GetRuntimeClass() == RUNTIME_CLASS(CSwitchFormVIEw))
ID=IDD_SWITCHFORM_FORM;
if(pOldActiveView->GetRuntimeClass() == RUNTIME_CLASS(CNextFormVIEw))
ID=IDD_NEXTFORM;
file://設置窗體的ID號
pOldActiveVIEw->SetDlgCtrlID(ID);
pNewActiveVIEw->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
RecalcLayout();
}
(六)添加兩個菜單相對應的命令響應函數和更新函數如下:
void CMainFrame::OnFirstform()
{
file://通過IsKindOf函數確定當前活動窗口是否是第一個窗口,如是,則無須切換,
file://否則將通過SwitchToForm函數將當前活動窗口切換到"IDD_SWITCHFORM_FORM"
file://標識的第二個窗體。
if (GetActiveView()->IsKindOf(RUNTIME_CLASS(CSwitchFormVIEw)))
return;
SwitchToForm(IDD_SWITCHFORM_FORM);
}
void CMainFrame::OnUpdateFirstform(CCmdUI* pCmdUI)
{
file://通過IsKindOf函數判斷當前活動窗口是否是第一個窗體,如是則將其選中。
pCmdUI->SetCheck(GetActiveView()->IsKindOf(RUNTIME_CLASS(CSwitchFormVIEw)));
}
void CMainFrame::OnSecondform()
{
if (GetActiveView()->IsKindOf(RUNTIME_CLASS(CNextFormVIEw)))
return;
SwitchToForm(IDD_NEXTFORM);
}
void CMainFrame::OnUpdateSecondform(CCmdUI* pCmdUI)
{
pCmdUI->SetCheck(GetActiveView()->IsKindOf(RUNTIME_CLASS(CNextFormVIEw)));
}
然後再在該文件開始處添加對兩個視圖類的引用:
#include "SwitchFormDoc.h"
#include "SwitchFormVIEw.h"
#include "NextFormVIEw.h"
在此須注意:應在兩個視類的引用之前添加對文檔類的引用,否則會引起編譯錯誤。另外,由於視類的構造函數在聲明時都確省的聲明為保護型的,在框架類中無法引用,所以還要將兩個視類的類聲明改動如下:
class CNextFormView : public CFormVIEw
{
public: file://將protected 改為public.
CNextFormVIEw();
……
};
class CSwitchFormView : public CFormVIEw
{
public: file://將protected 改為public.
CSwitchFormVIEw();
……
};
三、 編譯運行
編譯運行程序,開始時的窗體上有"這是第一個窗體的字樣",菜單也只有"第一個窗體"是被選中的,當前的活動窗體是第一個窗體;點擊菜單"第二個窗體",視圖中的窗體上的字樣變成了"這是第二 個窗體",同時選中的菜單也由"第一個窗體"變成了"第二個窗體",實現了通過菜單將窗體進行動態切換。
總結:此程序中關鍵的是SwitchToVIEw函數,在此函數中,程序搜索所有當前文檔的顯示窗口來查找與CruntimeClass變量匹的視圖類。如果找到,該窗口被激活。通過與之類似的方法,還可以實現在多文檔模式下的單檔(文檔)多視(視圖),通過不同的視圖以不同的方式顯示來自同一份文檔的數據,以更好的滿足程序的需要。