2 回答

TA貢獻1757條經驗 獲得超8個贊
關于對話框數據交換及驗證
對話框的數據交換和驗證機制(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);
}

TA貢獻1850條經驗 獲得超11個贊
UpdateData函數內部以this和UpdateData的參數為參數,構造了一個CDataExchange變量,以類變量的形式保存傳入構造的參數。
然后調用DoDataExchange,傳入上面的變量。
由于DoDataExchange是虛函數,這就回到了你的類的DoDataExchange中了。
DoDataExchange里面的宏很簡單,簡單看看就明白了。
- 2 回答
- 0 關注
- 105 瀏覽
添加回答
舉報