现在的位置: 首页 > 综合 > 正文

DDX双精度或浮点数为特定格式

2013年12月23日 ⁄ 综合 ⁄ 共 2504字 ⁄ 字号 评论关闭
一客户要求定制一对话框,显示几个数据,本以为几分钟就能搞定的事,却突然被一要求砸晕:客户要求其中一编辑框显示百分比,而且小数点必须是两位,也就是是说,如果是百分比为0的话,就要显示0.00。虽然情急之下用CString来关联编辑框,加上Format成员函数和scanf函数,也很快搞定。但也惊出一身冷汗,发现原来最简单的东西下面还有不简单啊。
后仔细查阅资料,并翻看MFC源码,发现确实没有简单的方法来实现。用CString作为变量,再定义一double变量,再转换,这种方法也颇为可行,但是有一点,要自己添加判断字符串是否是double类型数字,即简单的验证数据,有点麻烦。
查查源码,可以发现MFC的DDX_Text(CDataExchange* pDX, int nIDC, double& value)和其它的几个DDX_Text的内部实现不同,甚至于实现的文件也不同,分别在dlgfloat.cpp和dlgdata.cpp中
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, double& value)

{

    AfxTextFloatFormat(pDX, nIDC, &value, value, DBL_DIG);

}


void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, DWORD& value)

{

    if (pDX->m_bSaveAndValidate)

        _Afx_DDX_TextWithFormat(pDX, nIDC, _T("%lu"), AFX_IDP_PARSE_UINT, &value);

    else

        _Afx_DDX_TextWithFormat(pDX, nIDC, _T("%lu"), AFX_IDP_PARSE_UINT, value);

}
追踪AfxTextFloatFormat的实现如下:

void AFXAPI AfxTextFloatFormat(CDataExchange* pDX, int nIDC,

    void* pData, double value, int nSizeGcvt)

{

    ASSERT(pData != NULL);
    HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);

    TCHAR szBuffer[32];

    if (pDX->m_bSaveAndValidate)

    {

        ::GetWindowText(hWndCtrl, szBuffer, _countof(szBuffer));

        double d;

        if (!_AfxSimpleFloatParse(szBuffer, d))

        {

            AfxMessageBox(AFX_IDP_PARSE_REAL);

            pDX->Fail();            // throws exception

        }

        if (nSizeGcvt == FLT_DIG)

            *((float*)pData) = (float)d;

        else

            *((double*)pData) = d;

    }

    else

    {

        _stprintf(szBuffer, _T("%.*g"), nSizeGcvt, value);

        AfxSetWindowText(hWndCtrl, szBuffer);

    }

}
可以发现其实我们只要改动

_stprintf(szBuffer, _T("%.*g"), nSizeGcvt, value);        

AfxSetWindowText(hWndCtrl, szBuffer);

这部分代码就可以实现我们的目的了。
1.新建一测试工程tddx

2.在对话框模板中添加一编辑框,关联双精度变量double m_fPercent

3.添加自定义的数据交换函数
extern void AFXAPI AfxTextFloatFormat(CDataExchange* pDX, int nIDC,

    void* pData, double value, int nSizeGcvt);
void CTddxDlg::DDXEx_Text(CDataExchange *pDX, int nIDC, double &value, LPCTSTR lpszFormat)

{

    if(pDX->m_bSaveAndValidate){

        AfxTextFloatFormat(pDX, nIDC, &value, value, DBL_DIG);

    }

    else{

        HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);

        CString str;

        str.Format(lpszFormat, value);

//        _stprintf(szBuffer, _T("%.*g"), nSizeGcvt, value);

        ::SetWindowText(hWndCtrl, str);

    }

}

这里AfxTextFloatFormat被定义为全局函数,所以我们只需要导入即可。

4.修改DoDataExchange如下:

void CTddxDlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CTddxDlg)

//    DDX_Text(pDX, IDC_EDIT_PERCENT, m_fPercent);

    //}}AFX_DATA_MAP

    DDXEx_Text(pDX, IDC_EDIT_PERCENT, m_fPercent, "%0.2f");

}
运行即可发现已经实现目标如果在编辑框中输入非数字,会发现有错误提示。
差点忘了,由于DBL_DIG的存在,需要#include <float.h>

抱歉!评论已关闭.