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

一客户要求定制一对话框,显示几个数据,本以为几分钟就能搞定的事,却突然被一要求砸晕:客户要求其中一编辑框显示百分比,而且小数点必须是两位,也就是是说,如果是百分比为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>

你可能感兴趣的:(exception,测试,null,mfc,float)