cview類是負責每個軟體系統向顯示器輸出各種資訊流以及控制處理的類,但是它不負責物理層的輸出操作,因為windows是一個具有與裝置無關性的作業系統,cview類同過相應一系列傳送給他的一些列訊息,透過自已的一系列函式與之相對映,然後將訊息傳送給專門用來描述輸出裝置的CDC物件來完成顯示資訊的。。。 具體的封裝函式太多了介紹幾個重要的,具體的可以去查msdn。 關聯文件物件 檢視需要表示文件資料,所以文件物件與檢視物件必須建立關聯。這樣,當文件資料發生變化時,它可以及時通知檢視;當檢視需要顯示不同的文件資料時,它可以從文件物件中提取。 在文件/檢視框架程式中,文件物件總是在檢視之前建立,而在檢視的WM_CREATE訊息處理函式中,建立了它與文件物件的關聯。程式碼如下: Int CView::OnCreate (LPCREATESTRUCT lpcs) { 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: Creating a pane with no CDocument.\n”); } return 0; // ok } 同時,檢視類定義了成員函式GetDocument(),返回文件物件的指標。程式碼如下: CDocument* CView::GetDocument() const { ASSERT(this != NULL); return m_pDocument; } 檢視總是在文件物件之前銷燬,在檢視的解構函式中,與文件物件解除關聯。程式碼如下: CView::~CView() { if (m_pDocument != NULL) m_pDocument->RemoveView(this); } 編輯本段檢視的繪製 視窗的繪製工作總是在WM_PAINT訊息處理中進行的,當視窗需要繪製時,它會收到系統發來的WM_PAINT訊息。在繪製過程中,首先要準備顯示裝置控制代碼,最後要釋放控制代碼。眾所周知,在檢視視窗中繪製,無需過載WM_PAINT訊息處理函式OnPaint(),因為有一個更加友好的繪製新口:OnDraw()。該函式的實參是一個已經準備好的顯示裝置,最後無需釋放。其實,這一切還是WM_PAINT訊息處理函式OnPaint()為我們準備的,程式碼如下: void CView::OnPaint() { // CPaintDC類維護顯示裝置 CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc); } OnPrepareDC()是一個虛擬函式,它總是在OnDraw()之前執行,可以過載它,設定繪圖模式。因為OnDraw()每次執行,都使用不同的CPaintDC物件,所以本次繪圖模式的狀態不能保留到下一次。 OnDraw()在檢視基類CView中定義為純虛擬函式。例如: virtual void OnDraw(CDC* pDC) = 0; 所以CView是抽象基類,不能例項化,而派生類必須過載OnDraw()。 編輯本段虛擬函式 OnUpdate 當文件資料發生變化時,文件物件呼叫CDocument::UpdateAllView()通知所有檢視,作為響應,檢視的OnUpdate()成員被呼叫。所以,過載的OnUpdate()應該能夠根據需要,將文件資料的變化反映在檢視中。CView::OnUpdate()只是簡單地使客戶區無效,導致客戶區重畫。例如: void CView::OnUpdate(CView* pSender, LPARAM, CObject*) { ASSERT(pSender != this); UNUSED(pSender); // unused in release builds Invalidate(TRUE); } 編輯本段虛擬函式 OnInitialUpdate() 在初始建立、呼叫OnCreate()之後,或者在File/New、File/Open命令後被框架呼叫。基類CView::OnInitialUpdate()只是簡單地呼叫OnUpdate(),可以過載它完成初始化工作。但注意,它可能被多次呼叫。 void CView::OnInitialUpdate() { OnUpdate(NULL, 0, NULL); } 編輯本段虛擬函式 CalcWindowRect 每當主框架視窗的客戶區尺寸發生變化或控制條的位置發生變化,需要重新排列客戶區時,呼叫該函式,根據檢視客戶區尺寸計算檢視視窗的尺寸。 我們知道,排列主視窗客戶區是由CFrameWnd::RecalcLayout()完成的。顯然,檢視的CalcWindowRect()函式也是由它觸發呼叫的。主視窗的客戶區尺寸減掉所有控制佔用的部分,剩下的區域分給檢視,這部分割槽域作為實參傳入CalcWindowRect()。在CalcWindowRect()函式內,需要計算檢視視窗的尺寸。程式碼如下: void CView::CalcWindowRect(LPRECT lpClientRect, UNIT nAdjustType) { // lpClientRect此時是整個檢視客戶區的尺寸 // 需要為捲軸增加尺寸嗎 if (nAdjustType != 0) { // 呼叫API,根據視窗風格計算視窗尺寸 ::AdjustWindowRectEx(lpClientRect, 0, FALSE, GetExStyle()); DWORD dwStyle = GetStyle(); if (dwStyle & WS_VSCROLL) { // 為垂直捲軸增加尺寸 int nAdjust = afxData.csVScroll; if (dwStyle & WS_BORDER) nAdjust -= CX_BORDER; lpClientRect->right += nAdjust; } if (dwStyle & WS_HSCROLL) { // 為水平捲軸增加尺寸 int nAdjust = afxData.cyHScroll; if (dwStyle & WS_BORDER) nAdjust -= CY_BORDER; lpClientRect->bottom += nAdjust; } return; } // 無需為捲軸增加尺寸,呼叫基類成員完成計算 CWnd::CalcWindowRect(lpClientRect, nAdjustType); } 編輯本段虛擬函式PostNcDestroy 在檢視視窗關閉時最後呼叫的成員函式,它與CFrameWnd::PostNcDestroy完成相同的功能,即刪除檢視物件。程式碼如下: void CView::PostNcDestroy() { delete this; } 這樣,可以不必關心檢視的釋放工作,即使它在堆中構造。 編輯本段虛擬函式OnCmdMsg 在討論CFrameWnd::OnCmdMsg()時已經瞭解過該函式,下面只給出它的程式碼: BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { // 首先查詢自身的命令訊息對映 if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; // 如果檢視本身沒有處理該命令,將機會留給與其關聯的文件物件 if (m_pDocument != NULL) { CPushRoutingView push(this); return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } return FALSE; } 編輯本段虛擬函式 OnActivateView 當檢視被啟用為活動檢視,或由活動轉為非活動時,呼叫該函式通知檢視。基類的實現只是設定該檢視為焦點。程式碼如下: void CView::OnActivateView(BOOL bActivate, CView* pActivateView, CView*) { UNUSED(pActivateView); // unused in release builds if (bActivate) // 當前狀態為活動嗎 { ASSERT(pActivateView == this); // 如果其父視窗也是活動的,則設定焦點。(在MDI中,其父框架可能是非活動的) if (IsTopParentActive()) SetFocus(); } }
cview類是負責每個軟體系統向顯示器輸出各種資訊流以及控制處理的類,但是它不負責物理層的輸出操作,因為windows是一個具有與裝置無關性的作業系統,cview類同過相應一系列傳送給他的一些列訊息,透過自已的一系列函式與之相對映,然後將訊息傳送給專門用來描述輸出裝置的CDC物件來完成顯示資訊的。。。 具體的封裝函式太多了介紹幾個重要的,具體的可以去查msdn。 關聯文件物件 檢視需要表示文件資料,所以文件物件與檢視物件必須建立關聯。這樣,當文件資料發生變化時,它可以及時通知檢視;當檢視需要顯示不同的文件資料時,它可以從文件物件中提取。 在文件/檢視框架程式中,文件物件總是在檢視之前建立,而在檢視的WM_CREATE訊息處理函式中,建立了它與文件物件的關聯。程式碼如下: Int CView::OnCreate (LPCREATESTRUCT lpcs) { 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: Creating a pane with no CDocument.\n”); } return 0; // ok } 同時,檢視類定義了成員函式GetDocument(),返回文件物件的指標。程式碼如下: CDocument* CView::GetDocument() const { ASSERT(this != NULL); return m_pDocument; } 檢視總是在文件物件之前銷燬,在檢視的解構函式中,與文件物件解除關聯。程式碼如下: CView::~CView() { if (m_pDocument != NULL) m_pDocument->RemoveView(this); } 編輯本段檢視的繪製 視窗的繪製工作總是在WM_PAINT訊息處理中進行的,當視窗需要繪製時,它會收到系統發來的WM_PAINT訊息。在繪製過程中,首先要準備顯示裝置控制代碼,最後要釋放控制代碼。眾所周知,在檢視視窗中繪製,無需過載WM_PAINT訊息處理函式OnPaint(),因為有一個更加友好的繪製新口:OnDraw()。該函式的實參是一個已經準備好的顯示裝置,最後無需釋放。其實,這一切還是WM_PAINT訊息處理函式OnPaint()為我們準備的,程式碼如下: void CView::OnPaint() { // CPaintDC類維護顯示裝置 CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc); } OnPrepareDC()是一個虛擬函式,它總是在OnDraw()之前執行,可以過載它,設定繪圖模式。因為OnDraw()每次執行,都使用不同的CPaintDC物件,所以本次繪圖模式的狀態不能保留到下一次。 OnDraw()在檢視基類CView中定義為純虛擬函式。例如: virtual void OnDraw(CDC* pDC) = 0; 所以CView是抽象基類,不能例項化,而派生類必須過載OnDraw()。 編輯本段虛擬函式 OnUpdate 當文件資料發生變化時,文件物件呼叫CDocument::UpdateAllView()通知所有檢視,作為響應,檢視的OnUpdate()成員被呼叫。所以,過載的OnUpdate()應該能夠根據需要,將文件資料的變化反映在檢視中。CView::OnUpdate()只是簡單地使客戶區無效,導致客戶區重畫。例如: void CView::OnUpdate(CView* pSender, LPARAM, CObject*) { ASSERT(pSender != this); UNUSED(pSender); // unused in release builds Invalidate(TRUE); } 編輯本段虛擬函式 OnInitialUpdate() 在初始建立、呼叫OnCreate()之後,或者在File/New、File/Open命令後被框架呼叫。基類CView::OnInitialUpdate()只是簡單地呼叫OnUpdate(),可以過載它完成初始化工作。但注意,它可能被多次呼叫。 void CView::OnInitialUpdate() { OnUpdate(NULL, 0, NULL); } 編輯本段虛擬函式 CalcWindowRect 每當主框架視窗的客戶區尺寸發生變化或控制條的位置發生變化,需要重新排列客戶區時,呼叫該函式,根據檢視客戶區尺寸計算檢視視窗的尺寸。 我們知道,排列主視窗客戶區是由CFrameWnd::RecalcLayout()完成的。顯然,檢視的CalcWindowRect()函式也是由它觸發呼叫的。主視窗的客戶區尺寸減掉所有控制佔用的部分,剩下的區域分給檢視,這部分割槽域作為實參傳入CalcWindowRect()。在CalcWindowRect()函式內,需要計算檢視視窗的尺寸。程式碼如下: void CView::CalcWindowRect(LPRECT lpClientRect, UNIT nAdjustType) { // lpClientRect此時是整個檢視客戶區的尺寸 // 需要為捲軸增加尺寸嗎 if (nAdjustType != 0) { // 呼叫API,根據視窗風格計算視窗尺寸 ::AdjustWindowRectEx(lpClientRect, 0, FALSE, GetExStyle()); DWORD dwStyle = GetStyle(); if (dwStyle & WS_VSCROLL) { // 為垂直捲軸增加尺寸 int nAdjust = afxData.csVScroll; if (dwStyle & WS_BORDER) nAdjust -= CX_BORDER; lpClientRect->right += nAdjust; } if (dwStyle & WS_HSCROLL) { // 為水平捲軸增加尺寸 int nAdjust = afxData.cyHScroll; if (dwStyle & WS_BORDER) nAdjust -= CY_BORDER; lpClientRect->bottom += nAdjust; } return; } // 無需為捲軸增加尺寸,呼叫基類成員完成計算 CWnd::CalcWindowRect(lpClientRect, nAdjustType); } 編輯本段虛擬函式PostNcDestroy 在檢視視窗關閉時最後呼叫的成員函式,它與CFrameWnd::PostNcDestroy完成相同的功能,即刪除檢視物件。程式碼如下: void CView::PostNcDestroy() { delete this; } 這樣,可以不必關心檢視的釋放工作,即使它在堆中構造。 編輯本段虛擬函式OnCmdMsg 在討論CFrameWnd::OnCmdMsg()時已經瞭解過該函式,下面只給出它的程式碼: BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { // 首先查詢自身的命令訊息對映 if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; // 如果檢視本身沒有處理該命令,將機會留給與其關聯的文件物件 if (m_pDocument != NULL) { CPushRoutingView push(this); return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } return FALSE; } 編輯本段虛擬函式 OnActivateView 當檢視被啟用為活動檢視,或由活動轉為非活動時,呼叫該函式通知檢視。基類的實現只是設定該檢視為焦點。程式碼如下: void CView::OnActivateView(BOOL bActivate, CView* pActivateView, CView*) { UNUSED(pActivateView); // unused in release builds if (bActivate) // 當前狀態為活動嗎 { ASSERT(pActivateView == this); // 如果其父視窗也是活動的,則設定焦點。(在MDI中,其父框架可能是非活動的) if (IsTopParentActive()) SetFocus(); } }