對(duì)話框數(shù)據(jù)交換及驗(yàn)證
對(duì)話框的數(shù)據(jù)交換和驗(yàn)證機(jī)制(DDX、DDV)可以使對(duì)話框上控件與對(duì)象數(shù)據(jù)成員間協(xié)調(diào)工作。
包括控件窗口與控件對(duì)象間的連接,控件窗口與對(duì)話框數(shù)據(jù)成員間的連接,以及數(shù)據(jù)成員的合法性驗(yàn)證等等。
在 virtual void DoDataExchange(CDataExchange* pDX);中記錄了這些關(guān)系:
例如:
DDX_Control(pDX, IDC_BUTTON1, m_btn); //CButton對(duì)象到控件窗口IDC_BUTTON1的關(guān)聯(lián)
DDX_Text(pDX, IDC_EDIT1, m_int); //整型數(shù)據(jù)到編輯窗口的關(guān)聯(lián)
DDV_MinMaxInt(pDX, m_int, 0, 40); //整型數(shù)據(jù)的范圍驗(yàn)證
必要時(shí),可以自己編寫驗(yàn)證函數(shù)實(shí)現(xiàn)特定內(nèi)容檢驗(yàn)。
相關(guān)的成員函數(shù):
CDialog::OnInitDialog();
CWnd::DoDataExchange();
CDialog::DoDataExchange();
1 .控件關(guān)聯(lián)
DDX_Control實(shí)現(xiàn)控件窗口和C++控件對(duì)象的關(guān)聯(lián)。
由于對(duì)話框是以模板的方式建立的,故控件窗口都是事先建立好的。
C++控件對(duì)象用SubClassWindow的方法附著在控件窗口上,管理窗口的行為。
內(nèi)部流程分析:
①OnInitDialog 時(shí)調(diào)用基類CDialog::OnInitDialog();
BOOL CDialog::OnInitDialog()
{
.....
// 執(zhí)行UpdateData(),參數(shù)為FALSE,表示初始化
if (!UpdateData(FALSE))
{
....
}
.....
}
②UpdateData()
BOOL CWnd::UpdateData(BOOL bSaveAndValidate)
{
....
//調(diào)用虛函數(shù)DoDataExchange
CDataExchange dx(this, bSaveAndValidate);
....
TRY
{
DoDataExchange(&dx);
bOK = TRUE; // it worked
}
.....
}
③DoDataExchange
void C????Dlg::DoDataExchange(CDataExchange* pDX)
{
....
//對(duì)象到窗口的關(guān)聯(lián)。
DDX_Control(pDX, IDC_BUTTON1, m_btn);
....
}
④DDX_Control
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
{
if (rControl.m_hWnd == NULL) //若還未關(guān)聯(lián)
{
//窗口句柄
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
// SubclassWindow 實(shí)現(xiàn)關(guān)聯(lián)。
if (!rControl.SubclassWindow(hWndCtrl))
{
....
}
....
}
}
至此,控件對(duì)象與對(duì)話框上的子窗口關(guān)聯(lián)上了,可以通過對(duì)控件對(duì)象的操作來管理該子窗口。
2 .數(shù)據(jù)關(guān)聯(lián)
大致流程與前相似。在對(duì)話框OnOK()時(shí)將調(diào)用Update(TRUE),參數(shù)TRUE表示讀出及校驗(yàn)數(shù)據(jù)。
另可根據(jù)需要,隨時(shí)調(diào)用Update(TRUE)完成窗口內(nèi)容到成員數(shù)據(jù)的校驗(yàn)及轉(zhuǎn)換。
流程分析(以編輯框到整數(shù)的關(guān)聯(lián)為例)
①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) //讀取及校驗(yàn)
_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
在對(duì)話框初始化時(shí),m_bSaveAndValidate參數(shù)為FALSE;
在進(jìn)行數(shù)據(jù)讀取時(shí),m_bSaveAndValidate參數(shù)為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 //對(duì)話框初始化時(shí),以成員數(shù)據(jù)內(nèi)容初始窗口內(nèi)容。
{
//初始化窗口內(nèi)容。
wvsprintf(szT, lpszFormat, pData);
AfxSetWindowText(hWndCtrl, szT);
}
....
}
3. 數(shù)據(jù)驗(yàn)證
流程分析(以整數(shù)數(shù)值范圍驗(yàn)證為例)
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);
//驗(yàn)證
if (value < minVal || value > maxVal)
//報(bào)錯(cuò)返回
_AfxFailMinMaxWithFormat(pDX, (long)minVal, (long)maxVal, _T("%ld"),
AFX_IDP_PARSE_INT_RANGE);
}
(#)