• VC中DDX/DDV自定义


    DDX用于控件与变量的数据交换.DDV用于对数据交换后的变量进行校验,倘若校验失败将抛出异常导致Updata后面部分不能正常执行.必要时需要对Updata的返回值进行判断.
        对于数据交换,需要编写一个带有参数CDataExchange指针、一个控件ID和对某变量引用的全局函数,尽管可以不在函数前面添加DDX_前缀,但是为了可以和Class Wizard集成,最好忍住你的这种念头(后面你会看到为什么了).

        在交换函数中,可以检查CDataExchange指针,以了解你所须的细节.下面就来看看CDataExchange类的成员.

    成员 描述
    m_bSaveAndValidate 对应于你提供给UpdateData的参数,当为TRUE时数据从控件传递到变量
    m_pDlgWnd 控制窗口或对话框的句柄
    PrepareCtrl(int nIDC) 调用该函数,以标识当前控件(如不是编辑框)
    PrepareEditCtrl(int nIDC) 调用该函数,以标识当前控件(如是编辑框)
    Fail() 产生一个对控件的验证失败(你可以在DDX或者DDV中调用该函数),抛出一个异常,破坏DoDataExchange函数的执行

        一般的,编写交换函数,,你首先要检查m_bSaveAndValidate的值以确定数据的传递方向,如果传递失败,你有必要调用PrepareEditCtrl(适于编辑控件)或者PrepareCtrl(适于所有控件),在做此调用之后,任何对Fail的调用将导致把焦点交回给该控件,即使其它过程(比如一起的验证过程)发布同样的失败,也是这样编写一个验证函数,跟编写一个交换函数差不多,差别只是参数的不同.函数以DDV_为前缀,参数可以接受一个CDataExchange指针、合适类型的一个只值、一个或两个参数.

        它的工作很简单,如果m_bSaveAndValidate为TRUE时,一定要保证值是合法的(通常认为从程序传递到控件的值是正确的).如果数据正常,则从该函数返回,如果数据不正常,则调用Fail函数.前一个数据交换函数已经标识了当前操作的是哪个控件(这也就是为什么必须要在对应的DDX调用之后立即添加DDV的验证代码的原因了).
        下面的例子演示了如何定制自己的数据验证:

    程序清单:使用定制的DDX/DDV
    // validView.cpp : implementation of the CValidView class
    //
    #include "stdafx.h"
    #include "valid.h"
    typedef float Currency; // used for DDV
    #include "validDoc.h"
    #include "validView.h"
    #include "customdd.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    /////////////////////////////////////////////////////////////////////////////
    // CValidView
    IMPLEMENT_DYNCREATE(CValidView, CFormView)
    // Class Wizard won't put this here because it thinks
    // Dialog boxes handle OnOK. They do, but this is a
    // form view, not a dialog box
    BEGIN_MESSAGE_MAP(CValidView, CFormView)
        //{{AFX_MSG_MAP(CValidView)
        ON_COMMAND(IDOK,OnOK)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

    // CValidView construction/destruction
    CValidView::CValidView()
    : CFormView(CValidView::IDD)
    {
        validating=FALSE;
        vid=0;
    //{{AFX_DATA_INIT(CValidView)
        m_age = 18;
        m_name = _T("");
        m_wager = 1.0;
        m_btnenable = TRUE;
    //}}AFX_DATA_INIT
    // TODO: add construction code here
    }

    CValidView::~CValidView()
    void CValidView::DoDataExchange(CDataExchange* pDX)
    :CFormView::DoDataExchange(pDX);
    {
    //{{AFX_DATA_MAP(CValidView)
        DDX_Text(pDX, IDC_AGE, m_age);
        DDV_MinMaxInt(pDX, m_age, 18, 150);
        DDX_Text(pDX, IDC_NAME, m_name);
        DDV_MaxChars(pDX, m_name, 64);
        DDX_Text(pDX, IDC_WAGER, m_wager);
        DDV_MinMaxCurrency(pDX, m_wager, 1.f, 100.f);
        DDX_EnableWindow(pDX, IDOK, m_btnenable);
    //}}AFX_DATA_MAP
    }

    BOOL CValidView::PreCreateWindow(CREATESTRUCT& cs)
    // TODO: Modify the Window class or styles here by modifying
    // the CREATESTRUCT cs
    return CFormView::PreCreateWindow(cs);
    // CValidView diagnostics
    void CValidView::AssertValid() const
    CFormView::AssertValid();
    void CValidView::Dump(CDumpContext& dc) const
    CFormView::Dump(dc);
    CValidDoc* CValidView::GetDocument() // non-debug version is inline
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CValidDoc)));
    return (CValidDoc*)m_pDocument;
    #endif //_DEBUG
    // CValidView message handlers
    void CValidView::OnOK()
    {
        if (UpdateData(TRUE))
        {
            MessageBox("Wager placed");
            m_btnenable=FALSE;
            UpdateData(FALSE);
        }
    }

    程序清单:定制的DDX/DDV过程
    #include <stdafx.h>
    // Custom Exchange
    void DDX_EnableWindow(CDataExchange *pDX, int id, BOOL &flag)
    {
        CWnd *ctl=pDX->m_pDlgWnd->GetDlgItem(id);
        if (pDX->m_bSaveAndValidate)
            flag=ctl->IsWindowEnabled();
        else
            ctl->EnableWindow(flag);
    }
    // Custom validator
    void DDV_MinMaxCurrency(CDataExchange *pDX, float val, float min, float max)
    {
        CWnd *editctl=CWnd::FromHandle(pDX->m_hWndLastControl);
        CString s;
        int n;
        // Using math to decide if anything is left over is bad because of rounding
        // errors, so use a string method instead
        editctl->GetWindowText(s);
        n=s.Find('.');
        if (n!=-1 && n+3<s.GetLength())
            {
            AfxMessageBox("Please enter the data to the nearest penny!");
            pDX->Fail();
            }
        DDV_MinMaxFloat(pDX,val,min,max); // let the existing one do the job
    }


    与Class Wizard集成
       如果你只想把某定制过程应用于一个项目的话,可以把它添加到该项目的CLW文件.你也可以在包含mfcclwz.dll文件的BIN目录(我的是...\Microsoft Visual Studio\Common\MSDev98\Bin)下创建一个DDX.CLW文件,然后你的DDX过程就可以应用到所有项目了.
       下面来看一看怎样写CLW文件:
    首先添加一个名为[ExtraDDX]的区段,看起来象INI文件的区段,但是这里的名称是区分大小写的.
    [ExtraDDX]
    ExtraDDXCount=2
    ExtraDDX1=E;;Value;Currency;0.0;Text;Floating Point Currency;MinMaxCurrency;Mi&nimum;f;Ma&ximum;f
    ExtraDDX2=bBECcRLIMNn;;Enable State;BOOL;TRUE;EnableWindow;Window Enabled Status
    这些代码是什么意思呢?
    第二行ExtraDDXCount=x的x表示项目的数目(这里是2),然后接下来的一行以ExtraDDX1=开头,再下来是ExtraDDX2=、ExtraDDX3=等等。等号右边的代码被分成7个、10个或者12个域,具体倚赖于你所想实现的目标,每个域以分号分隔,下面的表格列出了这些域的意思:

     
    1 DDX应用的空间类型(比如E=编辑框)
    2 未使用
    3 属性类型(经常是值,对应着Class Wizard的第一个组合框)
    4 变量的数据类型
    5 初始值
    6 没有DDV_前缀的DDV过程名
    7 注释
    8  
    9 第一个DDV参数的名称(可选)
    10 第一个DDV参数的类型(比如,f=float;可选)
    11 第二个DDV参数的名称(可选)
    12 第二个DDV参数的类型(比如,f=float;可选)

       你不必指定任何DDV过程,你可以把一个新的验证过程与标准的交换函数混合在一起(也就象上面ExtraDDX1那一行所做的一样).注意,这些DDX和DDV函数名并没有以DDX_和DDV_开头,但是Class Wizard确实往它产生的代码中添加了这些前缀.这也就是用这些前缀命名函数的原因了

  • 相关阅读:
    P3811乘法逆元
    P4549裴蜀定理
    备用代码区
    其他板子整理
    DP
    图论板子整理
    约数
    浅谈假学习假努力
    质数
    P1019 单词接龙
  • 原文地址:https://www.cnblogs.com/dongzhiquan/p/1994573.html
Copyright © 2020-2023  润新知