value.Empty();
}
value.ReleaseBuffer();
}
else//FALSE,写内容到列表框 {
// 把value字符串写入当前选中的条目
if (::SendMessage(hWndCtrl, LB_SELECTSTRING,
(WPARAM)-1,(LPARAM)(LPCTSTR)value) == LB_ERR)
{
// no selection match
TRACE0(\
}
} }
DDX_LBString用来在列表框和CString类型的成员数据之间交换数据。首先,得到列表框的句柄,然后,调用Win32的列表框操作函数读取或者修改列表框的内容。
?
下面的DDX_Control用于得到一个有效的控制类型窗口对象(MFC对象)。
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl) {
if (rControl.m_hWnd == NULL) // 还没有子类化 {
ASSERT(!pDX->m_bSaveAndValidate);
//得到控制窗口句柄
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
//把hWndCtrl窗口和MFC窗口对象rControl捆绑在一起 if (!rControl.SubclassWindow(hWndCtrl)) {
ASSERT(FALSE); //不允许两次子类化 AfxThrowNotSupportedException();
}
#ifndef _AFX_NO_OCC_SUPPORT//OLE控制相关的操作
else
{
// If the control has reparented itself (e.g., invisible control),
// make sure that the CWnd gets properly wired to its control site.
if
(pDX->m_pDlgWnd->m_hWnd != ::GetParent(rControl.m_hWnd))
rControl.AttachControlSite(pDX->m_pDlgWnd);
}
#endif //!_AFX_NO_OCC_SUPPORT
}
}
DDX_Control用来把控制窗口(Windows窗口)和一个对话框成员(MFC窗口对象)捆绑在一起,这个过程是通过SubclassWindow函数完成的。这样,程序员就可以通过成员变量来操作控制窗口,读、写、修改控制窗口的内容。
MFC还提供了许多其他数据交换函数(“DDX_”为前缀)和数据验证函数(“DDV_”为前缀)。DDV函数和DDX函数类似,这里不再多述。
程序员可以创建自己的数据交换和验证函数并使用它们,可以手工加入这些函数到DoDataExchange中,如果要Classwizard使用这些函数,可以修改DDX.CLW文件,在DDX、DDV函数入口中加入自己创建的函数。
1. UpdateData函数
有了数据交换类和数据交换函数,怎么来使用它们呢?MFC设计了UpdateData函数来完成上述数据交换和验证的处理。
首先,UpdateData创建CDataExchange对象,然后调用DoDataExchange函数。其实现如下:
BOOL CWnd::UpdateData(BOOL bSaveAndValidate) {
ASSERT(::IsWindow(m_hWnd)); // calling UpdateData before DoModal? //创建CDataChange对象
CDataExchange dx(this, bSaveAndValidate); //防止在UpdateData期间派发通知消息给该窗口
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState(); HWND hWndOldLockout = pThreadState->m_hLockoutNotifyWindow; ASSERT(hWndOldLockout != m_hWnd); // must not recurse pThreadState->m_hLockoutNotifyWindow = m_hWnd; BOOL bOK = FALSE; // assume failure TRY {
//数据交换
DoDataExchange(&dx); bOK = TRUE; // it worked
}
CATCH(CUserException, e)//例外 {
// validation failed - user already alerted, fall through ASSERT(bOK == FALSE);
// Note: DELETE_EXCEPTION_(e) not required
}
AND_CATCH_ALL(e)
{
// validation failed due to OOM or other resource failure e->ReportError(MB_ICONEXCLAMATION, FX_IDP_INTERNAL_FAILURE); ASSERT(!bOK); DELETE_EXCEPTION(e);
}
END_CATCH_ALL //恢复原来的值
pThreadState->m_hLockoutNotifyWindow = hWndOldLockout; return bOK; }
UpdataDate根据参数创建CDataExchange对象dx,如果参数为TRUE,dx用来写数据,否则dx用来读数据;然后调用DoDataExchange进行数据交换。在数据交换期间,为了防止当前窗口接收和处理命令通知消息,在当前线程的线程状态中记录该窗口的句柄,用来防止给该窗口发送通知消息。
使用MFC的数据交换和验证机制,大大简化了程序员的工作。通常在OnInitDialog中,MFC调用UpdateData(FALSE)把数据送给控制窗口显示;在OnOk中,调用UpdateData(TRUE)从控制窗口中读取数据。
1. 无模式对话框
CFormView是MFC使用无模式对话框的一个典型例子。CFormView是基于对话框模板创建的视,它的直接基类是CSrcollView,CSrcollView的直接基类才是CView。所以,这里先对CScorllView作一个简要的介绍。
1. CScrollView
CScrollView继承了CView的特性,并且增加了如下的功能:
(1)管理映射模式、窗口尺寸、视口尺寸(Map mode、Window and Viewport size)。Window and Viewport size用来完成页面空间到设备空间的转换。 (2)自动管理滚动条,响应滚动条消息。
为了实现这些功能,CScrollView覆盖CView或者CWnd的一些虚拟函数和消息处理函数,添加了一些新的函数,当然也设计了新的成员变量。
?
CscrollView新的成员变量
protected: int m_nMapMode;
CSize m_totalLog; // total size in logical units (no rounding) CSize m_totalDev; // total size in device units
CSize m_pageDev; // per page scroll size in device units CSize m_lineDev; // per line scroll size in device units BOOL m_bCenter; // Center output if larger than total size BOOL m_bInsideUpdate; // internal state for OnSize callback
?
CScrollView新的成员函数,用来完成和滚动操作、滚动条等有关的功能
void SetScaleToFitSize(SIZE sizeTotal);
void SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault);