Introduction

Ever been bothered by message boxes popping up after entering a value in an edit field, telling you that the value is out of range? Or ever got annoyed by a masked edit field while trying to correct a character in the middle of the formatted string? Maybe this approach will give you the solution you where looking for.

The CAutoEdit class is derived from the normal CEdit class.

With the method SetValidChar, you can define which characters may be entered by the user, e.g. numeric characters only, or numeric characters, decimal point and sign, or the characters valid for representing a hexadecimal string. The method SetMaxChar lets you define the maximal number of characters expected in this field. Is this number reached, the focus is automatically set to the next field, allowing efficient data capturing. The next method SetExitChar lets you define one additional character which will be used to leave this field, just as pressing the TAB would. This is handy where you want to use the decimal point to skip to the next field etc.

Now the real invention is the error handling: CAutoEdit is using a validation interface class CEditValidate with a virtual function validate. This class can be attached to the CAutoEdit with the method SetValidationHandler. Whenever the CAutoEdit loses the focus, the validation method of the attached validation interface class is called. Here the contents of the field are validated, formatted and if necessary an error message set. If an error message is generated, two things will happen:

The focus stays in the erroneous field and the contents will be selected.

The error message is displayed in a little window just above the faulty field. The class CInfoWnd is used for this.

This behavior allows the user to fix the problem without having to get rid of a message box first and trying to remember the message. The message is right there and will only disappear after the field has been corrected. The user will not be able to select any other field before the problem is corrected with the exception of the cancel button.

There are some other methods to define the behavior of the signs, null padding etc., which I will not describe in detail, they are simple to use and easy to understand.

In order to use this class in you own project, you have to include the files autoedit.h, autoedit.cpp, infowmd.h and infownd.cpp. In your dialog, change your CEdit fields to CAutoEdit and add the initialization in the OnInitDialog:

//
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set up the behaviour for each edit field// leave the field after 2 (valid) characters have been entered
m_Edit1.SetMaxChars(2);
// allow all numeric characters
m_Edit1.SetValidChar(_T("0123456789"));
// create a validation interface
m_dayValidate = new CDayValidate;
// set the validation handler
m_Edit1.SetValidationHandler(m_dayValidate);
// start with this value
m_Edit1.SetDefaultValue(_T("01"));
// move the default into the field
m_Edit1.SetText();
m_Edit2.SetMaxChars(2);
m_Edit2.SetValidChar(_T("0123456789"));
m_monthValidate = new CMonthValidate;
m_Edit2.SetValidationHandler(m_monthValidate);
m_Edit2.SetDefaultValue(_T("01"));
m_Edit2.SetText();
m_Edit3.SetMaxChars(4);
m_Edit3.SetValidChar(_T("0123456789"));
m_yearValidate = new CYearValidate;
m_Edit3.SetValidationHandler(m_yearValidate);
m_Edit3.SetDefaultValue(_T("2000"));
m_Edit3.SetText();
m_Edit4.SetMaxChars(8);
m_Edit4.SetValidChar(_T("10"));
m_binValidate = new CBinValidate;
m_Edit4.SetValidationHandler(m_binValidate);
return TRUE; // return TRUE unless you set the focus to a control
}
//

Of course there are many possible improvements to this class, feel free to use and enhance it, just don't forget to share it here :-)

Problems

There are a few problems worth mentioning, maybe someone finds a (simple?) solution: For one, when a InfoWnd displays a message and the dialog is moved, the InfoWnd does not follow the dialog. The other problem is that pressing the 'Enter' key closes the dialog, even if there is still a invalid value in one of the CAutoEdit fields.

Note: There is one thing to know: You can not have the cancel button immediately following a CAutoEdit field in the TAB order, otherwise the validation will not work. The reason is that the cancel button is passed to the OnKillFocus method as the next control. This is used to determine if the user has cancelled the dialog and I can not determine if the user pressed the button or the focus is just passed there because it is the next control in line.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

Professional IT developer since 1983. First projects with Cobol, then Pascal, Modula2, C and since Visual C++ 1.0 also with C++. Works since 1986 as Consultant, between 1990 and 2008 for Infobrain in Switzerland, from 2008 until 2013 for enValue (also Switzerland) and currently I'm working for Comfone (Bern, Switzerland).

Comments and Discussions

Hi i'm using CAutoEdit to manage my Edit Control, i would use decimal number separed by points. I put the '.' in the list but when i press it within a Edito control i get the same effects of TAB pressure.
Anyone can helpme to findo solutions?
Thanks!
Matteo

Hi i'm using CAutoEdit to manage my Edit Control, i would use decimal number separed by points. I put the '.' in the list but when i press it within a Edito control i get the same effects of TAB pressure.
Anyone can helpme to findo solutions?
Thanks!
Matteo

