您的位置:首页 > 其它

MFC控件数据交换:DDX

2017-10-30 15:51 411 查看
MFC中操纵控件
   操作控件的两种方式:
   方式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静态库

编写如下测试代码

[cpp] view
plain copy

// 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 控件类型的绑定

[cpp] view
plain copy

DDX_Control (pDX, IDOK, m_wndOK);  

跟进:

[cpp] view
plain copy

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))  

    {  

        ..........................................  

    }  

}  

[cpp] view
plain copy

DDX_Control-->SubclassWindow  

跟进:

[cpp] view
plain copy

BOOL CWnd::SubclassWindow(HWND hWnd)  

{// this == m_wndOK, hWnd == 控件句柄  

    // 将m_wndOK控件变量与OK按钮句柄绑定  

    if (!Attach(hWnd))  

        return FALSE;  

    ...............................................  

}  

[cpp] view
plain copy

DDX_Control-->SubclassWindow-->Attach  

跟进:

[cpp] view
plain copy

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);  

    ........................................  

}  

[cpp] view
plain copy

DDX_Control-->SubclassWindow-->Attach-->SetPermanent  

跟进:

[cpp] view
plain copy

void CHandleMap::SetPermanent(HANDLE h, CObject* permOb)  

{  

    .......................................  

    // 以控件句柄为键,以变量句柄为值建立映射关系  

    m_permanentMap[(LPVOID)h] = permOb;  

    .........................................  

}  

Ok到这里就清晰了

  总结流程如下:

   

[cpp] view
plain copy

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 值类型的绑定

[cpp] view
plain copy

UpdateData (FALSE);  

跟进:

[cpp] view
plain copy

BOOL CWnd::UpdateData(BOOL bSaveAndValidate)  

{// this == &dlg,  bSaveAndValidate == FALSE  

    .............................................  

  

    CDataExchange dx(this, bSaveAndValidate);  

  

     ..........................................  

     // 虚函数,会调用我们重写的函数  

     DoDataExchange(&dx);  

     ........................................  

}  

[cpp] view
plain copy

UpdateData-->DoDataExchange-->CMyDlg::DoDataExchange-->DDX_Text  

跟进:

[cpp] view
plain copy

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);  

    }  

}  

总结上面的流程如下:

[cpp] view
plain copy

 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);  

  }  

           

       }  

    }  

 } 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mfc