-
CView
鎖定
CView是視圖程序設計中使用率最高的窗口對象,它是用户的主要操作界面。因為它通常以某種形式表示文檔數據,所以稱之為視圖。一個視圖對象只關聯一個文檔對象;一個文檔對象可以關聯多個視圖,每個視圖對象以不同形式表示文檔數據。
- 中文名
- CView
- 關聯對象
- WM_CREATE
- 保 存
- 文檔類將修改後保存到磁盤文件
- 接 受
- 用户對文檔中數據的編輯和修改
CView基本介紹
從文檔類中將文檔中的數據取出後顯示給用户;接受用户對文檔中數據的編輯和修改;將修改的結果反饋給文檔類,由文檔類將修改後的內容保存到磁盤文件中。
文檔負責了數據真正在永久介質中的存儲和讀取工作,視圖呈現只是將文檔中的數據以某種形式向用户呈現,因此一個文檔可對應多個視圖。
Invalidate(TRUE)將整個窗口設置為需要重繪的無效區域,它會產生WM_PAINT消息,這樣OnDraw將被調用。
假如文檔中的數據發生了變化,必須通知所有鏈接到該文檔的視圖,這時候文檔類的UpdateAllView函數需要被調用。
然而,除了打印和打印預覽外,視圖類顯示得很簡單。
CView關聯對象
前面已經提到,視圖需要表示文檔數據,所以文檔對象與視圖對象必須建立關聯。這樣,當文檔數據發生變化時,它可以及時通知視圖;當視圖需要顯示不同的文檔數據時,它可以從文檔對象中提取。
在文檔/視圖框架程序中,文檔對象總是在視圖之前建立,而在視圖的WM_CREATE消息處理函數中,建立了它與文檔對象的關聯。代碼如下:
IntCView:: OnCreate(LPCREATESTRUCTlpcs) { if( CWnd::OnCreate(lpcs)==-1) return-1; //m_pDocuemnt視圖成員,用於存儲相應文檔對象的指針,此時為空 ASSERT(m_pDocument==NULL); CCreateContext*pContext=(CCreateContext*)lpcs->lpCreateParams; //pContext->m_pCurrentDoc是已經建立的文檔對象的指針 if(pContext!=NULL&&pContext->m_pCurrentDoc!=NULL) { //將當前視圖加入文檔對象的視圖列表中,因為一個文檔可關聯多個視圖 pContext->m_pCurrentDoc->AddView(this); /*在文檔的AddView()函數中,已經將當前文檔 對象指針賦給m_pDocument視圖成員。這樣,在視圖建立之初,二者就建立了關聯。*/ ASSERT(m_pDocument!=NULL); } else { TRACE(“Warning:CreatingapanewithnoCDocument.\n”); } return0;//ok }
同時,視圖類定義了成員函數GetDocument( ),返回文檔對象的指針。代碼如下:
CDocument*CView::GetDocument() const { ASSERT(this!=NULL); returnm_pDocument; }
視圖總是在文檔對象之前銷燬,在視圖的析構函數中,與文檔對象解除關聯。代碼如下:
CView::~CView() { if(m_pDocument!=NULL) m_pDocument-> RemoveView(this); }
CView視圖繪製
窗口的繪製工作總是在WM_PAINT消息處理中進行的,當窗口需要繪製時,它會收到系統發來的WM_PAINT消息。在繪製過程中,首先要準備顯示設備句柄,最後要釋放句柄。眾所周知,在視圖窗口中繪製,無需重載WM_PAINT消息處理函數OnPaint( ),因為有一個更加友好的繪製新口:OnDraw( )。該函數的實參是一個已經準備好的顯示設備,最後無需釋放。其實,這一切還是WM_PAINT消息處理函數OnPaint( )為我們準備的,代碼如下:
voidCView::OnPaint() { // CPaintDC類維護顯示設備 CPaintDCdc(this); OnPrepareDC(&dc); OnDraw(&dc); }
OnPrepareDC( )是一個虛擬函數,它總是在OnDraw( )之前執行,可以重載它,設置繪圖模式。因為OnDraw( )每次執行,都使用不同的CPaintDC對象,所以本次繪圖模式的狀態不能保留到下一次。
virtualvoidOnDraw( CDC* pDC)=0;
CView虛函數
OnUpdate
當文檔數據發生變化時,文檔對象調用CDocument::UpdateAllView( )通知所有視圖,作為響應,視圖的OnUpdate( )成員被調用。所以,重載的OnUpdate( )應該能夠根據需要,將文檔數據的變化反映在視圖中。CView::OnUpdate( )只是簡單地使客户區無效,導致客户區重畫。例如:
voidCView::OnUpdate(CView*pSender, LPARAM, CObject*) { ASSERT(pSender!=this); UNUSED(pSender);//unusedinreleasebuilds Invalidate(TRUE); }
OnInitialUpdate( )
在初始創建、調用OnCreate( )之後,或者在File/New、File/Open命令後被框架調用。基類CView::OnInitialUpdate( )只是簡單地調用OnUpdate( ),可以重載它完成初始化工作。但注意,它可能被多次調用。
voidCView::OnInitialUpdate() { OnUpdate(NULL,0,NULL); } CalcWindowRect
每當主框架窗口的客户區尺寸發生變化或控制條的位置發生變化,需要重新排列客户區時,調用該函數,根據視圖客户區尺寸計算視圖窗口的尺寸。
我們知道,排列主窗口客户區是由CFrameWnd::RecalcLayout( )完成的。顯然,視圖的CalcWindowRect( )函數也是由它觸發調用的。主窗口的客户區尺寸減掉所有控制佔用的部分,剩下的區域分給視圖,這部分區域作為實參傳入CalcWindowRect( )。在CalcWindowRect( )函數內,需要計算視圖窗口的尺寸。代碼如下:
voidCView::CalcWindowRect(LPRECTlpClientRect,UNITnAdjustType) { //lpClientRect此時是整個視圖客户區的尺寸 //需要為 滾動條增加尺寸嗎 if(nAdjustType!=0) { //調用API,根據窗口風格計算窗口尺寸 :: AdjustWindowRectEx(lpClientRect,0,FALSE,GetExStyle()); DWORDdwStyle= GetStyle(); if(dwStyle&WS_VSCROLL) { //為垂直滾動條增加尺寸 //afxData在.NET下需要#include<../../src/mfc/afximpl.h> //afxData在VC6.0下需要#include<../src/mfc/afximpl.h> intnAdjust=afxData.cxVScroll; if(dwStyle&WS_BORDER) nAdjust-=CX_BORDER; lpClientRect->right+=nAdjust; } if(dwStyle&WS_HSCROLL) { //為水平滾動條增加尺寸 intnAdjust=afxData.cyHScroll; if(dwStyle&WS_BORDER) nAdjust-=CY_BORDER; lpClientRect-> bottom+=nAdjust; } return; } //無需為 滾動條增加尺寸,調用 基類成員完成計算 CWnd:: CalcWindowRect(lpClientRect,nAdjustType); }
PostNcDestroy
在視圖窗口關閉時最後調用的成員函數,它與CFrameWnd::PostNcDestroy完成相同的功能,即刪除視圖對象。代碼如下:
voidCView::PostNcDestroy() { deletethis; }
這樣,可以不必關心視圖的釋放工作,即使它在堆中構造。
OnCmdMsg
在討論CFrameWnd::OnCmdMsg( )時已經瞭解過該函數,下面只給出它的代碼:
BOOLCView::OnCmdMsg(UINTnID,intnCode, void*pExtra,AFX_CMDHANDLERINFO*pHandlerInfo) { //首先查找自身的命令消息映射 if( CWnd::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo)) returnTRUE; //如果視圖本身沒有處理該命令,將機會留給與其關聯的文檔對象 if(m_pDocument!=NULL) { CPushRoutingViewpush(this); returnm_pDocument->OnCmdMsg(nID,nCode,pExtra,pHandlerInfo); } returnFALSE; }
OnActivateView
當視圖被激活為活動視圖,或由活動轉為非活動時,調用該函數通知視圖。基類的實現只是設置該視圖為焦點。代碼如下:
voidCView::OnActivateView(BOOLbActivate,CView*pActivateView,CView*) { UNUSED(pActivateView);//unusedinreleasebuilds if(bActivate)//當前狀態為活動嗎 { ASSERT(pActivateView==this); //如果其父窗口也是活動的,則設置焦點。(在 MDI中,其父框架可能是非活動的) if(IsTopParentActive()) SetFocus(); } }
CView派生類
MFC提供了豐富的CView派生類,各種不同的派生類實現了對不同種類控件的支持,以為用户提供多元化的顯示界面。
CScrollView:提供滾動支持; CCtrlView:支持tree、list和 richedit控件; CDaoRecordView:在dialog-box控件中顯示數據庫記錄; CEditView:提供了一個簡單的多行文本編輯器視圖; CFormView:包含dialog-box控件,可滾動,基於對話框模板資源; CListView:支持列表控件視圖; CRecordView:在dialog-box控件中顯示數據庫記錄; CRichEditView:支持富文本編輯的控件視圖; CTreeView:支持重點在樹控件的文檔/視圖結構的視圖。
- 詞條統計
-
- 瀏覽次數:次
- 編輯次數:18次歷史版本
- 最近更新: 亡命听