📄 mfc12.php
字号:
<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 (!_AfxCheckDialogTemplate(m_lpszTemplateName,
TRUE))</P>
<P align=justify>{</P>
<P align=justify>ASSERT(FALSE); //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -