C++MFC-CEdit/EDITTEXT控件-只允许某些字符



感谢您的回答和评论。我选择了我选择的答案,因为它允许我继续使用CEdit,只需对代码进行一些小的更改。然而,考虑CMFCMaskedEdit的解决方案在测试时似乎也同样有效。如果您选择使用该解决方案,请确保在初始化时为对象应用正确的函数,如SetValidChars等!:)再次感谢大家


我正在使用带有MFC 的Visual Studio Professional 2017 C++


我的MFC项目中有一个CEdit对象,该对象在我的.rc文件中也有EDITTEXT控件。

CEdit对象将由键入关键字的用户编辑,我将对该关键字执行一些操作,即查找包含该关键字的文件

当然,由于我的任务,我不能允许以下char/:*?"<>|,因为这些char不允许在文件或文件夹名中。

我该怎么做才能防止用户将这些字符输入到CEditBox中。实际上,我只需要chars:A-Za-z0-9_

另一个规格:请不要regex理想情况下,答案将使用我可能忽略的Control(我在此处查看)或function(我在这里查看)。

如果没有解决方案,我会回到这个:

我将检查这些char是否在用户输入的文本中。如果没有,太棒了,没什么好担心的!如果是,那么我将返回一个错误:)

提前感谢!:D

对于您的问题,我可以想出两种可能的解决方案。下面发布的第一个解决方案是最容易实现的,因为它不需要对控件进行子类化。

第一个解决方案-控制通知

编辑控件在即将显示(更新的)文本之前发送EN_UPDATE通知。您可以很容易地捕获此事件:打开资源编辑器,转到对话框,选择编辑控件,然后在属性编辑器中转到控制事件页面并添加EN_UPDATE处理程序。编辑器将把处理程序添加到消息映射中,并生成函数:

BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
.
.
ON_EN_UPDATE(IDC_EDIT_FNAME, &(CMyDialog::OnEnUpdateEditFname)
END_MESSAGE_MAP()

在生成的函数中添加以下代码:

void CMyDialog::OnEnUpdateEditFname()
{
CString s;
GetDlgItemText(IDC_EDIT_FNAME, s); // Get the control's text - may contain illegal characters

// First illegal character position
int nFIChar = -1;
// Loop until all illegal chars are removed - will also work for a paste operation w/ multiple illegal chars
while (LPCTSTR p = _tcspbrk(s, _T("\/:*?"<>|")))
{
if (nFIChar<0) nFIChar = p-s; // Store 1st illegal char position
s.Remove(*p);   // Remove illegal char(s)
}
if (nFIChar>=0) // At least one illegal char found
{   // Replace the control's text and display a balloon
CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT_FNAME);
pEdit->SetWindowText(s);            // SetWindowText() will reset the caret position!
pEdit->SetSel(nFIChar, nFIChar);    // Set caret to the 1st illegal character removed
MessageBeep(-1);
pEdit->ShowBalloonTip(NULL, _T("A file name can't contain any of the following characters:nt\ / : * ? " < > | "));
}
}

这将删除非法字符并显示气球提示,就像在文件资源管理器中尝试重命名文件时输入非法字符一样。它经过测试并有效。

替代解决方案-子类

另一种解决方案是可能的,采用子类控制类:

  • 定义一个CEdit派生类
  • WM_CHAR消息添加一个处理程序
  • WM_CHAR处理程序中,如果要输入非法字符,请发出嘟嘟声并显示气球,但不要调用默认值,否则调用它

所以代码可能是:

BEGIN_MESSAGE_MAP(CFilenameEdit, CEdit)
ON_WM_CHAR()
END_MESSAGE_MAP()
void CFilenameEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (_tcschr(_T("\/:*?"<>|"), nChar))
{
MessageBeep(-1);
ShowBalloonTip(NULL, _T("A file name can't contain any of the following characters:nt\ / : * ? " < > | "));
}
else CEdit::OnChar(nChar, nRepCnt, nFlags);
}

您可能还需要为WM_PASTE消息添加一个处理程序。

然后,您必须在对话框中使用它,只需使用类向导添加派生编辑类的成员变量,该成员变量与编辑控件关联。它可以很容易地在另一个项目中重复使用。


编辑:

第一个解决方案(捕获EN_UPDATE通知)更容易实现(尽管这个示例中有更多的代码——第二个解决方案目前不处理粘贴操作),因为它不需要定义新的子类。这是开发人员处理特殊需求的选择,以便为项目快速实现它。

第二个解决方案定义了一个新的子类。它可以在另一个项目中重用——我倾向于使用可重用的代码——但它需要完成(也处理粘贴操作),然后进行维护。为了更有用,最好对其进行增强,例如使其更通用,比如为完全限定的路径/文件名添加一个选项(它们可能包含:"),或者更好地允许开发人员定义无效字符集-在这种情况下,显示的消息也应该由开发人员定义*,因为新类可以在更多情况下使用,而不仅仅是用于文件名或路径。因此,这最初需要更多的工作,最终是一个选择问题(更大的"前期投资",具有潜在的未来效益)。

*包含无效字符列表的消息的第二行应该通过类的代码以编程方式构建

注意:_tcspbrk()_tcschr()(strpbrk()strchr()的THCAR.H版本)是CRT功能。也可以使用Shlwapi中的StrPBrk()StrCSpn()StrChr()函数,这些函数都是有用的实用函数

我建议您改用CMFCMaskedEdit类而不是CEdit。它完全支持你所追求的行为。

最新更新