// m_age is int
DDX_Text(pDX, IDC_AGE, m_age);
DDV_MinMaxInt(pDX, m_age, 1, 120);
虽然 DDX 工作表现得很好,DDV 是不免有点老土。MFC
在有效性验证方面所能做到的很有限。你可以在文本域中限制数字字符,不同类型的最小/最大约束。最小/最大是不错,但如果你想验证邮编或电话号码怎么办?MFC
对此无能为力。你不得不编写自己的 DDV 函数。当我第一次用正则表达式实现有效性验证时,我只要写一个函数即可,就像这样: 逆风者
void DDV_Regex(CDataExchange* pDX, CString& val,
LPCTSTR pszRegex)
{
if (pDX->m_bSaveAndValidate) {
CMRegex r(pszRegex);
if (!r.Match(val).Success()) {
pDX->Fail(); // throws exception
}
}
}
这使你很容易象下面这样用正则表达式验证输入:
// in CMyDialog::DoDataExchange
DDX_Text(pDX, IDC_ZIP, m_zip);
DDV_Regex(pDX, m_zip,_T("^\\d{5}(-\\d{4})?$"));
好酷啊,仅用四行代码就搞掂。(当然,那要假设你有 RegexWrap——否则你得使用托管扩展直接调用框架 Regex
类。)DDV_Regex 在 MFC 的 DDX/DDV 方案中工作表现很完美,但是当我开始添加更多的域时,我马上发现一些 DDX/DDV
的主要缺点,其一,如果域输入无效,则每个 DDV
函数都显示一个出错消息框并丢出异常,那么要是有五个无效域,用户就会看到五个消息框——真实糟透了!此外,在对 DDV
的调用中,我不想将正则表达式写死在代码中。但我拒绝 DDX/DDV 的主要理由是它太程序化。为了验证新的域,你不得不添加另外的数据成员以及在
DoDataExchange 加更多的代码,不久这个函数便膨胀臃肿,就像下面这样:
DDX_Text(pDX, IDC_FOO,...);
DDV_Mumble(pDX, ...)
DDX_Text(pDX, IDC_BAR,...);
DDV_Bletch(...)
... // etc for 14 lines
为什么我非得要墨守成规编写过程指令来描述固有的验证规则呢?我的五条编程最高准则之一是:拒斥程序化代码。另一个是:一个表格胜过一千行代码。你肯定猜到我要干什么了。最终,我编写自己的对话框验证系统,一个基于规则的、表格驱动的验证系统。它依靠在
DDX 的最上层,但废掉了 DDV
并有好得多的用户接口。当然,它还易于使用,借助正则表达式进行验证。所有细节都封装在一个类中,CRegexForm,你可以在任何 MFC
对话框中使用这个类。

Figure 1 TestForm 里的工具提示
与往常一样,我编写了一个测试程序来示范它的工作原理。初看起来,TestForm 有点像再平常不过的基于 MFC
的对话框程序。它的主对话框中有几个编辑框——邮编、SSN(社会保险号),电话号码等。但当你通过对 TestForm
的测试,你会很快认识到它蕴含着许多玄机。如果你用tab键在输入域间移动,TestForm 会显示一个工具提示,它描述在这个输入域能输入什么(如图
Figure 1)。如果你敲入了一个非法字符——例如,在电话号码输入域敲入一个字符——TestForm
将拒绝接受该字符并发出蜂鸣声。当你按下确认键或OK键,你会得到一个描述所有无效输入域的出错信息框,如图 Figure 2
所示。所有的错误都显示在一个消息框中,而不是每个错误一个消息框。接着当用户tab到其中一个无效输入域时,TestForm
会再次在对话框本身的一个应用程序提供的“反馈”窗口内显示出错信息(如 Figure
3),因此用户不必记住错误信息所描述的内容,当他们更正每个无效输入域时,窗体会提醒他们。如果只有一个输入域无效,TestForm
会放弃消息框而直接在“反馈”窗口显示错误信息。

Figure 2 集中显示出错的输入域
所有这些神奇的特性都是由 CRegexForm 自己实现的。你只需使用它即可,使用方法相当直白,首先你得定义一个自己窗体。下面是
TestForm 的窗体内容,这些定义位于 MainDlg.cpp:
本文章更多内容:<<上一页 - 1 - 2 - 3 - 4 - 5 - 6 - 下一页>> |