陪伴而非守候
关于对话框数据交换及验证 对话框的数据交换和验证机制(DDX、DDV)可以使对话框上控件与对象数据成员间协调工作。 包括控件窗口与控件对象间的连接,控件窗口与对话框数据成员间的连接,以及数据成员的合法性验证等等。 在 virtual void DoDataExchange(CDataExchange* pDX);中记录了这些关系: 例如: DDX_Control(pDX, IDC_BUTTON1, m_btn); //CButton对象到控件窗口IDC_BUTTON1的关联 DDX_Text(pDX, IDC_EDIT1, m_int); //整型数据到编辑窗口的关联 DDV_MinMaxInt(pDX, m_int, 0, 40); //整型数据的范围验证 必要时,可以自己编写验证函数实现特定内容检验。 相关的成员函数: CDialog::OnInitDialog(); CWnd::DoDataExchange(); CDialog::DoDataExchange(); 1 .控件关联 DDX_Control实现控件窗口和C++控件对象的关联。 由于对话框是以模板的方式建立的,故控件窗口都是事先建立好的。 C++控件对象用SubClassWindow的方法附着在控件窗口上,管理窗口的行为。 内部流程分析: ①OnInitDialog 时调用基类CDialog::OnInitDialog(); BOOL CDialog::OnInitDialog() { ..... // 执行UpdateData(),参数为FALSE,表示初始化 if (!UpdateData(FALSE)) { .... } ..... } ②UpdateData() BOOL CWnd::UpdateData(BOOL bSaveAndValidate) { .... //调用虚函数DoDataExchange CDataExchange dx(this, bSaveAndValidate); .... TRY { DoDataExchange(&dx); bOK = TRUE; // it worked } ..... } ③DoDataExchange void C????Dlg::DoDataExchange(CDataExchange* pDX) { .... //对象到窗口的关联。 DDX_Control(pDX, IDC_BUTTON1, m_btn); .... } ④DDX_Control void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl) { if (rControl.m_hWnd == NULL) //若还未关联 { //窗口句柄 HWND hWndCtrl = pDX->PrepareCtrl(nIDC); // SubclassWindow 实现关联。 if (!rControl.SubclassWindow(hWndCtrl)) { .... } .... } } 至此,控件对象与对话框上的子窗口关联上了,可以通过对控件对象的操作来管理该子窗口。 2 .数据关联 大致流程与前相似。在对话框OnOK()时将调用Update(TRUE),参数TRUE表示读出及校验数据。 另可根据需要,随时调用Update(TRUE)完成窗口内容到成员数据的校验及转换。 流程分析(以编辑框到整数的关联为例) ①DoDataExchange void C???Dlg::DoDataExchange(CDataExchange* pDX) { .... DDX_Text(pDX, IDC_EDIT1, m_int); .... } ②DDX_Text void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, int& value) { if (pDX->m_bSaveAndValidate) //读取及校验 _Afx_DDX_TextWithFormat(pDX, nIDC, _T("%d"), AFX_IDP_PARSE_INT, &value); else //初始化 _Afx_DDX_TextWithFormat(pDX, nIDC, _T("%d"), AFX_IDP_PARSE_INT, value); } ③_Afx_DDX_TextWithFormat 在对话框初始化时,m_bSaveAndValidate参数为FALSE; 在进行数据读取时,m_bSaveAndValidate参数为TRUE; AFX_STATIC void AFX_CDECL _Afx_DDX_TextWithFormat(CDataExchange* pDX, int nIDC, LPCTSTR lpszFormat, UINT nIDPrompt, ...) // only supports windows output formats - no floating point { .... //窗口句柄 HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC); TCHAR szT[32]; if (pDX->m_bSaveAndValidate) { //读取 // the following works for %d, %u, %ld, %lu ::GetWindowText(hWndCtrl, szT, _countof(szT)); if (!_AfxSimpleScanf(szT, lpszFormat, pData)) { AfxMessageBox(nIDPrompt); pDX->Fail(); // throws exception } } else //对话框初始化时,以成员数据内容初始窗口内容。 { //初始化窗口内容。 wvsprintf(szT, lpszFormat, pData); AfxSetWindowText(hWndCtrl, szT); } .... } 3. 数据验证 流程分析(以整数数值范围验证为例) void C????Dlg::DoDataExchange(CDataExchange* pDX) { .... DDV_MinMaxInt(pDX, m_int, 0, 40); .... } void AFXAPI DDV_MinMaxInt(CDataExchange* pDX, int value, int minVal, int maxVal) { ASSERT(minVal <= maxVal); //验证 if (value < minVal || value > maxVal) //报错返回 _AfxFailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, _T("%ld"), AFX_IDP_PARSE_INT_RANGE); }