再談“VC++5.0下實現多視”
發表于:2007-07-14來源:作者:點擊數:
標簽:
浙江鄞縣鐘公廟鎮長豐二村 王磊 ---- 《計算機世界》前幾期介紹了兩種實現多視的方法。前者,作者利用MDI方法來實現,編程比較復雜;而后者作者使用CSpillterWnd類來實現多視。 ---- 事實上,MFC在CDocument類中已經為我們封裝了實現多視的直接方法,如果查
浙江鄞縣鐘公廟鎮長豐二村 王磊
---- 《計算機世界》前幾期介紹了兩種實現多視的方法。前者,作者利用MDI方法來實現,編程比較復雜;而后者作者使用CSpillterWnd類來實現多視。
---- 事實上,MFC在CDocument類中已經為我們封裝了實現多視的直接方法,如果查閱一下聯機文檔,可以發現,CDocument中有AddView 和RemoveView兩個成員函數,恰恰是這兩個函數,為我們實現多視提供了便捷。
---- 下面是關于CDocument::AddView和CDocument::RemoveView的簡單介紹,具體請參見聯機文檔:
void CDocument::AddView( CView* pView );
---- 為當前CDocument類實例加入新的視圖。其中參數pView是指向新視圖的指針。
Void CDocument::RemoveView ( CView* pView );
---- 從當前的CDocument類實例中移去一個視圖。其中參數pView是指向要移去的視圖的指針,注意必須在該視圖不可見的情況下才能移去,否則會產生異常。
---- 通過這兩個函數,我們可以方便的實現增加和移去視圖。
---- 下面是實現的一個實例:
---- 本實例實現一文檔兩視圖的功能。視圖一由CView派生,用來顯示文檔中的數據,而視圖二由CEditView派生,用來對文檔中的數據進行編輯。用“查看”菜單中的視圖一、視圖二來選擇視圖。關于如何實現加入新的視圖類和菜單請參考其他資料。
---- 下面為主窗口類添加數據成員和消息處理函數:
CDemoView *m_pView1;
//指向視圖一的指針,CDemoView由應用向導生成
CMyEditView *m_pView2;
//指向視圖二的指針,CMyEditView派生于CEditView
int m_nWhichView;
//指示當前為哪一個視圖,并初始化為0
---- 以下是菜單選擇視圖二的處理函數:
void CMainFrame::OnView2()
{
// TODO: Add your command handler code here
if(m_pView2==NULL)
{
//取得視圖一的指針
m_pView1 = (CDemoView *)GetActiveView();
//生成視圖二實例對象
m_pView2 = new CMyEditView;
//取得活動文檔的指針
CDemoDoc *pDoc = (CDemoDoc*)GetActiveDocument();
//為視圖二實例對象創建窗口,
具體參數請參見聯機文檔的CWin::Create
m_pView2->Create(NULL,NULL,AFX_WS_DEFAULT_VIEW,
rectDefault,this,AFX_IDW_PANE_FIRST+1,NULL);
//下面置換視圖一和視圖二的ID號
//使得主窗口可以正確的使當前視圖占據整個客戶區
int nId = m_pView2- >GetDlgCtrlID();
m_pView2- >SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_pView1- >SetDlgCtrlID(nId);
//顯示視圖二,隱藏視圖一
m_pView2- >ShowWindow(SW_SHOW);
m_pView1- >ShowWindow(SW_HIDE);
//添加新視圖
pDoc- >AddView(m_pView2);
//設置視圖二位活動視圖
SetActiveView(m_pView2);
m_pView2- >SetWindowText(pDoc- >m_Hello);
RecalcLayout();
}
else
if(m_nWhichView==0)
{ //同上,僅僅省略視圖二的創建工作
int nId = m_pView2- >GetDlgCtrlID();
m_pView2- >SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_pView1- >SetDlgCtrlID(nId);
m_pView1- >ShowWindow(SW_HIDE);
m_pView2- >ShowWindow(SW_SHOW);
SetActiveView(m_pView2);
RecalcLayout();
}
m_nWhichView=1;
}
---- 以下是菜單選擇視圖一的處理函數:
if(m_nWhichView==1)
{
//原理同上
int nId = m_pView1- >GetDlgCtrlID();
m_pView1- >SetDlgCtrlID(AFX_IDW_PANE_FIRST);
m_pView2- >SetDlgCtrlID(nId);
m_pView2- >ShowWindow(SW_HIDE);
m_pView1- >ShowWindow(SW_SHOW);
SetActiveView(m_pView1);
RecalcLayout();
m_nWhichView = 0;
}
---- 然后為文檔類CDemoDoc 添加成員數據 CString m_Hello,用于視圖一的顯示數據和視圖二的編輯數據。
---- 最后分別加入視圖一和視圖二的處理函數。
---- 在視圖一中加入OnDraw處理函數用于顯示數據,如下:
void CDemoView::OnDraw(CDC* pDC)
{
CDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
RECT rect;
GetClientRect(&rect);
pDC->SetTextColor(RGB(0,128,128));
pDC->DrawText(pDoc- >m_Hello,pDoc- >
m_Hello.GetLength(),&rect,DT_WORDBREAK);
}
---- 在視圖二中加入用于相應數據改變的處理函數:
void CMyEditView::OnChange()
{
// TODO: If this is a RICHEDIT control,
the control will not
// send this notification unless you override
the CEditView::OnInitDialog()
// function to send the EM_SETEVENTMASK
message to the control
// with the ENM_CHANGE flag
ORed into the lParam mask.
// TODO: Add your control
notification handler code here
//僅將數據保存到文檔
CDemoDoc *pDoc = (CDemoDoc *)GetDocument();
GetWindowText(pDoc- >m_Hello);
}
---- 注意:編譯前在MainFrm.cpp中加入DemoView.h 和MyEditView.h 和 DemoDoc.h三個頭文件。于是大功告成,可以進行編譯
測試了。
---- 總結:使用MDI和CSplitter來實現多視,無非是隱含的使用AddView來實現一文檔多視,而這里,筆者直接使用了AddView來實現多視。當然,朋友們可能會問,上面這個演示程序,為什么只能在各個視圖中切換,而不能同時將其顯示在主窗口的客戶區。其實,同時顯示在客戶區是可能的,筆者經過多次試驗,發現兩個視圖完全可以顯示在同一主窗口的客戶區內,不過視圖類窗口不是普通的窗口,沒有標題、系統控制菜單和放大縮小按鈕,因此它缺少一些普通窗口的屬性,如不采用特殊手段不能用鼠標拖動和進行放大縮小操作。當然這可以通過一些API函數來實現,但這可能會太過麻煩。
---- 細心的朋友可能會注意到MDI的每一個視圖其實是被放置在CMDIChildWnd 類派生的主幀窗口的客戶區,由此來獲得普通窗口的各種特性,使得各個視圖窗口在同一主窗口下共存,這也是用MDI實現一文檔多視的方法。不過,我們完全可以變通一下,自己建立主幀窗口,并在建立視圖時將其父窗口指針指向該主幀窗口,從而獲得同用MDI實現多視相同的效果,不過這可能會略顯復雜。而分隔器窗口也僅僅為顯示視圖窗口以及為各個視圖窗口的重新定位提供了機制,我們也可以不用分隔器窗口而通過重載主窗口的RecalcLayout來實現視圖窗口的重新定位,限于篇幅,這里不再作介紹。有興趣的朋友可以研究一下CMDIChildWnd和CsplitterWnd實現的MFC源程序。
原文轉自:http://www.anti-gravitydesign.com