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