Home > Net >  C MFC - CEdit / EDITTEXT Control - only allow certain chars
C MFC - CEdit / EDITTEXT Control - only allow certain chars

Time:08-05

I am using Visual Studio Professional 2017 C with MFC


I have a CEdit object in my MFC project which also has an EDITTEXT control in my .rc file.

The CEdit object will be edited by the user who will type a keyword, and I will do something with that keyword, that is, find files that contain that keyword.

Naturally, due to my task, I cannot allow the following char s: \ / : * ? " < > | , since these chars are not allowed to be in a file or folder name.

What can I do to prevent a user from entering these characters into the CEditBox. Realistically, the only chars I will need are: A-Z, a-z, 0-9, and _.

Another specification: no regex please ! Ideally the answer will use a Control (I looked here) or function (I looked here) I may have overlooked.

If there is no solution, I will fall back to this:

I will check whether any of these chars are in the text the user entered. If no, awesome, nothing to worry about ! If yes, then I will return an error :)

Thank you in advance ! :D

CodePudding user response:

I suggest you switch to using the CMFCMaskedEdit class instead of CEdit. It supports exactly the behavior you are after.

CodePudding user response:

I can think of two possible solutions to your question. The 1st solution posted just below is the easiest to implement because it does not require subclassing the control.

1st Solution - Control Notification

Edit controls send the EN_UPDATE notification, just before the (updated) text is about to be displayed. You can capture this event easily: open the Resource Editor, go to the dialog, select the edit conrol and in the Properties Editor go to Control Events page and Add the EN_UPDATE handler. The editor will add the handler to the message-map and generate the function:

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

In the generated function add the following code:

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\\ / : * ? \" < > | "));
    }
}

This will remove the illegal characters and will display a balloon tip, like when entering an illegal character while trying to rename a file in File Explorer. It's tested and works.

Alternative Solution - Subclassing

Another solution is possible, employing a subclassed control class:

  • Define a CEdit-derived class.
  • Add a handler for the WM_CHAR message.
  • In the WM_CHAR handler, if an illegal character is about to be entered, beep and display the balloon, but do NOT call the default, otherwise call it.

So the code could be:

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);
}

You may want to add a handler for the WM_PASTE message too.

Then you have to use it in your dialog, just use the Class Wizard to add a member variable of the derived edit class, associated with the edit control. It can be easily reused in another project.

  • Related