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

Hus*_*kfa 1 c++ user-interface controls mfc cedit

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


我正在使用 Visual Studio Professional 2017 C++ 和 MFC


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

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

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

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

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

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

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

先感谢您 !:D

Con*_*iou 6

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

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

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

BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
    .
    .
    ON_EN_UPDATE(IDC_EDIT_FNAME, &(CMyDialog::OnEnUpdateEditFname)
END_MESSAGE_MAP()
Run Code Online (Sandbox Code Playgroud)

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

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:\n\t\\ / : * ? \" < > | "));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

替代解决方案 - 子类化

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

  • 定义一个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:\n\t\\ / : * ? \" < > | "));
    }
    else CEdit::OnChar(nChar, nRepCnt, nFlags);
}
Run Code Online (Sandbox Code Playgroud)

您可能还想为该消息添加一个处理程序WM_PASTE

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


编辑:

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

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

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

注意:和(THCAR.H 版本的和)是 CRT_tcspbrk()函数。人们可以选择使用or和函数- 顺便说一句,那里有许多有用的实用函数。_tcschr()strpbrk()strchr()StrPBrk()StrCSpn()StrChr()Shlwapi