![]() |
Desktop Development »
Edit Controls »
Masked and Validating controls
Intermediate
License: The Code Project Open License (CPOL)
Validating Edit ControlsBy Alvaro MendezCEdit-derived classes which validate the most popular types of data input. |
VC6, Windows, MFC, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

Edit controls are often used to enter dates, times, currency values, or preformatted numeric data such as phone numbers. A control that allows its user to only enter a specific type of data is useful for several reasons:
The classes presented in this article provide these benefits for the most popular types of data that may be entered: dates, times, decimals, integers, currency amounts, formatted numerics, and restricted alphanumerics.
A while back I worked on a project which required edit controls with very strict behavior. One was a date control which needed to accept dates in mm/dd/yyyy format only. The user would be allowed to enter just the numbers and the slashes would be filled in automatically (unlike Microsoft’s Date control). The control would also prevent the user from messing up the format, by, for example, deleting the second character. Another edit control was used for entering dollar amounts and would automatically insert commas for the thousand’s separator.
I went on the hunt for a set of controls that would give me this behavior and I took a look at Masked Edit Control from Dundas Software. Unfortunately it wasn’t specific enough, especially when it came to dates. I needed more than just a masked control; I needed to make sure the value would always be valid. I also didn’t feel like spending time modifying or extending Dundas’s code to make it work like I needed it, so I took a big gulp and decided to do it all from scratch. What you see now is the result of that effort, which I finally got around to publishing. :-)
All classes derive from CEdit and are prefixed with CAMS (AMS are my company’s initials). The following table gives the class names and descriptions:
| Class Name | Description |
| CAMSEdit |
Base class for the classes below. It has some basic functionality. |
| CAMSAlphanumericEdit |
Prohibits input of one or more characters and restricts length. |
| CAMSNumericEdit |
Used to input a decimal number with a maximum number of digits before and/or after the decimal point. |
| CAMSIntegerEdit |
Only allows a whole number to be entered. |
| CAMSCurrencyEdit |
Inserts a monetary symbol in front of the value and a separator for the thousands. |
| CAMSDateEdit |
Allows input of a date in the mm/dd/yyyy or dd/mm/yyyy format, depending on the locale. |
| CAMSTimeEdit |
Allows input of a time with or without seconds and in 12 or 24 hour format, depending on the locale. |
| CAMSDateTimeEdit | Allows input of a date and time by combining the above two classes. |
| CAMSMaskedEdit |
Takes a mask containing '#' symbols, each one corresponding to a digit. Any characters between the #s are automatically inserted as the user types. It may be customized to accept additional symbols. |
| CAMSMultiMaskedEdit |
Takes a mask and adopts its behavior to any of the above classes. |
What follows is a more detailed description of these classes and their usage. All member functions are public unless otherwise specified.
I decided to give all my CEdit-derived classes a common base class for any common methods they may need. The result is this class which only has minor enhancements to the CEdit class, but serves as a pseudo-namespace for the Behavior classes used by the CAMSEdit-derived classes.
| Member | Description |
|
|
Sets the text for the control. This text is validated against the controls proper format. |
|
|
Retrieves the text in the control. |
|
|
Retrieves the text in the control without leading or trailing spaces. |
|
|
Sets the control's background color. |
|
|
Retrieves the control's background color. |
|
|
Sets the control's text color. |
|
|
Retrieves the control's text color. |
|
|
Returns true if the control is read-only. |
virtual bool ShouldEnter(TCHAR c) const; |
This protected member is called directly by all classes right before a typed-in character is to be shown. By default it always returns true. But you may override it (in a derived class) and make it return false if the user enters a character you don't want to allow. |
This class is used for general alphanumeric input with the exception of whatever characters you specify to not be allowed. So if you need to prevent certain characters from being entered, this class is useful. It can also restrict the length of the text.
| Member | Description |
|
|
Sets each of characters contained in the given string to not be allowed for input. By default these characters are not allowed: %'*"+?><:\ |
|
|
Retrieves the characters not allowed for input. |
|
|
Sets the maximum number of characters allowed. By default there is no limit (0). |
|
|
Retrieves the maximum number of characters allowed. |
This is the base class for all numeric entry classes. It ensures that the user enters a valid number and provides features such as automatic formatting. It also allows you to restrict what the number can look like, such as how many digits before and after the decimal point, and whether it can be negative or not.
| Member | Description |
|
|
Sets the control's text to the given double value. If bTrimTrailingZeros is true, any insignificant zeros after the decimal point are removed. |
|
|
Returns the current text as a double value. |
|
|
Sets the control's text to the given integer value. |
|
|
Returns the current text as an integer value. |
|
|
Sets the maximum number of digits before the decimal point. This is 9 by default. |
|
|
Retrieves the maximum number of digits before the decimal point. |
|
|
Sets the maximum number of digits after the decimal point. This is 4 by default. |
|
|
Retrieves the maximum number of digits after the decimal point. |
|
|
Sets a flag to allow a negative sign or not. By default negatives are allowed. |
|
|
Determines whether a negative sign can be entered or not. |
|
|
Sets the size of the groups of digits to be separated before the decimal point. This is 0 by default but is typically set to 3 to separate thousands. |
|
|
Retrieves the number of digits per group shown before the decimal point. |
|
|
Sets the character to use for the decimal point and the group separator (thousands) |
|
|
Retrieves the character being used for the decimal point and group separator (thousands). |
|
|
Sets the characters to automatically display in front of the numeric value entered. This is useful for displaying currency signs. By default it is empty. |
|
|
Retrieves the characters to automatically display in front of the numeric value entered. |
|
|
Parses a string containing '#', comma, and period characters to determine the format of the number that the user may enter. For example: #,###.# means: (1) allow up to 4 digits before the decimal point, (2) insert commas every 3 digits before the decimal point, (3) use a dot as the decimal point, and (4) allow up to one digit after the decimal point. |
|
|
Retrieves a string containing '#', comma, and period characters representing the format of the numeric value that the user may enter. |
|
|
Sets the range of valid numbers values allowed. By default it's |
|
|
Retrieves the range of valid numbers allowed. |
|
|
Returns true if the number is valid and falls within the allowed range. |
|
|
Returns true if the number is valid and optionally shows an error message if not. |
|
|
Allows adding or removing flags from the control. This may used to set/clear the flags below to alter the behavior of the control: |
|
|
Inserts the decimal symbol automatically when the user enters a digit and all the whole numbers have already been entered. |
|
|
Automatically pads the number with zeros after the decimal point any time the text is changed (using SetWindowText or a key stroke). |
|
|
Automatically pads the number with zeros after the decimal point any time the text is set (using SetWindowText). |
|
|
Pads the number with zeros before the decimal symbol up to the max allowed (set by |
|
|
Pads the number with zeros after the decimal symbol up to the max allowed (set by |
|
|
When combined with any of the above two "Pad" flags, the value is not padded if it's empty. |
|
|
Beeps if the value is not a valid number. |
|
|
Beeps if the no value has been entered. |
|
|
Beeps if the value is not valid or has not been entered. |
|
|
Changes the value to a valid number if it isn't. |
|
|
Fills in a valid number value if the control is empty. |
|
|
Sets the value to a valid number if it's empty or not valid. |
|
|
Sets the focus back to the control if its value is not valid. |
|
|
Sets the focus back to the control if it doesn't contain a value. |
|
|
Sets the focus back to the control if it's empty or not valid. |
|
|
Shows an error message box if the value is not a valid number. |
|
|
Shows an error message box if it doesn't contain a value. |
|
|
Shows an error message box if its empty of not valid. |
This class is used to only allow integer values to be entered. It is derived from
This class is used for entering monetary values. It is also derived from CAMSNumericEdit but it sets the prefix to the currency sign specified in the locale (such as a '$'). It also separates thousands using the character specified in the locale (such as a comma). And it sets the maximum number of digits after the decimal point to two.
This class handles dates in a very specific format: mm/dd/yyyy or dd/mm/yyyy, depending on the locale. As the user enters the digits, the slashes are automatically filled in. The user may only remove characters from the right side of the value entered. This ensures that the value is kept in the proper format. As a bonus, the user may use the up/down arrow keys to increment/decrement the month, day, or year, depending on the location of the caret.
| Member | Description |
|
|
Sets the date value. |
|
|
Sets the date value. |
|
|
Sets the date value. |
|
|
Sets the date value to today's date. |
|
|
Retrieves the date (with zeros for the hour, minute, and second). |
|
|
Retrieves the date (with zeros for the hour, minute, and second). |
|
|
Retrieves the year. |
|
|
Retrieves the month |
|
|
Retrieves the day |
|
|
Sets the year. |
|
|
Sets the month |
|
|
Sets the day |
|
|
Returns true if the date value is valid. |
|
|
Returns true if the date is valid and optionally shows an error message if not. |
|
|
Sets the range of valid date values allowed. By default it's 01/01/1900 to 12/31/9999. |
|
|
Sets the range of valid date values allowed. |
|
|
Retrieves the range of valid dates allowed. |
|
|
Retrieves the range of valid dates allowed. |
|
|
Sets the character used to separate the date's components. By default it's a slash ('/'). |
|
|
Retrieves the character used to separate the date components. |
|
|
Overrides the locale's format and based on the flag sets the day to be shown before or after the month. |
|
|
Returns true if the day will be shown before the month (dd/mm/yyyy). |
|
|
Allows adding or removing flags from the control. This may used to set/clear the flags below to alter the behavior of the control when it loses focus: |
|
|
Beeps if the value is not a valid date. |
|
|
Beeps if the no value has been entered. |
|
|
Beeps if the value is not valid or has not been entered. |
|
|
Changes the value to a valid date if it isn't. |
|
|
Fills in a valid date value (today's date if allowed) if the control is empty. |
|
|
Sets the value to a valid date if it's empty or not valid. |
|
|
Sets the focus back to the control if its value is not valid. |
|
|
Sets the focus back to the control if it doesn't contain a value. |
|
|
Sets the focus back to the control if it's empty or not valid. |
|
|
Shows an error message box if the value is not a valid date. |
|
|
Shows an error message box if it doesn't contain a value. |
|
|
Shows an error message box if its empty of not valid. |
This class handles times in a very specific format: HH:mm or hh:mm AM, depending on the locale. Seconds are also supported, but not by default. As the user enters the digits, the colons are automatically filled in. The user may only remove characters from the right side of the value entered. This ensures that the value is kept in the proper format. As a bonus, the user may use the up/down arrow keys to increment/decrement the hour, minute, second, or AM/PM, depending on the location of the caret.
| Member | Description |
|
|
Sets the time value. |
|
|
Sets the time value using the time portion of the given date. |
|
|
Sets the time value using the time portion of the given date |
|
|
Sets the time value to the current time. |
|
|
Retrieves the time (with Dec 30, 1899 for the date). |
|
|
Retrieves the time (with Dec 30, 1899 for the date). |
|
|
Retrieves the hour. |
|
|
Retrieves the minute. |
|
|
Retrieves the second. |
|
|
Returns the AM/PM symbol currently shown on the control or an empty string. |
|
|
Sets the hour. |
|
|
Sets the minute. |
|
|
Sets the second. |
|
|
Sets the AM or PM symbol if not in 24 hour format. |
|
|
Returns true if the time value is valid. If |
|
|
Returns true if the time is valid and is in range, and optionally shows an error message if not. |
|
|
Sets the range of valid time values allowed. By default it's 00:00:00 to 23:59:59. Note: While the control has focus, the user will be allowed to input any value between 00:00:00 and 23:59:59, regardless of what values are passed to SetRange. |
|
|
Sets the range of valid time values allowed. |
|
|
Retrieves the range of valid times allowed. |
|
|
Retrieves the range of valid times allowed. |
|
|
Sets the character used to separate the time's components. By default it's a colon (':'). |
|
|
Retrieves the character used to separate the date components. |
|
|
Overrides the locale's format and based on the flag sets the hour to go from 00 to 23 (24 hour format) or from 01 to 12 with the AM/PM symbols. |
|
|
Returns true if the hour will be shown in 24 hour format (instead of 12 hour format with the AM/PM symbols). |
|
|
Sets whether the seconds will be shown or not. |
|
|
Returns true if the seconds will be shown. |
|
|
Overrides the locale's format and sets the symbols to display for AM and PM, which may be of any length but must both be of the same length. |
|
|
Retrieves the symbols to display for AM and PM into the given CString pointers. |
|
|
Allows adding or removing flags from the control. This may used to set/clear the flags below to alter the behavior of the control when it loses focus: |
|
|
Beeps if the value is not a valid date. |
|
|
Beeps if the no value has been entered. |
|
|
Beeps if the value is not valid or has not been entered. |
|
|
Changes the value to a valid date if it isn't. |
|
|
Fills in a valid date value (today's date if allowed) if the control is empty. |
|
|
Sets the value to a valid date if it's empty or not valid. |
|
|
Sets the focus back to the control if its value is not valid. |
|
|
Sets the focus back to the control if it doesn't contain a value. |
|
|
Sets the focus back to the control if it's empty or not valid. |
|
|
Shows an error message box if the value is not a valid date. |
|
|
Shows an error message box if it doesn't contain a value. |
|
|
Shows an error message box if its empty of not valid. |
ModifyFlags function.
| Member | Description |
|
|
Sets the date and time value. |
|
|
Sets the date and time value from the given |
|
|
Sets the date and time value from the given |
|
|
Sets the date and time value to the current date and time. |
|
|
Retrieves the date and time into a |
|
|
Retrieves the time and time into a |
|
|
Returns true if the date and time value is valid. |
|
|
Returns true if the date and time is valid and is in range, and optionally shows an error message if not. |
|
|
Sets the range of valid date values allowed. By default it's 01/01/1900 00:00:00 to 12/31/9999 23:59:59. |
|
|
Sets the range of valid time values allowed. |
|
|
Retrieves the range of valid times allowed. |
|
|
Retrieves the range of valid times allowed. |
|
|
Sets the character used to separate the date or the time components. By default it's a slash ('/') for the date, or the colon (':') for the time. |
|
|
Retrieves the character used to separate the date or the time components. |
|
|
Allows adding or removing flags from the control. This may used to set/clear the same flags in the |
|
|
Changes this class to only allow a date value, just like the |
|
|
Changes this class to only allow a time value, just like the |
This class is useful for values with a fixed numeric format, such as phone numbers, social security numbers, or zip codes.
| Member | Description |
|
|
Sets the format of the values to be entered. By default, each '#' symbol in the mask represents a digit. Any other characters in between the # symbols are automatically filled-in as the user types digits. Additional characters may be added to be interpreted as special mask symbols. See |
|
|
Retrieves the mask used to format the value entered by the user. |
|
|
Retrieves the control's value without any non-numeric characters. |
|
|
Retrieves a reference to the array of symbols that may be found on the mask. By default, this array will contain one element for the # symbol. Use this function to add, edit, or delete symbols (see the // Add the '?' symbol to allow alphabetic // characters. m_ctlMasked.GetSymbolArray().Add( CAMSMaskedEdit::Symbol('?', _istalpha)); // Add the '{' symbol to allow alphabetic // characters and then convert them to uppercase. m_ctlMasked.GetSymbolArray().Add( CAMSMaskedEdit::Symbol('{', _istalpha, _totupper)); |
This class is capable of dynamically taking on the behavior of any of the above classes based on the mask assigned to it. See SetMask below for more details. It contains not only it's own member functions but also those of the Alphanumeric, Numeric, Masked, and DateTime classes above. With such high overhead, I recommend you only use this class for controls which must dynamically change from one behavior to another at run time. The default behavior is Alphanumeric.
| Member | Description |
|
|
Sets the format of the values to be entered.
### or #,###.### (without foreign characters after the first #) then it's treated as a number; otherwise it's treated as a masked value (e.g., ###-####). |
|
|
Retrieves the mask used to format the value entered by the user. |
These classes are designed to be used inside CDialog-derived classes as replacements for the CEdit variables typically created with the ClassWizard. Here's what you need to use them inside your project:
CEdit variables. CEdit to one of the CAMSEdit-derived classes above. OnInitDialog handler to adjust any settings, such as initial values, ranges, etc. For example if you have a CAMSDateEdit class, you would probably want to set its date ranges using the SetRange member. Note: If you need to keep your executable as small as possible, you can change the AMSEDIT_COMPILED_CLASSES macro (defined in amsEdit.h) to compile just the classes you need to use. Also, if you want to build and export these classes in an MFC Extension DLL, look inside amsEdit.h for instructions.
Version 1.0
Apr 9, 2002
CAMSDateEdit whenever the date would appear in dd/mm/yyyy format. Thanks to spleen for reporting it.Apr 21, 2002
Version 2.0
Jan 28, 2003
CAMSTimeEdit class to allow input of time values. Many thanks to Paul Runstedler for providing me with his version of the class. CAMSTimeEdit class in action. CAMSDateTimeEdit class to allow input of date and time values in the same edit box. This class multiply inherits from the DateBehavior and TimeBehavior classes. OnKillFocus flags to the NumericBehavior class to allow padding of the value with zeros before and/or after the decimal point. This is especially useful when entering monetary values, so I added it to the CAMSCurrencyEdit class. Thanks to Spiros Prantalos for giving me the idea. NumericBehavior to automatically put a zero in front of values that start with a decimal symbol when the control loses focus (ie. ".69" becomes "0.69"). AddDecimalAfterMaxWholeDigits flag to allow the decimal point to be automatically inserted when the user enters a digit and all the whole numbers have already been entered. Thanks to Spiros Prantalos for giving me the idea. IsValidMonth). Thanks to Hakon for reporting it. GetTrimmedText to the CAMSEdit class. Thanks to Paul Runstedler for providing me with his code. GetTextAsLong and GetTextAsDouble functions with GetInt and GetDouble inside the CAMSNumericEdit class (which propagates to the CAMSIntegerEdit and CAMSCurrencyEdit classes). I also added SetInt and SetDouble to make it easy to set the text to an int or double value. Feb 14, 2003
IsReadOnly to CAMSEdit and fixed a bug that was allowing input even when the control was read-only. Thanks to solopido for reporting it.Mar 4, 2003
NumericBehavior class. This means that if a range has been set and any of the OnKillFocus flags are set, the value will be verified when the control loses focus. Thanks to Anatoly Sidorov for requesting it. NumericBehavior) -- the decimal symbol and the thousand's separator. Thanks to João Paulo Figueira for giving me the idea. NumericBehavior's value to be refreshed unnecessarily and thus causing extra EN_CHANGE messages to be sent. Thanks to Anatoly Sidorov for reporting it. TimeBehavior.Sep 25, 2003
Version 3.0
Mar 18, 2004
NumericBehavior class related to decimal and thousand's separators for non-US locales. Thanks to Carlos Marsura for reporting and suggesting a fix the problem. _tsetlocale(LC_ALL, _T("")); inside OnInitDialog of the Demo to make it use the current user's locale. This isn't done by the underlying code! Doing this fixes problems with conversions between string and double values in locales where the decimal point is not a dot. Thanks to JNKS for reporting this problem along with a workaround. PadWithZerosAfterDecimalWhenTextChanges and PadWithZerosAfterDecimalWhenTextIsSet flags to the NumericBehavior class to allow automatic padding with zeros. I then set the PadWithZerosAfterDecimalWhenTextIsSet flag into the CAMSCurrencyEdit class so that the ".00" would be automatically appended (if necessary). AMSEDIT_EXPORT to each class declaration to make it easy to export the code from an MFC Extension DLL if desired. See amsEdit.h for more details. AMSEDIT_COMPILED_CLASSES macro defined at the top of amsEdit.h. This helps to reduce the executable's size. Thanks to Michael Mann for the idea."#CAMSNumericEdit">CAMSNumericEdit so it contains all of its member, except SetDouble, GetDouble, and SetMaxDecimalPlaces which don't make sense (thus are private).
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 21 Mar 2004 Editor: Sean Ewington |
Copyright 2001 by Alvaro Mendez Everything else Copyright © CodeProject, 1999-2010 Web11 | Advertise on the Code Project |