?? mfc教程_ 對話框和對話框類cdialog.htm
字號:
<P
align=justify>MFC還提供了許多其他數據交換函數(“DDX_”為前綴)和數據驗證函數(“DDV_”為前綴)。DDV函數和DDX函數類似,這里不再多述。</P>
<P
align=justify>程序員可以創建自己的數據交換和驗證函數并使用它們,可以手工加入這些函數到DoDataExchange中,如果要Classwizard使用這些函數,可以修改DDX.CLW文件,在DDX、DDV函數入口中加入自己創建的函數。</P>
<OL>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc457299128></A><B>UpdateData函數</B>
<P></P></LI></OL></OL></OL></OL>
<P align=justify>有了數據交換類和數據交換函數,怎么來使用它們呢?MFC設計了UpdateData函數來完成上述數據交換和驗證的處理。</P>
<P align=justify>首先,UpdateData創建CDataExchange對象,然后調用DoDataExchange函數。其實現如下:</P>
<P align=justify>BOOL CWnd::UpdateData(BOOL bSaveAndValidate)</P>
<P align=justify>{</P>
<P align=justify>ASSERT(::IsWindow(m_hWnd)); // calling UpdateData before
DoModal?</P>
<P align=justify></P>
<P align=justify>//創建CDataChange對象</P>
<P align=justify>CDataExchange dx(this, bSaveAndValidate);</P>
<P align=justify></P>
<P align=justify>//防止在UpdateData期間派發通知消息給該窗口</P>
<P align=justify>_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();</P>
<P align=justify>HWND hWndOldLockout =
pThreadState->m_hLockoutNotifyWindow;</P>
<P align=justify>ASSERT(hWndOldLockout != m_hWnd); // must not recurse</P>
<P align=justify>pThreadState->m_hLockoutNotifyWindow = m_hWnd;</P>
<P align=justify></P>
<P align=justify>BOOL bOK = FALSE; // assume failure</P>
<P align=justify>TRY</P>
<P align=justify>{</P>
<DIR>
<P align=justify>//數據交換</P>
<P align=justify>DoDataExchange(&dx);</P>
<P align=justify>bOK = TRUE; // it worked</P></DIR>
<P align=justify>}</P>
<P align=justify>CATCH(CUserException, e)//例外</P>
<P align=justify>{</P>
<DIR>
<P align=justify>// validation failed - user already alerted, fall through</P>
<P align=justify>ASSERT(bOK == FALSE);</P>
<P align=justify>// Note: DELETE_EXCEPTION_(e) not required</P></DIR>
<P align=justify>}</P>
<DIR>
<P align=justify>AND_CATCH_ALL(e)</P></DIR>
<P align=justify>{</P>
<DIR>
<P align=justify>// validation failed due to OOM or other resource failure</P>
<P align=justify>e->ReportError(MB_ICONEXCLAMATION,
FX_IDP_INTERNAL_FAILURE);</P>
<P align=justify>ASSERT(!bOK);</P>
<P align=justify>DELETE_EXCEPTION(e);</P></DIR>
<P align=justify>}</P>
<P align=justify>END_CATCH_ALL</P>
<P align=justify></P>
<P align=justify>//恢復原來的值</P>
<P align=justify>pThreadState->m_hLockoutNotifyWindow = hWndOldLockout;</P>
<P align=justify>return bOK;</P>
<P align=justify>}</P>
<P
align=justify>UpdataDate根據參數創建CDataExchange對象dx,如果參數為TRUE,dx用來寫數據,否則dx用來讀數據;然后調用DoDataExchange進行數據交換。在數據交換期間,為了防止當前窗口接收和處理命令通知消息,在當前線程的線程狀態中記錄該窗口的句柄,用來防止給該窗口發送通知消息。</P>
<P
align=justify>使用MFC的數據交換和驗證機制,大大簡化了程序員的工作。通常在OnInitDialog中,MFC調用UpdateData(FALSE)把數據送給控制窗口顯示;在OnOk中,調用UpdateData(TRUE)從控制窗口中讀取數據。</P>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc452641003></A><A name=_Toc457299129></A><B>無模式對話框</B>
<P></P>
<P>CFormView是MFC使用無模式對話框的一個典型例子。CFormView是基于對話框模板創建的視,它的直接基類是CSrcollView,CSrcollView的直接基類才是CView。所以,這里先對CScorllView作一個簡要的介紹。</P>
<OL>
<P align=justify>
<LI><A name=_Toc452641004></A><A name=_Toc457299130></A><B>CScrollView</B>
<P></P></LI></OL></LI></OL></OL>
<P align=justify>CScrollView繼承了CView的特性,并且增加了如下的功能:</P>
<P align=justify>(1)管理映射模式、窗口尺寸、視口尺寸(Map mode、Window and Viewport size)。Window
and Viewport size用來完成頁面空間到設備空間的轉換。</P>
<P align=justify>(2)自動管理滾動條,響應滾動條消息。</P>
<P
align=justify>為了實現這些功能,CScrollView覆蓋CView或者CWnd的一些虛擬函數和消息處理函數,添加了一些新的函數,當然也設計了新的成員變量。</P>
<UL>
<P align=justify>
<LI>CscrollView新的成員變量
<P></P></LI></UL>
<P align=justify>protected:</P>
<P align=justify>int m_nMapMode;</P>
<P align=justify>CSize m_totalLog; // total size in logical units (no
rounding)</P>
<P align=justify>CSize m_totalDev; // total size in device units</P>
<P align=justify>CSize m_pageDev; // per page scroll size in device units</P>
<P align=justify>CSize m_lineDev; // per line scroll size in device units</P>
<P align=justify></P>
<P align=justify>BOOL m_bCenter; // Center output if larger than total size</P>
<P align=justify>BOOL m_bInsideUpdate; // internal state for OnSize callback</P>
<UL>
<P align=justify>
<LI>CScrollView新的成員函數,用來完成和滾動操作、滾動條等有關的功能
<P></P></LI></UL>
<P align=justify>void SetScaleToFitSize(SIZE sizeTotal);</P>
<P align=justify>void SetScrollSizes(int nMapMode, SIZE sizeTotal,</P>
<P align=justify>const SIZE& sizePage = sizeDefault,</P>
<P align=justify>const SIZE& sizeLine = sizeDefault);</P>
<P align=justify>這兩個函數中的尺寸大小按邏輯單位計算。</P>
<P
align=justify>SetScaleToFitSize設置視口尺寸為當前的窗口尺寸,這樣,在沒有滾動條時,邏輯視的內容被放大或者縮小到正好窗口大小。</P>
<P align=justify>SetScrollSizes設置窗口的映射模式,窗口尺寸,頁和行尺寸。sizeDefualt被定義為(0,0)。</P>
<UL>
<P align=justify>
<LI>下面幾個函數用來實現滾動或者得到滾動條相關的信息
<P></P></LI></UL>
<P align=justify>void ScrollToPosition(POINT pt); // set upper left position</P>
<P align=justify>void FillOutsideRect(CDC* pDC, CBrush* pBrush);</P>
<P align=justify>void ResizeParentToFit(BOOL bShrinkOnly = TRUE);</P>
<P align=justify>CPoint GetScrollPosition() const; // upper corner of
scrolling</P>
<P align=justify>CSize GetTotalSize() const; // logical size</P>
<UL>
<P align=justify>
<LI>下面兩個函數使用了設備坐標單位
<P></P></LI></UL>
<P align=justify>CPoint GetDeviceScrollPosition() const;</P>
<P align=justify>void GetDeviceScrollSizes(int& nMapMode, SIZE&
sizeTotal,</P>
<P align=justify>SIZE& sizePage, SIZE& sizeLine) const;</P>
<P align=justify></P>
<UL>
<P align=justify>
<LI>覆蓋的消息處理函數
<P></P></LI></UL>
<P align=justify>處理WM_SIZE的OnSize;</P>
<P align=justify>處理WM_HSCROLL的OnHScroll;</P>
<P align=justify>處理WM_VSCROLL的OnVScroll;</P>
<P align=justify></P>
<UL>
<P align=justify>
<LI>覆蓋的虛擬函數
<P></P></LI></UL>
<P align=justify>CWnd的CalcWindowRect</P>
<P align=justify>CView的OnPrepareDC、OnScroll、OnScrollBy</P>
<UL>
<P align=justify>
<LI>用于DEBUG的Dump和AssertValid
<P></P></LI></UL>
<P align=justify>這里,覆蓋的消息處理函數和虛擬函數共同完成對滾動條、滾動消息的處理。</P>
<P align=justify>在CSrcollView的實現涉及到許多和Windows映射模式、坐標轉換等相關的函數的使用。這里,不作具體討論。</P>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc452641005></A><A name=_Toc457299131></A><B>CFormView</B>
<P></P></LI></OL></OL></OL>
<P
align=justify>CFormView派生于CSrcollView,本身沒有增加新的函數,但覆蓋了一些基類的虛擬函數,增加了幾個成員變量(以下列出的不包含OLE處理)。</P>
<OL>
<P align=justify>
<LI>增加的成員變量
<P></P>
<P align=justify>LPCTSTR m_lpszTemplateName;</P>
<P align=justify>CCreateContext* m_pCreateContext;</P>
<P align=justify>HWND m_hWndFocus; // last window to have focus</P>
<P
align=justify>m_lpszTemplateName用來保存創建視圖的對話框模板的名稱,_pCreateContext用來保存創建上下文,m_hWndFocus用來保存最近一次擁有焦點的控制窗口。在構造CFormView對象時,構造函數把有關信息保存到成員變量中,如下所示:</P>
<P align=justify>CFormView::CFormView(LPCTSTR lpszTemplateName)</P>
<P align=justify>{</P>
<P align=justify>m_lpszTemplateName = lpszTemplateName;</P>
<P align=justify>m_pCreateContext = NULL;</P>
<P align=justify>m_hWndFocus = NULL; // focus window is font</P>
<P align=justify>}</P>
<P align=justify></P>
<LI>覆蓋的虛擬函數
<P></P>
<P align=justify>virtual void OnDraw(CDC* pDC); // MFC缺省處理空</P>
<P align=justify>virtual BOOL Create(LPCTSTR, LPCTSTR, DWORD,</P>
<P align=justify>const RECT&, CWnd*, UINT, CCreateContext*);</P>
<P align=justify>virtual BOOL PreTranslateMessage(MSG* pMsg);</P>
<P align=justify>virtual void OnActivateView(BOOL, CView*, CView*);</P>
<P align=justify>virtual void OnActivateFrame(UINT, CFrameWnd*);</P>
<P
align=justify>創建基于對話框的視窗口,不同于創建普通視窗口(前者調用CWnd::CreateEx,后者調用CWnd::CreateDlg),故需要覆蓋Create虛擬函數。</P>
<P align=justify>覆蓋PreTranslateMessage是為了過濾對話框消息,把一些消息讓CFormView對象來處理。</P>
<P align=justify></P>
<LI>覆蓋了兩個消息處理函數:
<P></P></LI></OL>
<P align=justify>afx_msg int OnCreate(LPCREATESTRUCT lpcs);</P>
<P align=justify>afx_msg void OnSetFocus(CWnd* pOldWnd);</P>
<P
align=justify>下面,分析幾個函數作。Create函數解釋了MFC如何使用一個對話框作為視的方法,PreTranslateMessage顯示了CFormView不同于CDialog的實現。</P>
<OL>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc457299132></A><B>CFormView的創建</B>
<P></P>
<P align=justify>設計CFormView的創建函數,必須考慮兩個問題:</P>
<P
align=justify>首先,CFormView是一個視,其創建函數必須是一個虛擬函數,原型必須和CWnd::Create(LPSTR…pContext)函數一致,見圖5-13視的創建。其次,CFormView使用了對話框創建函數和對話框“窗口類”來創建視,但必須作一些處理使得該窗口具備視的特征。</P>
<P align=justify>Create的實現如下:</P>
<P align=justify>BOOL CFormView::Create(LPCTSTR /*lpszClassName*/,</P>
<P align=justify>LPCTSTR /*lpszWindowName*/,</P>
<P align=justify>DWORD dwRequestedStyle, const RECT& rect, CWnd*
pParentWnd, UINT nID,</P>
<P align=justify>CCreateContext* pContext)</P>
<P align=justify>{</P>
<P align=justify>ASSERT(pParentWnd != NULL);</P>
<P align=justify>ASSERT(m_lpszTemplateName != NULL);</P>
<P align=justify></P>
<P align=justify>m_pCreateContext = pContext; // save state for later
OnCreate</P>
<P align=justify></P>
<P align=justify>#ifdef _DEBUG</P>
<P align=justify>// dialog template must exist and be invisible with
WS_CHILD set</P>
<P align=justify>if (!_Af
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -