操作控件的兩種方式:
方式1 通過調用CWnd::GetDlgItem()函數,根據控件ID獲取控件對象指針,操作控件即可。
對話框的初始化函數:OnInitDialog()
方式2 對話框的數據交換技術(DDX)
將控件和一個成員變量綁定,可以通過操作成員變量達到操作控件的目的。
1 定義與控件綁定的成員變量
2 在對話框中添加DoDataExchange()函數,在函數中完成控件
與變量的綁定。
DDX_Control()//控件類型的綁定
DDX_Text()//值類型的綁定
3 通過成員變量完成對控件的操作
4 值類型的綁定,還需要調用UpdateData(BOOL)函數
UpdateData(TRUE)- 控件中的值傳賦值變量(接收)
UpdateData(FALSE)-將變量的值顯示到控件上
新建一個Win32 Application,選擇A Simple Win32 Application,修改stdafx.h 中的windwos.h爲afxwin.h,工程屬性設置使用MFC靜態庫
編寫如下測試代碼
// DDX.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
class CMyDlg : public CDialog
{
public:
CMyDlg ():CDialog(IDD_DIALOG1){}
virtual void DoDataExchange (CDataExchange* pDX);
virtual BOOL OnInitDialog ();
virtual void OnOK();
protected:
CButton m_wndOK;
CString m_strEdit;
};
void CMyDlg::DoDataExchange (CDataExchange* pDX)
{
//完成控件與變量的綁定
DDX_Control (pDX, IDOK, m_wndOK);
DDX_Text (pDX, IDC_EDIT1, m_strEdit);
}
BOOL CMyDlg::OnInitDialog ()
{
if (!CDialog::OnInitDialog())
return FALSE;
// 初始化控件
// 方式一:通過GetDlgItem操作控件
CWnd *pWnd = GetDlgItem (IDCANCEL);
pWnd->EnableWindow (FALSE);
m_wndOK.MoveWindow (0, 0, 100, 100);
m_wndOK.SetWindowText ("DDXOK");
// 方式二:通過DDX操作控件
m_strEdit = "Hello you";
UpdateData (FALSE);
return TRUE;
}
void CMyDlg::OnOK ()
{
// 接收控件的值到關聯的變量
UpdateData (TRUE);
AfxMessageBox (m_strEdit);
CDialog::OnOK();
}
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance ();
};
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance ()
{
CMyDlg dlg;
m_pMainWnd = &dlg;
dlg.DoModal ();
return TRUE;
}
DDX的實現原理
1 控件類型的綁定
DDX_Control (pDX, IDOK, m_wndOK);
跟進:
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
{// nIDC: IDCOK , rControl: m_wndOK
...................................
// 通過控件ID得到控件句柄
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
if (!rControl.SubclassWindow(hWndCtrl))
{
..........................................
}
}
DDX_Control-->SubclassWindow
跟進:
BOOL CWnd::SubclassWindow(HWND hWnd)
{// this == m_wndOK, hWnd == 控件句柄
// 將m_wndOK控件變量與OK按鈕句柄綁定
if (!Attach(hWnd))
return FALSE;
...............................................
}
DDX_Control-->SubclassWindow-->Attach
跟進:
BOOL CWnd::Attach(HWND hWndNew)
{//this == m_wndOK, hWndNew == 控件句柄
......................................
CHandleMap* pMap = afxMapHWND(TRUE); // create map if not exist
ASSERT(pMap != NULL);
// 建立映射關係
pMap->SetPermanent(m_hWnd = hWndNew, this);
........................................
}
DDX_Control-->SubclassWindow-->Attach-->SetPermanent
跟進:
void CHandleMap::SetPermanent(HANDLE h, CObject* permOb)
{
.......................................
// 以控件句柄爲鍵,以變量句柄爲值建立映射關係
m_permanentMap[(LPVOID)h] = permOb;
.........................................
}
Ok到這裏就清晰了
總結流程如下:
DDX_Control(pDX,IDOK,m_wndOK);
{
//通過控件ID得到控件句柄
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
//將控件句柄與變量綁定
rControl.SubclassWindow(hWndCtrl);
{
Attach(hWnd);
{
pMap->SetPermanent(m_hWnd = hWndNew, this);
{
//以句柄爲健,以變量地址爲值建立映射關係
m_permanentMap[(LPVOID)h] = permOb;
}
}
}
}
2 值類型的綁定
UpdateData (FALSE);
跟進:
BOOL CWnd::UpdateData(BOOL bSaveAndValidate)
{// this == &dlg, bSaveAndValidate == FALSE
.............................................
CDataExchange dx(this, bSaveAndValidate);
..........................................
// 虛函數,會調用我們重寫的函數
DoDataExchange(&dx);
........................................
}
UpdateData-->DoDataExchange-->CMyDlg::DoDataExchange-->DDX_Text
跟進:
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value)
{// pDX中保存了&dlg和FALSE, nIDC == IDOK, value == m_strEdit
// 通過控件ID拿到編輯框控件句柄
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
if (pDX->m_bSaveAndValidate)
{// UpdateData (TRUE)
int nLen = ::GetWindowTextLength(hWndCtrl);
// 獲取控件文本
::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1);
value.ReleaseBuffer();
}
else
{// UpdateData (FALSE)
// 設置控件文本
AfxSetWindowText(hWndCtrl, value);
}
}
總結上面的流程如下:
UpdateData(FALSE);
{
CDataExchange dx(this, bSaveAndValidate);
DoDataExchange(&dx);
{
DDX_Text(pDX,IDC_EDIT1,m_strEdit);
{
//通過控件ID得到控件句柄
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
if (pDX->m_bSaveAndValidate)
{
::GetWindowText(hWndCtrl,...);
value.ReleaseBuffer();
}
else
{
//將變量的值設置到控件的窗口上
AfxSetWindowText(hWndCtrl, value);
}
}
}
}