I don't know if it's just me, but when I created a dialog with 20 CAutoEdit controls
it would take a few seconds to come up. I traced it down to the m_pInfoWnd->Create()
method in CAutoEdit::PreSubclassWindow(). Is there any way of speeding this up?

I'm a bit of a newbie at Windows programming, so bear with me if this is a simple problem. I have added your autoedit class to my project and it works great. However, I want my parent dialog to be notified when the user enters something so that it can read the new contents after it has been validated. I replaced "ON_CONTROL_REFLECT" with "ON_CONTROL_REFLECT_EX" which is supposed to pass the notification on to the parent after the child is done (if the child handler returns TRUE). The handler in the subclass is called, but the parent's handler is not called. The parent dialog has the following in the message map:
ON_EN_KILLFOCUS(IDC_IM2_VALUE, OnKillfocusIm2Value)
and the associated function OnKillfocusIm2Value(). What am I doing wrong?

Nice work but the demo program freezes for a few seconds then crashes if the dialog is closed while the date field has a invalid year. By 'closed' I mean the pressing of the Esc key or the close button in the dialog's title bar.

I have a similar problem with my code. (I was hoping your's would give a solution.) The problem in my code is that when closing a dialog OnClose is called before OnKillFocus. This results in the window being closed before you are able to check for a valid range. (When the Ok button is pressed OnKillFocus is called before OnOk.)

Your class is top class!! I am using it. Thanks. Especially I liked the way you have provided the Validate interface, allowing us to customise it.

It gives pleasure to find bug in some one's code!!

Bug1:
In your test, in the edit-field where I can type binaries, I am not able to type any alphabet. Fine. But I am able to paste any text. Hence eventually I am able to get a non binary number over there!!

Workaround:
Right now as a work around, inside OnKillFocus() before asking the validater to validate, I am checking each charecter in the edit field -> "Whether every charecter present in the edit-field is a permissable charecter, if the answer is 'no' then like you did, I select all the text and pop up the window".

I do not like this work-around, what I would prefer is, when the user tries to paste it, as the text in the clipboard has non valid charecter, user should hear a BEEP and text should not be pasted. As I am just one month old to MFC, I do not know how to intersept clip-board events.

Bug2: ??
I have 3 AutoEdit instances in a dialog and one instance of a Validater. All the 3 AutoEdits has reference to the same Validater. All my validater does is, returns the string "Empty!" if the input string is empty. To start with all the edit fields are empty. By clicking mouse, I place cursor in one edit-field. Without filling anything, I pressed the tab-key. I see "Empty!" window exactly over two(not 3) edits. Now I am able to edit these two edits simultaneously. By making them empty, from the second edit-field, if I press tab-key again, I see the third "Empty!" window. Now I can edit any one of these 3 edit fields. (Ofcourse, I am not able to Click on OK button.)

Note: in the above, ' "Empty!" window ' I mean, your red-window with the content "Empty!". (window is not empty).

If all the 3 edits have popuped with the red windows I will be able to tell my Boss it is the feature. How to get rid off this bug? (I am using Window2K).

I will be happy if these two bugs are removed. Waiting for your reply eagerly.

A while back, you posted a question on the CAutoEdit example from CodeProject - how to intercept a Clipboard text so that invalid text would not be pasted into a CEdit control with validation.

Did you get a solution?

Here is what I'm thinking. Process the CEdit::OnCommand(WPARAM, LPARAM) messages and then look at the case when wParam is WM_PASTE -- here is an example based upon a CodeProject example entitled MenuEdit (Context Menus)

Daniel sits right next to me.
So it's a bit overkill to post a small bugfix here.
But for all those using the class here's a small fix
for setValidChar().
In case one of the chars is equal to 'm_nExitChar'
it's not possible to leave the field. So I reset
the exit char to the tab key.

I tried your sample executable on Win95 and seems to me there's a bug in it:
After entering a binary digit not beginning with 1 and pressing TAB
to cause the tooltip to appear, just hit ENTER: The tooltip
text dissapears and the thing seems to go mad.

Take it easy, man. Didn't mean to be offensive, if that has been
your impression. As a programmer *that hasn't taken a look at
the code* I cannot be much more specific: the application
gets unresponsive and finally I got to kill it via CTRL+ALT+SUPR.
Try it yourself to see what I mean.

By no means I was offended, I just can't reproduce the problem and 'gos mad' didn't help me much .
That it hangs, is much more specific.
Guess I'll have to try it on different configurations.
Regards Daniel

It's an interesting idea, but I'm not sure if I'd recommend it, at least not the way it's implemented here.

Firstly, an edit box is just that -- it's an area that allows you to edit an entry of information. While you're editing the data, you know that it won't necessarily be valid. So, to have it popping up with text telling you it's invalid during edit might become annoying. I prefer Microsoft's approach in Word where incorrect spellings are underlined when you LEAVE the area (or press space, in that case).

Secondly, modal is old-hat. I hate modal! When you're editing, if you get it wrong, it doesn't let you leave the edit box until you get it right. Regardless of whether you want to go and do something else and come back to it later, it stops you! Arrghh! That's probably the most annoying feature. Instead, it should work with you -- not against you. It should kindly remind you that it's invalid by turning it red, or underlining it (perhaps), and then popup the tooltip only when you mouse over it or return focus to the area.

Thirdly, tooltips like this one obscure other regions of the entry box -- and you can't get rid of it. Again, it would be better if it would only popup when you mouse over...

Perhaps someone would like to product a squiggly underline implementation instead?

I think both implementations are useful for different applications. Whether you misspell something in Word does not have any effect on world peace. Then a notification of possible errors is more than sufficient. When, on the other hand, you enter important data that cannot be wrong, there must be a mechanism to handle
this. Then the covering of other parts of the dialog is unimportant compared to ensuring correct data input.

Hi John,
I agree to a certain extend. The chosen solution of the spell checker in WinWord is very convenient. But then again it does not mark errors, it just marks possible errors ! The user might still decide that the spelling is correct.
Edit fields often contain different kind of information, e.g. it must be a number between 1 and 100, it must be a string of at least 8 characters, it must start with a capital letter etc. The validation is set, if not the approach described in my edit control is the wrong solution for that particular information.
You hate modal... lets have a look at the alternative : You enter all fields, you make the one or other mistake. But there is one point in time, where the entered information must be checked, e.g. when you leave the dialog. At this time you have to inform the user about his/her mistake(s) and ask for corrections. How do you solve that ? Showing a message box giving the user information about the error ? The user clicks it away and searches for the field in question (Oh, what was the message again?), corrects it and tries to leave the dialog again. Now you show the next error...
You can always leave the dialog using the cancel button or the ESC key, even if the current field is in error, just like the normal behaviour or a dialog.
The ToolTip should not obscure any important region of your screen, you can tell the infownd where to show up.
Personally I do like it, when I get a information about my errors right then and there, I correct them and continue. Rather than have to go through a number of fields again later because the data can not be accepted by the application.

The time when the data is checked should be when you click OK. That's what the OK button is for: "The form is OK now and I'm ready to send it". At this point it should be validated, and any errors should stop the form from closing and should display the error in a status bar beside the buttons -- momentarily flashing it red to alert the user, for example. Focus should then be set to the first field in error. If then want to abort the process, they click cancel. At least, this is the way we've been doing it in our products for the past 10 years.

If you could combine this with underlining the fields that are in error, and have a tooltip appear displaying the actual error when you mouse over the textbox, then I think that would be an improvement.

Kinda reminds of how we use to program those ol' dumb terminals, back about 15 or 20 years ago.;)
Your point though is quite valid and should be followed where ever it makes sense. But I have come up against situations where it does not make sense. For instance, consider a heads-down, high speed data entry operation where data is being transcribed from paper to dialogs. Usually, the person entering the data is wanting to be alarmed of the very first wrong key that they have typed and so 'immediate editting', (my own term!) can be extremely useful and can enhance an operators ability to perform efficiently.

That's quite a specific type of application. I'm still not convinced of your argument though. If they are entering tons of data very fast then -- ok -- maybe they need to be told as soon as they make an error. Well, to be honest I don't think so. Most people in that category type while staring at the keyboard, not the screen. If they make an error in a field then they'll happily be continuing to type along the rest of the data -- except in this instance they won't realize that their keystrokes are a waste of time because they're modally stuck in the field in which the error occurred.

What I'm suggesting is that it BEEPS as soon as they leave the field in error, and underlines the erroneous data. Or even paints its background red. That way when they finish the line they're entering in, they get an indication, they go back to the field in which the error occurred, correct it and carry on as before.

When I'm entering data, I just type everything as fast as possible. I forget about errors. Then, when I finish, I go back and correct all the errors. That way I get things done far more quickly, because I know that most of the time I will get the entry correct. If I have to switch between entry to validation to correction mode over and over again then it becomes a huge distraction and I cannot work as fast.

Hi there,
Seriously I did think about it... but patent something like that will kill it. And thats really not the idea. It would be nice if things like this become standard.
Personally I strongly object that it is possible to patent simple ideas, which did not need any investment like large amount of capital or time to develop.
Of course if MS or Linus want to contribute some Millions, I will gladly tell then my account number
Regards Daniel