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 char
s 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 char
s 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 char
s 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.